How to configure Vue CLI 4 with ESLint + Airbnb rules + TypeScript + Stylelint for SCSS, in VS Code editor with autofix on save? How to configure Vue CLI 4 with ESLint + Airbnb rules + TypeScript + Stylelint for SCSS, in VS Code editor with autofix on save? vue.js vue.js

How to configure Vue CLI 4 with ESLint + Airbnb rules + TypeScript + Stylelint for SCSS, in VS Code editor with autofix on save?


Official scaffolded Vue CLI project's configurations

After Vue CLI 4.2 upgrades in create project scaffolding in February 2020, you are half way through the configurations by creating a new project with global vue create myproject command and making at least these selections (configurations included below):

Vue CLI v4.2.2? Please pick a preset: Manually select features? Check the features needed for your project: (*) Babel (*) TypeScript ( ) Progressive Web App (PWA) Support ( ) Router ( ) Vuex (*) CSS Pre-processors>(*) Linter / Formatter ( ) Unit Testing ( ) E2E Testing     ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n) Y ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):  Sass/SCSS (with dart-sass)> Sass/SCSS (with node-sass)  Less  Stylus      ? Pick a linter / formatter config:  ESLint with error prevention only> ESLint + Airbnb config  ESLint + Standard config  ESLint + Prettier  TSLint (deprecated)    ? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)>(*) Lint on save ( ) Lint and fix on commit ? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)> In dedicated config files  In package.json                                                                                                                             

Now you may be wondering why I chose node-sass over the first suggested option dart-sass − here's why: Vue CLI CSS pre-processor option: dart-sass VS node-sass?

In package.json you are given at least these dependencies:

  "dependencies": {    "core-js": "^3.6.4",    "vue": "^2.6.11"  },  "devDependencies": {    "@typescript-eslint/eslint-plugin": "^2.18.0",    "@typescript-eslint/parser": "^2.18.0",    "@vue/cli-plugin-babel": "~4.2.0",    "@vue/cli-plugin-eslint": "~4.2.0",    "@vue/cli-plugin-typescript": "~4.2.0",    "@vue/cli-service": "~4.2.0",    "@vue/eslint-config-airbnb": "^5.0.2",    "@vue/eslint-config-typescript": "^5.0.1",    "eslint": "^6.7.2",    "eslint-plugin-import": "^2.20.1",    "eslint-plugin-vue": "^6.1.2",    "node-sass": "^4.12.0",    "sass-loader": "^8.0.2",    "typescript": "~3.7.5",    "vue-template-compiler": "^2.6.11"  }

With .eslintrc.js:

