如何在VS Code编辑器中配置Vue CLI 4与ESLint+Airbnb规则+TypeScript+Stylelint for SCSS,实现保存时自动修复?

34

注意:这是我之前有关此主题的类似问题,该问题部分未解决,并且挑战的性质在此之后发生了相当的变化。: 如何配置带有ESLint + Prettier + Airbnb规则 + TypeScript + Vetur的Vue CLI 4?

在2019年,我非常着迷于配置带有TypeScript的Vue的“圣杯”工具设置,并让VS Code在.vue、.ts和.scss文件上保存时自动修复代码

但是,让PrettierESLintVetur最佳地协作实际上是一个很大的挑战。由于Prettier与ESLint有部分相同的目标和类似的规则检查,以及Vetur在VS Code中为此特定混合物增加了更多的复杂性。

另外,当设置大部分正常工作时,需要连续保存文件几次,这令人相当烦恼。因为一旦ESLint找到并修复了一组错误,新的错误就会出现,并且它无法在一行中运行这些检查和修复,直到所有内容都已清除...

2019年11月,我参加了Vue Conf Toronto,在Evan先生的工作坊“深度剖析Vue 3.0”中,我问他了这个问题。他说官方工具将很快进行重大改进,并将引入来自较新版本ESLint的新功能......

他还暗示目前几乎已经编写了自动修复逻辑以应对Vue官方样式指南的所有规则检查,并且结合即将到来的Vue 3.0完全模块化架构,甚至可能会推出官方的VS Code扩展程序。或者至少通过利用这些新功能使Vetur和类似插件更容易运行代码检查和修复。

2019年12月,Vue CLI 4.1插件和预设升级带来了ESLint 6版本的特性。这意味着我们可以开始将ESLint不仅用作linter,而且还可以用作格式化程序,从而有效地取消了我们设置中需要Prettier的需求

在同一时间,ESLint发布了其官方VS Code扩展的2.0版本dbaeumer.vscode-eslint,增加了对VS Code的保存时运行代码操作功能的支持,这由editor.codeActionsOnSave设置控制。

因此,终于为运行此设置铺平了道路!接下来,我将回答如何配置此混合体的问题。

附注:虽然仍然可以将Vetur用作此设置的一部分,但我已更改为使用Stylelint。 Stylelint的自动修复功能仍存在一些问题,但可能会在未来的更新中解决。 但我仍然很想听听Vetur是否有或没有与Stylelint一起使用的价值!

1个回答

47

官方脚手架Vue CLI项目的配置

在2020年2月Vue CLI 4.2升级创建项目脚手架之后,您可以通过使用全局命令vue create myproject创建新项目,并至少进行以下选择(包括以下配置)来完成一半的配置:

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                                                                                                                             

现在你可能会想知道为什么我选择 node-sass 而不是第一个建议的选项 dart-sass − 原因如下:Vue CLI CSS 预处理器选项:dart-sass VS node-sass?package.json 中,你至少会得到这些依赖项:
  "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"
  }

使用 .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',
  },
};

使用 .editorconfig 文件:

[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100

针对代码检查和格式化的偏好设置更改

因此,使用我自己的偏好修改了 .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,
      },
    },
  ],
};

接着我添加了 .eslintignore 文件:

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

接着我在 .editorconfig 文件的顶部添加了这个部分(不确定是否需要这个文件):

# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

安装和配置Stylelint

Stylelint是一个与CSS/SCSS/SASS/LESS/Stylus类似的项目,就像ESLint对于JavaScript/TypeScript一样,同样可以通过插件和预设进行扩展。它有一个官方的VS Code扩展程序,并且也可以在Webpack构建过程中运行。

我选择使用stylelint-scss包来扩展Stylelint,该包目前每周下载量达到50万次,以及由同一维护者提供的stylelint-config-recommended-scss包。此外,我还将stylelint-webpack-plugin配置为Webpack构建过程的一部分。

通过命令行安装这些开发依赖项:npm i -D stylelint stylelint-config-recommended-scss stylelint-scss stylelint-webpack-plugin

添加一个文件.stylelintrc.json,其中包含一些带偏见的规则修改作为示例(Vue的::v-deep自定义选择器处理可能会用到):

{
  "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"]
      }
    ]
  }
}

创建文件或添加到vue.config.js,以下是一些偏见的配置示例:
// Add in the top of the file
const 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编辑器、扩展和设置

在项目根目录中创建名为.vscode的文件夹,用于放置项目特定的设置和扩展推荐。请注意,如果您以工作区模式打开VS Code(同时包含多个项目根目录),则某些设置在此模式下不起作用,因此我总是直接打开项目根目录,而不使用工作区模式。

在此文件夹中添加一个extensions.json文件,并至少添加以下内容进行推荐,并安装这些扩展程序。

{
  "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",
  ]
}

新增一个名为settings.json的文件,并添加以下或类似设置:

{
  // 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,
}

所以这些是我的偏见项目设置,我很想听到改进建议!

4
谢谢分享!它没有自动格式化单独的 .ts 文件。我不得不像这里建议的那样在 settings.json 中添加 "eslint.validate": ["typescript"]。这似乎是 eslint 中的一个 bug。 编辑:删除了我之前关于 html 格式化无法工作的评论(它确实可以工作)。 - andy-bc
1
你的解决方案在我的Vue CLI项目上很好用。格式似乎可以工作,但奇怪的是VS Code一直显示“扩展程序'ESlint'无法格式化'src/App.vue'”(当然使用不同的文件名)。有什么想法吗? - Michal Levý
1
@MichalLevý 不确定那里出了什么问题。在接下来的几周中,我将与一些人一起检查此代码检查和格式设置的可能增强功能。我也会在这里更新更改。我也很想听听社区中是否有其他人有改进建议! - ux.engineer
2
对于任何在单文件 Vue 组件中无法正确格式化 HTML 的人,我错过了一个可能是关键的细节:请注意默认的.eslintrc.js和带有@ux.engineer的“偏执”更改的版本之间的区别-- plugin:vue/essential => plugin:vue/recommended。这为我解决了问题,您可以在此处查看具体规则-https://eslint.vuejs.org/rules/ - launchoverit
能够使用 eslint-config-airbnb-typescript 代替 @vue/airbnb 会更好,因为 @vue/airbnb 没有 eslint-config-airbnb-typescript 具有的 TypeScript 特定规则。 - wube
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接