[前端代码规范实践] ESLint + [StyleLint] + [Prettier] + EditorConfig

背景

前端代码规范问题由来已久,相信除了笔者以外大多数也有过被多人开发或中途接手项目中各种格式的代码折磨到不堪受辱以致满嘴**还不得不继续输出代码的经历。个人实在是忍了它很长时间,决定自己细致的整理一遍关于前端代码规范的理论以及具体实践方案。

在学习相关的知识前,定位问题永远是首要任务,以下是笔者总结的几点现象:

  • 项目中没有(使用|开启)代码规范插件(极少数)
  • 开发人员规范插件的配置冲突导致格式化Error Loop
  • 不同开发人员使用不同插件、IDE配置
  • 没有按照规范输出代码,例如CSS的BEM标准规范

前三点属于配置范围,最后一点则属于软性规范,本文给出的也是前者问题的个人答案。

工作原理

这四种插件运行的原理都比较相似,在这里主以ESLint为例:

  • 初始化阶段:
    • 初始化配置参数:包括setting.jsonESLint的配置以及项目本地.eslintrc的配置
    • 搜索ESLint核心库ESLint插件本身不包含核心代码,仅作为类似启动器的角色被使用,ESLint核心库需要项目本地或者本地(全局依赖)提供
    • 初始化核心库类:辅以配置参数实例化ESLint核心类,初始化编译器
  • 编译检测阶段:
    • 代码编译ESLint使用Javascript的Espree解析器将代码解析成AST
    • 规则检测:深度遍历解析的AST,监听每一个选择器,根据Rules进行检测
  • 回显阶段:
    • 可视化检测结果:深度遍历检测完成后VSCode编辑器得到检测的结果。其一(简洁):以Error Reason + Rule Name显示在terminal终端的problems面板;其二(详细):以详细完整的检测信息显示在terminal终端的output面板;其三(高亮):被检测代码下方以红色波浪线高亮标示不符合规则的代码;

ESLint|Stylelint|Prettier|EditorConfig这些检测工具的工作原理都比较类似,不外乎对象实例化-编译Javascript-遍历AST检测-输出检测结果这四步流程,如果想要更多的理解内部的运行原理,需要读者自行找寻源码研读,本文不作展开。

负责区域

ESLint:检测代码质量和代码风格;
StyleLint:检测样式代码质量和代码风格;
Prettier:检测代码风格;
EditorConfig:统一不同IDE之间的配置差异,例如一个编辑器行缩进使用的是Tab,另一个编辑器使用的则是空格Space;

Specification.png

结合ESLint + Prettier + StyleLint并集图形以及作用简介,ESLintStyleLint中都有对应的Quality/Styling-Code Check,但相对没有Prettier那么专业一致,可以通过禁用ESlintStyleLint中关于Styling规则的方式使三者达成平衡,不会导致Error Loop

可以并集也就意味着可以不并集,在项目体量不大时ESLint已经够用。在这里没有将EditorConfig并入,因为它本身的作用是抹平多人开发时多种编辑器带来的配置差异,这是其它插件所没有的,这也是笔者标题中没有对EditorConfig使用中括号表示可选的意思。

实践方案

首先列一下在项目中需要用到的依赖插件,如下图:

// 依赖清单
[
    // ESLint
    eslint,
    babel-eslint,
    eslint-plugin-vue,
    eslint-webpack-plugin,      // 开发环境实时检测(可选
    
    // StyleLint(可选)
    stylelint,
    stylelint-webpack-plugin,   // 开发环境实时检测
    stylelint-config-standard,
    
    // Prettier(可选)
    prettier,
    eslint-config-prettier,
    eslint-plugin-prettier,
    stylelint-config-prettier
]
复制代码

主要分四层配置进行:

  • 核心规则配置:各检测工具必要的规则配置文件,没有它们检测工具无法执行,如.eslintrc文件。
  • 命令行脚本配置package.jsonscript属性配置执行脚本,开发人员手动执行命令,如npm run lint
  • 开发环境配置webpack开发环境构建配置中,添加开发环境运行时检测插件,类似于启动器,运行时自动执行各自的检测工具进行检测。
  • 编辑器配置VSCode编辑器安装插件并配置属性,实时进行检测。