module.exports = {  root: true,  env: {    node: true,  },  extends: [    'plugin:vue/essential',    '@vue/airbnb',    '@vue/typescript/recommended',  ],  parserOptions: {    ecmaVersion: 2020,  },  rules: {    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',  },};

With .editorconfig:

[*.{js,jsx,ts,tsx,vue}]indent_style = spaceindent_size = 2end_of_line = lftrim_trailing_whitespace = trueinsert_final_newline = truemax_line_length = 100

Biased config changes for linting and formatting

So, with my biased modifications to .eslintrc.js:

module.exports = {  root: true,  env: {    node: true,  },  extends: [    'plugin:vue/recommended',    '@vue/airbnb',    '@vue/typescript/recommended',  ],  parserOptions: {    ecmaVersion: 2020,  },  rules: {    'class-methods-use-this': 0,    // Changing max row length from 80 to 150.    // Remember to change in .editorconfig also, although am not sure if that file is even needed?    // Especially as scaffolding gave 100 as max len while ESLint default is 80...    'max-len': [      'error',      {        code: 150,        ignoreComments: true,        ignoreUrls: true,      },    ],    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',    '@typescript-eslint/ban-ts-ignore': 0,  },  // These are added if you chose also to install Jest plugin for Vue CLI  // With my own modifications here as an example  overrides: [    {      files: [        './src/**/__tests__/*.spec.{j,t}s',        './src/**/__mock__/*.{j,t}s',      ],      env: {        jest: true,      },      rules: {        'no-unused-expressions': 0,      },    },  ],};

Then I've added .eslintignore file:

# Lint config files in the root ending .js!/*.js

Then I've added this section in top of .editorconfig (while not sure if this file is needed):

# EditorConfig is awesome: https://EditorConfig.org# top-most EditorConfig fileroot = true

Installing and configuring Stylelint

Stylelint is a somewhat similar project to CSS/SCSS/SASS/LESS/Stylus than ESLint is for JavaScript/TypeScript, being likewise extendable with plugins and presets. It has an official VS Code extension, and it can also be run during your Webpack build process.

I've chosen to extend Stylelint with stylelint-scss package, which currently has half a million of weekly downloads, and stylelint-config-recommended-scss package from the same maintainer. In addition, I've configured stylelint-webpack-plugin as a part of the Webpack build process.

Install these dev dependencies from the command line by: npm i -D stylelint stylelint-config-recommended-scss stylelint-scss stylelint-webpack-plugin

Add a file .stylelintrc.json with a few biased rule modifications as an example (Vue's ::v-deep custom selector handling may come needed):

{  "extends": "stylelint-config-recommended-scss",  "rules": {    "max-nesting-depth": 4,    "no-descending-specificity": null,    "property-no-unknown": [      true,      {        "ignoreProperties": ["user-drag", "font-smooth"]      }    ],    "selector-pseudo-element-no-unknown": [      true,      {        "ignorePseudoElements": ["v-deep"]      }    ]  }}

Create file or add to vue.config.js, this some biased config examples:

// Add in the top of the fileconst StyleLintPlugin = require('stylelint-webpack-plugin');module.exports = {  css: {    loaderOptions: {      sass: {        // Here as example if needed:        // Import Sass vars and mixins for SFC's style blocks        prependData: '@import "@/assets/styles/abstracts/_variables.scss"; @import "@/assets/styles/abstracts/_mixins.scss";',      },    },  },  lintOnSave: process.env.NODE_ENV !== 'production',  productionSourceMap: false,  devServer: {    overlay: {      warnings: true,      errors: true,    },  },  configureWebpack: {    // Fast source maps in dev    devtool: process.env.NODE_ENV === 'production' ? false : 'cheap-eval-source-map',    plugins: [      new StyleLintPlugin({        files: 'src/**/*.{vue,scss}',      }),    ],    resolve: {      alias: {        // Alias @ to /src folder for ES/TS imports        '@': path.join(__dirname, '/src'),      },    },  },};

VS Code editor, extensions and settings

Create .vscode named folder in your project root for placing project specific settings and extension recommendations. Note that if you open VS Code in workspace mode (having multiple project roots included at once), some of the settings do not work in this mode, so I'm always opening the project root directly without using workspace mode.

In this folder add a file extensions.json, with at least this content recommended, and install the extensions.

{  "recommendations": [    // ESLint - Integrates ESLint JavaScript into VS Code.    "dbaeumer.vscode-eslint",    // Disable eslint rule - Disable eslint rule with one click.    "wooodhead.disable-eslint-rule",    // eslint-disable-snippets - Simple snippets for disable eslint rules    "drknoxy.eslint-disable-snippets",    // Vue - Syntax highlight for Vue.js    "jcbuisson.vue",    // stylelint - Modern CSS/SCSS/Less linter    "stylelint.vscode-stylelint",    // EditorConfig for VS Code - EditorConfig Support for Visual Studio Code    // Not sure if this is needed or recommended,    // but .editorconfig file is still included in the scaffolded project...    "editorconfig.editorconfig",    // DotENV - Support for dotenv file syntax.    "mikestead.dotenv",  ]}

Add another file settings.json with these or similar settings:

{  // EDITOR  // ----------------------------------------  "editor.defaultFormatter": "dbaeumer.vscode-eslint",  "[javascript]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint" },  "[typescript]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint" },  "[vue]": { "editor.defaultFormatter": "dbaeumer.vscode-eslint" },  "[scss]": { "editor.defaultFormatter": "stylelint.vscode-stylelint" },  "[css]": { "editor.defaultFormatter": "stylelint.vscode-stylelint" },  "editor.codeActionsOnSave": {    // https://github.com/microsoft/vscode-eslint/blob/master/README.md#release-notes    "source.fixAll.eslint": true,    "source.fixAll.stylelint": true  },  // ESLINT  // ----------------------------------------  "eslint.enable": true,  "eslint.alwaysShowStatus": true,  "eslint.options": {    "extensions": [".html", ".js", ".ts", ".vue"]  },  // VETUR  // Disable rules if user has extension installed and enabled.  // ----------------------------------------  "vetur.validation.template": false,  "vetur.validation.style": false,  "vetur.format.defaultFormatter.html": "none",  "vetur.format.defaultFormatter.css": "none",  "vetur.format.defaultFormatter.scss": "none",  "vetur.format.defaultFormatter.js": "none",  "vetur.format.defaultFormatter.ts": "none",  // STYLELINT  // ----------------------------------------  "stylelint.enable": true,  "css.validate": true,  "scss.validate": true,  // HTML  // ----------------------------------------  "html.format.enable": false,  "emmet.triggerExpansionOnTab": true,  "emmet.includeLanguages": {    "vue-html": "html"  },  // FILES  // ----------------------------------------  "files.exclude": {    "**/*.log": true,    "**/*.log*": true,    "**/dist": true,  },  "files.associations": {    ".babelrc": "jsonc",    ".eslintrc": "jsonc",    ".markdownlintrc": "jsonc",    "*.config.js": "javascript",    "*.spec.js": "javascript",    "*.vue": "vue"  },  // The default end of line character. Use \n for LF and \r\n for CRLF.  "files.eol": "\n",  "files.insertFinalNewline": true,  "files.trimFinalNewlines": true,  "files.trimTrailingWhitespace": true,}

So these were my biased project settings, and I'm interested in hearing improvement suggestions!