Linting & Formatting
Stacks provides built-in linting and formatting tools to maintain consistent code quality across your project. Based on ESLint and Prettier with sensible defaults.
Overview
Stacks linting features:
- Zero configuration - Works out of the box
- TypeScript-first - Full TypeScript support
- Vue support - Lint Vue SFC files
- Auto-fix - Fix issues automatically
- IDE integration - Real-time feedback
Quick Start
Run Linting
# Check for issues
buddy lint
# Fix auto-fixable issues
buddy lint --fix
# Lint specific files
buddy lint src/components/
# Check formatting only
buddy format:check
# Fix formatting
buddy format
ESLint Configuration
Default Rules
Stacks uses a curated set of ESLint rules:
// eslint.config.ts
import { defineConfig } from '@stacksjs/eslint'
export default defineConfig({
// Default configuration
})
Customizing Rules
// eslint.config.ts
import { defineConfig } from '@stacksjs/eslint'
export default defineConfig({
rules: {
// Override rules
'no-console': 'warn',
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
}],
},
ignores: [
'dist/**',
'node_modules/**',
'_.gen.ts',
],
})
Extending Configuration
import { defineConfig, presets } from '@stacksjs/eslint'
export default defineConfig({
extends: [
presets.recommended,
presets.vue,
presets.typescript,
],
rules: {
// Your custom rules
},
})
TypeScript Rules
Strict Type Checking
export default defineConfig({
typescript: {
strict: true,
typeChecked: true,
},
rules: {
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/strict-boolean-expressions': 'error',
},
})
Common TypeScript Rules
rules: {
// Require explicit return types
'@typescript-eslint/explicit-function-return-type': 'warn',
// Disallow any type
'@typescript-eslint/no-explicit-any': 'error',
// Require type annotations
'@typescript-eslint/typedef': ['error', {
parameter: true,
propertyDeclaration: true,
}],
// Prefer interfaces over type aliases
'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
// Enforce consistent type imports
'@typescript-eslint/consistent-type-imports': ['error', {
prefer: 'type-imports',
}],
}
Vue Rules
Vue-Specific Linting
export default defineConfig({
vue: {
version: 3,
scriptSetup: true,
},
rules: {
// Component naming
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
// Prop naming
'vue/prop-name-casing': ['error', 'camelCase'],
// Event naming
'vue/custom-event-name-casing': ['error', 'camelCase'],
// No unused refs
'vue/no-unused-refs': 'error',
// Require default props
'vue/require-default-prop': 'error',
// Order of component options
'vue/order-in-components': 'error',
},
})
Vue Template Rules
rules: {
// Self-closing tags
'vue/html-self-closing': ['error', {
html: { normal: 'never', void: 'always' },
svg: 'always',
math: 'always',
}],
// Max attributes per line
'vue/max-attributes-per-line': ['error', {
singleline: 3,
multiline: 1,
}],
// Attribute order
'vue/attributes-order': ['error', {
order: [
'DEFINITION',
'LIST_RENDERING',
'CONDITIONALS',
'RENDER_MODIFIERS',
'GLOBAL',
'UNIQUE',
'TWO_WAY_BINDING',
'OTHER_DIRECTIVES',
'OTHER_ATTR',
'EVENTS',
'CONTENT',
],
}],
}
Prettier Integration
Formatting Configuration
// prettier.config.ts
import { defineConfig } from '@stacksjs/prettier'
export default defineConfig({
// Defaults
semi: false,
singleQuote: true,
tabWidth: 2,
trailingComma: 'all',
printWidth: 100,
// Override per file type
overrides: [
{
files: '_.md',
options: {
proseWrap: 'always',
},
},
{
files: '*.json',
options: {
tabWidth: 2,
},
},
],
})
Running Prettier
# Check formatting
buddy format:check
# Fix formatting
buddy format
# Format specific files
buddy format src/**/*.ts
IDE Integration
VS Code
Create .vscode/settings.json:
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"typescript",
"vue"
],
"typescript.preferences.importModuleSpecifier": "relative"
}
Recommended Extensions
// .vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"vue.volar"
]
}
WebStorm / IntelliJ
- Go to Settings > Languages & Frameworks > JavaScript > Code Quality Tools > ESLint
- Enable Automatic ESLint configuration
- Check Run eslint --fix on save
Pre-commit Hooks
Setup with Husky
# Install hooks
buddy hooks:install
// .husky/pre-commit
# !/bin/sh
bun run lint-staged
Lint-Staged Configuration
// package.json
{
"lint-staged": {
"_.{ts,tsx,vue}": [
"eslint --fix",
"prettier --write"
],
"_.{json,md,yml}": [
"prettier --write"
]
}
}
CI Integration
GitHub Actions
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- run: bun install
- run: bun run lint
- run: bun run format:check
Common Rules
Import Ordering
rules: {
'import/order': ['error', {
groups: [
'builtin',
'external',
'internal',
'parent',
'sibling',
'index',
],
'newlines-between': 'always',
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
}],
}
Naming Conventions
rules: {
'@typescript-eslint/naming-convention': [
'error',
// Variables: camelCase
{ selector: 'variable', format: ['camelCase', 'UPPER_CASE'] },
// Functions: camelCase
{ selector: 'function', format: ['camelCase'] },
// Classes: PascalCase
{ selector: 'class', format: ['PascalCase'] },
// Interfaces: PascalCase with I prefix optional
{ selector: 'interface', format: ['PascalCase'] },
// Types: PascalCase
{ selector: 'typeAlias', format: ['PascalCase'] },
// Enums: PascalCase
{ selector: 'enum', format: ['PascalCase'] },
],
}
Disable Rules
Per-Line
// eslint-disable-next-line no-console
console.log('Debug output')
const value = 42 // eslint-disable-line no-magic-numbers
Per-File
/_ eslint-disable no-console _/
// All console statements allowed in this file
console.log('Hello')
console.log('World')
/_ eslint-enable no-console _/
For Block
/_ eslint-disable _/
// All rules disabled
const messy = code
/_ eslint-enable _/
Best Practices
- Start strict - Begin with strict rules, relax as needed
- Fix gradually - Use
--fixto auto-fix, review changes - Consistent formatting - Let Prettier handle formatting
- IDE integration - Get real-time feedback
- Pre-commit hooks - Catch issues before commit
- CI enforcement - Fail builds on lint errors
Related
- Testing - Testing your code
- CI - Continuous integration
- Configuration - Project configuration