需要注意的是,上述二、三种配置一旦执行,会全量检测所有需要检测的文件(初次检测不符合规则的量可能会很大),而最后一种只对打开在工作可视区内需要检测的文件进行检测。

核心规则配置

  • ESLint部分:
    1.安装eslint依赖

    npm install --save-dev eslint
    复制代码

    2.创建.eslintrc.js文件,在配置前,首先对如下几个主要属性进行简介:

    • root:一般创建在项目顶层的配置文件必备属性,用于终止eslint初始化阶段向父级文件夹无限制搜索eslint配置文件。
    • parser: 可自定义指定eslint用于解析代码的解析器,配置eslint-plugin-vue依赖时会用到。
    • parserOptions:可指定eslint解析器选项。
    • env:指定环境,会提供预先定义的全局变量,比如{ browser: true }会提供window变量,eslint检测认定为已定义变量,不会报错。
    • extends: 想要添加的规则集合,如eslint:recommended表示eslint官方提供的一组检测规则集合。

    3.配置.eslintrc.js文件:

    • ==基础配置==
    • 配置root属性,一般情况下只需在项目顶层配置文件即可,{root: true}
    • 配置env属性,提供全局变量,{browser: true, es6: true, node: true}
    • 配置extends属性,推荐eslint推荐规则作为基础,['eslint:recommended']
    module.exports = {
        root: true,
        env: {
            browser: true,
            es6: true,
            node: true
        },
        extends: [
            'eslint:recommended'
        ]
    }
    复制代码
    • ==进阶配置一(基于上述配置)==
    • 安装eslint-plugin-vue | babel-eslint依赖
    npm install --save-dev eslint-plugin-vue babel-eslint
    复制代码
    • 配置parser属性,因为eslint-plugin-vue在检测.vue文件时需要特定解析器,否则无法正常工作,{parser: 'vue-eslint-parser'}
    • 配置parserOptions.parser属性,因为parser属性不能被覆盖,自定义的解析器只能在这里,{parser: 'babel-eslint'}
    • 配置parserOptions.sourceType属性,笔者vue开发栈,vue项目采用ES6的import/export模块语法,{sourceType: 'module'}
    • 配置parserOption.ecmaFeatures.jsx属性,用于支持检测JSX语法,这还是比较推荐的,{ecmaFeatures: {jsx: true}}
    • 配置extends属性,eslint-plugin-vue依赖提供了许多组规则集合,笔者推荐plugin:vue/recommended(其余参考插件官网),读者可以根据自己的情况进行选用,[plugin:vue/recommend]
    • 配置plugins属性,eslint-plugin-vue必需属性,区分.vue文件中script和template标签以便检测内容,['vue']
    // http://eslint.org/docs/user-guide/configuring
    
    module.exports = {
        parser: 'vue-eslint-parser',
        parserOptions: {
            parser: 'babel-eslint',
            sourceType: 'module',
            ecmaFeatures: {
                jsx: true
            }
        },
        extends: [
            'eslint:recommended',
            'plugin:vue/recommended'
        ],
        // required to lint *.vue files
        plugins: ['vue'],
    }
    复制代码
    • ==进阶配置二(基于上述配置,禁用code style规则,全权由prettier进行code style检测与格式化)==
    • 安装prettier|eslint-plugin-prettier|eslint-config-prettier依赖
    npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier
    复制代码
    • 配置extends属性,由eslint-plugin-prettier提供,禁用由’eslint:recommended’开启的eslint规则,(具体参考npm文档有详细说明),['plugin:prettier/recommended']
    • 配置extends属性,由prettier提供,禁用由’plugin:vue/recommended’开启的eslint规则,['prettier/vue']
    module.exports = {
        extends: [
            'eslint:recommended',
            'plugin:vue/recommened',
            'plugin:prettier/recommend',
            'prettier/vue'
        ]
    }
    复制代码
    • ==进阶配置三(基于上述配置,选择性开启部分规则)==
    • 配置rules属性,这个属性中定义的是每一条具体的规则配置,笔者定义规则相对较多,不在此展示,若想参考请点击这里,每一条规则笔者都有简单的注释说明
  • StyleLint部分
    相比于eslint,stylelint的配置比较简单,笔者只安装了stylelint推荐的standard规则集合用于检测CSS,基本上已经够用,同时安装了stylelint-prettier屏蔽stylelint中可能与prettier冲突的规则。

    1.安装stylelint依赖:

    npm install --save-dev stylelint
    复制代码

    2.创建并配置.stylelintrc.js文件:

    • 安装stylelint-config-standard|stylelint-config-prettier依赖
    npm i --save-dev stylelint-config-standard stylelint-config-prettier stylelint-prettier
    复制代码
    • 配置extends属性,添加两组规则集合,即标准规则集合和屏蔽规则集合['stylelint-config-standard', 'stylelint-prettier/recommend']
    // stylelint-prettier作为stylelint的插件,
    // 作用机制与上述eslint的eslint-pluing-prettier插件几乎一致
    module.exports = {
        extends: [
            'stylelint-config-prettier',
            'stylelint-prettier/recommend'
        ]
    }
    复制代码
    • 配置rules属性,与eslint一样,笔者在上述扩展规则集合的基础上,选择性的配置了部分stylelint规则,不在此展示,若想参考请点击这里,每一条规则笔者都由简单的注释说明。
  • Prettier部分
    prettier是专注于code style的检测与格式化器,通过快捷键能一步到’胃’,但是神奇的是总共需要配置的属性却只有20个,具体的每条属性对应的code style不作赘述,请参考官网

    • 安装prettier依赖:
    npm install --save-dev prettier
    复制代码
    • 创建并配置.prettierrc.js文件,除去几个很少用到的属性,笔者都进行了配置,如下:
    // https://prettier.io/docs/en/options.html
    // 创建并配置.prettierrc.js
    module.exports = {
        printWidth: 120,
        tabWidth: 4,
        useTabs: false,
        semi: false,
        singleQuote: true,
        jsxSingleQuote: false,
        trailingComma: 'none',
        bracketSpacing: true,
        jsxBracketSameLine: false, // 在jsx中把'>' 放同一行
        arrowParens: 'always',
        endOfLine: "lf"
    }
    复制代码

    除了这三个文件之外,你还得创建ignore文件,如.eslintignore,因为项目中肯定有不需要检测的文件,比如**.min.js|css这类压缩文件以及插件内容,这些屏蔽能减少不必要的检测时间。依据读者情况自己定义屏蔽范围,不作阐述。

  • EditorConfig部分
    editorConfig的作用是专门抹平不同编辑器同一配置之间差异。比较神奇的是它并不需要项目配依赖且配置及其简单,只需要编辑器安装指定扩展插件以及项目配置文件.editorConfig即可。

    • VSCode中安装插件:EditorConfig for VS Code
    • 项目根目录下创建并配置.editorConfig
    root = true
    
    [*]
    charset = utf-8
    indent_style = space
    indent_size = 4
    end_of_line = lf
    insert_final_newline = true
    trim_trailing_whitespace = true
    复制代码

