javascript - ¿Cómo configurar Vue CLI 4 con ESLint + reglas de Airbnb + TypeScript + Stylelint para SCSS, en el editor VS Code con autocorrección al guardar?
Nota: Esta es una pregunta similar a mi pregunta anterior sobre el tema, la cual quedó parcialmente sin resolver y después de la cual la naturaleza del desafío cambió considerablemente: ¿Cómo configurar Vue CLI 4 con ESLint + Prettier + reglas de Airbnb + TypeScript + Vetur?
En 2019 estaba bastante obsesionado con conseguir una configuración de herramientas de 'santo grial' con Vue en TypeScript y tener VS Code para corregir automáticamente tu código al guardar archivos en .vue, .ts y .scss.
Pero lograr que Prettier funcione de manera óptima con ESLint y Vetur terminó siendo demasiado desafiante. Debido a un conflicto inherente entre Prettier y ESLint, que tienen parcialmente el mismo objetivo y reglas similares, y con Vetur agregando más complejidad a esta mezcla particular en VS Code.
Además, cuando la configuración funcionaba en su mayoría, era bastante irritante que tuvieras que guardar el archivo varias veces seguidas. Porque una vez que ESLint encontraba y corregía un conjunto de errores, aparecían nuevos errores y no era lo suficientemente avanzado para ejecutar esas comprobaciones y correcciones en serie hasta que todo estuviera solucionado...
En noviembre de 2019 estaba asistiendo a Vue Conf Toronto, y en el taller de Mr. Evan llamado Deep Dive with Vue 3.0 pude preguntarle sobre este problema. Él comentó que la herramienta oficial va a recibir una renovación importante muy pronto, y que habrá nuevas funciones provenientes de versiones más recientes de ESLint...
También insinuó que en este momento hay lógica de autocorrección escrita para casi todas las comprobaciones de reglas de la Guía de Estilo oficial de Vue, lo que en combinación con la próxima arquitectura totalmente modular de Vue 3.0 incluso podría ver la aparición de una extensión oficial de VS Code. O al menos está haciendo más fácil para Vetur y plugins similares ejecutar comprobaciones y correcciones de código aprovechando estas nuevas capacidades.
En diciembre de 2019, las actualizaciones de plugins y presets de Vue CLI 4.1 trajeron las características de ESLint versión 6 a la mesa. Lo que significaba que podíamos empezar a usar ESLint no solo como un linter, sino también como un formateador, efectivamente eliminando la necesidad de Prettier en nuestras configuraciones.
Durante el mismo tiempo, ESLint lanzó la versión 2 de su extensión oficial para VS Code dbaeumer.vscode-eslint, incorporando soporte para la función Ejecutar Acciones de Código al guardar de VS Code, controlada por la configuración editor.codeActionsOnSave.
¡Así que finalmente se despejó el camino para poner en marcha esta configuración! A continuación, responderé mi propia pregunta sobre cómo configurar esta mezcla.
PD. Aunque es posible que Vetur todavía se pueda usar como parte de esta configuración, aquí he cambiado a usar Stylelint. Todavía ha habido algunos problemas con la función de autocorrección de Stylelint, pero es probable que se resuelvan en futuras actualizaciones. ¡Aún así estoy interesado en saber si Vetur resultaría útil con o sin Stylelint!
Respuesta #1
Configuraciones oficiales de un proyecto Vue CLI estructurado
Después de las actualizaciones de Vue CLI 4.2 en la creación de esqueleto de proyecto en febrero de 2020, estás a mitad de camino de las configuraciones al crear un nuevo proyecto con el comando global vue create myproject y haciendo al menos estas selecciones (configuraciones incluidas a continuación):
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
Ahora puede que se pregunte por qué elegí node-sass en lugar de la primera opción sugerida dart-sass − aquí está la razón: Opción de preprocesador CSS de Vue CLI: dart-sass VS node-sass?
En package.json se te dan al menos estas dependencias:
"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"
}
Con .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',
},
};
Con .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
Cambios de configuración sesgados para linting y formato
Entonces, con mis modificaciones sesgadas en .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,
},
},
],
};
Luego he añadido el archivo .eslintignore:
Lint config files in the root ending .js
!/*.js
Luego he agregado esta sección en la parte superior de .editorconfig (aunque no estoy seguro de si este archivo es necesario):
EditorConfig is awesome: https://EditorConfig.org
top-most EditorConfig file
root = true
Instalación y configuración de Stylelint
Stylelint es un proyecto algo similar a CSS/SCSS/SASS/LESS/Stylus que ESLint lo es para JavaScript/TypeScript, siendo igualmente ampliable con complementos y presets. Tiene una extensión oficial para VS Code, y también se puede ejecutar durante tu proceso de construcción con Webpack.
He elegido extender Stylelint con el paquete stylelint-scss, que actualmente tiene medio millón de descargas semanales, y el paquete stylelint-config-recommended-scss del mismo mantenedor. Además, he configurado stylelint-webpack-plugin como parte del proceso de construcción de Webpack.
Instala estas dependencias de desarrollo desde la línea de comandos con: npm i -D stylelint stylelint-config-recommended-scss stylelint-scss stylelint-webpack-plugin
Agrega un archivo .stylelintrc.json con algunas modificaciones de reglas sesgadas como ejemplo (puede ser necesario el manejo del selector personalizado ::v-deep de Vue):
{
"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"]
}
]
}
}
Crea un archivo o añade a vue.config.js, estos son algunos ejemplos de configuración sesgada:
// 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'),
},
},
},
};
Editor de VS Code, extensiones y configuraciones
Crea una carpeta llamada .vscode en la raíz de tu proyecto para colocar configuraciones específicas del proyecto y recomendaciones de extensiones. Ten en cuenta que si abres VS Code en modo de espacio de trabajo (incluyendo varias raíces de proyecto a la vez), algunas de las configuraciones no funcionan en este modo, por lo que siempre estoy abriendo la raíz del proyecto directamente sin usar el modo de espacio de trabajo.
En esta carpeta, agrega un archivo extensions.json, con al menos este contenido recomendado, e instala las extensiones.
{
"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",
]
}
Agrega otro archivo settings.json con estas configuraciones o similares:
{
// 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,
}
Así que estos eran mis ajustes de proyecto sesgados, y ¡me interesa escuchar sugerencias de mejora!
