Croot Blog

Home About Tech Hobby Archive

vue ํ™˜๊ฒฝ lint ์„ค์ •

๐Ÿ’ก
์ „์ฒด ์ƒ˜ํ”Œ ์ฝ”๋“œ๋Š” ์•„๋ž˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.
https://github.com/croot-dev/vue-lint-config
https://github.com/croot-dev/vue-lint-config/tree/240508

ํ™˜๊ฒฝ ๋ฐ ์„ค์ •

.vscode/extensions.json

{
  "recommendations": [
	  // ...
	  
    "Vue.volar",
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "stylelint.vscode-stylelint"
    
	  // ...
  ]
}

.vscode/settings.json

{
		// ...
		
		// editor
    "editor.codeActionsOnSave": {
        "source.fixAll": "explicit",
        "source.fixAll.eslint": "explicit",
        "source.fixAll.stylelint": "explicit"
    },
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode",

    // eslint
    "eslint.enable": true,
    "eslint.format.enable": false,
    "eslint.codeActionsOnSave.mode": "problems",
    "eslint.codeActionsOnSave.rules": null,

		// stylelint
    "stylelint.enable": true,
    "stylelint.validate": ["css", "scss", "vue"]
    "stylelint.packageManager": "yarn",
    
    // ...
}

package.json

{
  "name": "vue-lint-config",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "run-p type-check \"build-only {@}\" --",
    "preview": "vite preview",
    "build-only": "vite build",
    "type-check": "vue-tsc --build --force",
    "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
    "format": "prettier --write src/"
  },
  "dependencies": {
    "vue": "^3.4.21"
  },
  "engines": {
	  "node": "18.18.2",
	  "yarn": "1.22.22"
  },
  "devDependencies": {
    "@rushstack/eslint-patch": "^1.8.0",
    "@tsconfig/node20": "^20.1.4",
    "@types/node": "^20.12.5",
    "@typescript-eslint/parser": "^7.8.0",
    "@vitejs/plugin-vue": "^5.0.4",
    "@vue/eslint-config-prettier": "^9.0.0",
    "@vue/eslint-config-typescript": "^13.0.0",
    "@vue/tsconfig": "^0.5.1",
    "eslint": "^8.57.0",
    "eslint-config-stylelint": "^21.0.0",
    "eslint-import-resolver-typescript": "^3.6.1",
    "eslint-plugin-import": "^2.29.1",
    "eslint-plugin-stylelint": "^0.1.1",
    "eslint-plugin-vue": "^9.23.0",
    "npm-run-all2": "^6.1.2",
    "prettier": "^3.2.5",
    "sass": "^1.77.0",
    "stylelint": "^16.5.0",
    "stylelint-config-recess-order": "^5.0.1",
    "stylelint-config-recommended-scss": "^14.0.0",
    "stylelint-config-recommended-vue": "^1.5.0",
    "stylelint-config-standard-scss": "^13.1.0",
    "typescript": "~5.4.0",
    "vite": "^5.2.8",
    "vue-tsc": "^2.0.11"
  }
}

Eslint ์„ค์ •

.eslintrc.cjs

/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
  root: true,
  extends: [
    'plugin:vue/vue3-recommended',
    'eslint:recommended',
    'plugin:import/recommended',
    'plugin:import/typescript',
    '@vue/eslint-config-typescript',
    '@vue/eslint-config-prettier/skip-formatting'
  ],
  plugins: ['stylelint', 'import'],
  parser: 'vue-eslint-parser',
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaVersion: 'latest'
  },
  rules: {
    'import/order': [
      'error',
      {
        groups: [
          'type',
          'builtin',
          'external',
          'internal',
          'parent',
          'sibling',
          'index',
          'unknown'
        ],
        pathGroupsExcludedImportTypes: ['@tanstack*'],
        alphabetize: {
          order: 'asc'
        }
      }
    ]
  }
}

Prettier ์„ค์ •

.prettierrc.json

{
  "$schema": "https://json.schemastore.org/prettierrc",
  "semi": false,
  "tabWidth": 2,
  "singleQuote": true,
  "printWidth": 100,
  "trailingComma": "none"
}

Stylelint ์„ค์ •

.stylelintrc.json

{
  "extends": [
    "stylelint-config-standard",
    "stylelint-config-standard-scss",
    "stylelint-config-recommended-scss",
    "stylelint-config-recommended-vue",
    "stylelint-config-recess-order"
  ],
  "plugin": ["stylelint-scss", "stylelint-order"],
  "rules": {}
}