命令行脚本配置

package.json文件的script脚本中配置,相信大家在各自的项目中看到或用过。

{
 // 省略其余属性...
 "script": {
     "eslint-lint": "eslint --ext .js,.vue --fix src",
     "stylelint-lint": "stylelint src/**/.css src/**/.vue src/**/.less --fix"
 }
}
复制代码

开发环境配置

1.安装eslint-webpack-plugin | stylelint-webpack-plugin依赖:

npm install --save-dev eslint-webpack-plugin stylelint-webpack-plugin
复制代码

2.webpack开发环境添加检测插件配置:

const EslintWebpackPlugin = require('eslint-webpack-plugin')
const StylelintWebpackPlugin = require('stylelint-webpack-plugin')

// webpack其余不相关配置已省略...
module.exports = {
    devServer: {
        // 当检测到错误或警告时,浏览器覆盖蒙层并显示相关错误
        warnings: true,
        errors: true
    },
    plugins: [
        // 剩余不展示在这里的配置项已经不多,
        // 更多的配置参考npm文档
        new EslintWebpackPlugin({
            extensions: ['js', 'vue'],
            fix: true, // 是否自动修复
            files: 'src'emitWarning: true, // 检测到规则warning时是否暴露
            emitError: true,  // 检测到规则error时是否暴露
            failOnWarning: true,  // 检测到规则warning时是否停止开发环境构建
            failOnError: true  // 检测到规则error时是否停止开发环境构建
        }),
        new StylelintWebpackPlugin({
            fix: true,
            files: ['**/*.{vue,htm,html,css,sss,less,scss,sass}'],
            emitWarning: true,
            emitError: true,
            failOnWarning: true,
            failOnError: true
        })
    ]
}
复制代码

编辑器配置

编辑器以VSCode为例,在配置方面主要满足以下两点:

  • 避免检测工具之间规则冲突;
  • 一键格式化,修复能自动修复的规则错误|警告。
{
    // 一键格式化
    "editor.formatOnSave": false,
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true,
        "source.fixAll.stylelint": true
    },

    /**
     *  @Extension  Vetur
     *  @Version  0.24.0
     *  @Description  专注于.vue文件的语法高亮与智能提示
     *
     *  @Tip    Vetur是一个多功能集合插件,包含了语法高亮、代码检测与格式化、
     *  以及智能提示等。代码检测与格式化与当前ESLint|Stylelint|Prettier功能重叠,
     *  不关闭的情况下可能导致不同的格式化(多人开发),因此关闭代码检测与格式化。
     *  如下:
     */
    "vetur.format.enable": false,
    "vetur.validation.template": false,
    "vetur.validation.script": false,
    "vetur.validation.style": false,

    /**
     *  @Extension ESLint
     *  @Version  2.1.8
     *  @Description 专注于代码质量的规范
     *
     *  @Tip    
     *  集成终端OUTPUT面板输出详细(verbose)日志。
     *  集成终端PROBLEMS面板输出[错误原因-规则名称]格式简单日志。
     */
    "eslint.enable": true,
    "eslint.alwaysShowStatus": true,
    "eslint.trace.server": "verbose",

    /**
     *  @Extension  Stylelint
     *  @Version    0.86.0
     *  @Description 专注于统一的样式规则规范
     *
     *  @Tip   不作具体配置,以项目内配置为主。
     */
    "stylelint.enable": true, 
    // 关闭VS Code编辑器内置的样式规则检测规范,避免与Stylelint的检测规范重复|冲突
    "css.validate": false,
    "less.validate": false,
    "scss.validate": false,

    /**
     * @Extension Prettier
     * @Version 5.5.0
     * Description 专注于代码风格的规范
     *
     * @Tip   作为默认配置,优先项目配置为主。
     */
    "prettier.enable": true,
    "prettier.printWidth": 1000,
    "prettier.tabWidth": 4,
    "prettier.useTabs": false,
    "prettier.semi": false,
    "prettier.singleQuote": true,
    "prettier.quoteProps": "as-needed",
    "prettier.jsxSingleQuote": false,
    "prettier.trailingComma": "none",
    "prettier.bracketSpacing": true,
    "prettier.jsxBracketSameLine": false,
    "prettier.arrowParens": "always",
    "prettier.vueIndentScriptAndStyle": false,
    "prettier.endOfLine": "lf",
    "prettier.embeddedLanguageFormatting": "auto",
    "prettier.useEditorConfig": true,
    "diffEditor.ignoreTrimWhitespace": false
}
复制代码

总结

总的来说,配置分两个层面:核心规则配置 + '启动器'配置。不管多花里胡哨,核心的规则是作为检测的关键,所以必须要有;其次如何提升配置启动检测也是提示开发效率也是的关键。

  • 在不启动项目且编辑器没有相关扩展插件以及配置时,可以手动输入命令行进行检测;
  • 在开发环境中,可以通过自动的实时检测报错提醒代码的规范(所有需要检测的文件都会检测);
  • 打开在可视工作区内需要检测的文件能够实时显示错误所在(红色波浪线高亮提示 + 终端面板);
  • 最后一键格式化可自动修复不符合规则代码。

在这里多提一嘴,如果你觉得这样的配置太过繁重且损耗性能或项目比较简单,你可以选择性的去除stylelint或prettier的配置(标题括起它俩的原因)。因为目前来说eslint本身也存在自动修复功能,项目不复杂或基于其它情况考虑,eslint和editorconfig配合也算是够用了。

这是笔者第一次输出文章,属实有点紧张,如有不明确或不正确的地方请大声的留言,让我们一起交流一起进步,请多多指教!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享