规范化标准学习总结(ESLint 、StyleLint 、Prettier 、Git Hooks)

规范化标准

规范化介绍

规范化是我们践行前端工程化中重要的一部分。

为什么要有规范化标准

  • 大多数情况下,软件开发需要多人协同。
  • 不同的开发者有不同的编码习惯和喜好。
  • 不同的喜好增加项目维护成本。
  • 每个项目或者团队需要明确统一的标准。

哪里需要规范化标准

  • 开发过程中编写的代码、文档、甚至是提交日志等
  • 也就是凡是开发过程中,人为编写而产生的内容,都应该被规范化操作
  • 其中代码标准化规范最为重要
    • 代码规范很大程度上决定了项目质量 和 项目可维护性
    • 为了便于后期维护 和 团队其他成员的阅读,一般会对代码的编码风格做一个统一的要求。
    • 其中一般都会包括:
      • 统一关键词和操作符中的空格
      • 统一代码缩进方式
      • 统一是否使用分号结尾
      • 统一变量或函数的命名规范

实时规范化的方法

最初开发者在落实规范化的操作时,使用提前认为约定标准的方式,然后按照这个标准进行开发工作。

最终在Code review 环节,就会按照之前约定的标准,检查相应的代码。

这种单靠人为约束的方式落实规范化,有很多问题:

  1. 人为约束不可靠
  2. 开发者很难记住所有规则

所以需要相应的工具去保障。

相比人为检查,借助工具检查更为严谨。

同时还可以配合自动化工具,自动检测。

这样的规范化就更加容易得到质量的保证。


一般,将通过工具去找到项目中不符合规范的地方的过程 叫做 「Lint」。

来源:

在刚有C语言的时候,有一些常见的代码问题,是不能被编译器打包到的。

所以有人就开发了一个叫做「Lint」的工具,用于在编译之前检查出这些问题。

避免编译之后,带来不必要的问题。

所以后续这种类似功能的工具,就都被称作「Lint」,或者「Linter」。

例如现在前端最常见的 ESLint StyleLint。

常见的规范化实现方式
  • ESLint 工具使用
  • 定制 ESLint 校验规则
  • ESLint 对 TypeScript 的支持
  • ESLint 结合自动化工具或者 Webpack
  • 基于 ESLint 的衍生工具
  • StyleLint 工具的使用
  • Git Hooks 配合Lint工具,实现代码提交前进行自动化校验

ESLint 介绍

ESLint 是当下最为主流的 Javascript Lint 工具,专门用于检测 JS 代码质量。

ESLint 很容易统一开发者的编码风格,例如缩进 换行 分号 空格的使用。

ESLint 可以帮助开发者找出代码中不合理的地方,这些问题都是开发过程中的隐患,例如:

  • 定义了一个从未使用的变量
  • 在变量使用后才对它进行声明
  • 在使用比较的时候总会使用双等号==

ESLint可以帮助开发者提升编码能力。

ESLint 安装

  • 初始化项目
  • 安装 ESLint 模块为开发依赖 npm i eslint --save-dev or yarn add eslint --dev
  • 通过 CLI 命令验证安装结果 npm run eslint -v or npx eslint -v or yarn eslint -v

ESLint 快速上手

新建js文件,编写“问题”代码

// index.js
const foo=123


function fn(){
  console.log("hello");

    console.log("eslint")


}


fn(


syy()


完成 eslint 使用配置(ESLint需要一个配置文件,否则会提示Something went wrong!

通过npx eslint --init初始化一个配置文件

How would you like to use ESLint?

如何使用ESLink

How would you like to use ESLint? 
	To check syntax only // 只检查语法性错误
	To check syntax and find problems // 检查语法错误并且发现问题代码
> To check syntax, find problems, and enforce code style // 检查语法错误,发现问题代码,校验代码风格
  • 语法错误:代码示例中的fn(就是 语法错误
  • 问题代码:代码中不可理的地方,例如:
    • 代码示例中定义了一个未被使用的变量foo
    • 以及调用了一个不存在的函数syy()
  • 代码风格:eslint默认以及自定义的一些代码风格规范,例如:
    • 缩进不统一
    • 空行太多等

项目开发中,建议选择第三种。

What type of modules dos your project use?

项目代码中使用哪种模块发方式

What type of modules dos your project use? 
	JavaScript modules (import/export) // ESM:允许使用import/export
	CommonJS (require/exports) // CommonJS:允许使用require/exports
> None of these // 没有用到任何模块化

这个问题决定代码当中是否允许使用或调用指定的语法。

Which framework does you project use?

当前项目使用的那款框架

Which framework does you project use?
 	React
	Vue.js
> None of these
Does your project use TypeScript?

项目是否使用了TypeScript,本例选择No

Does your project use TypeScript? No / Yes
Where does you code run?

代码最终将运行在什么环境中。

根据运行环境,判断是否允许使用相应环境下的API,例如:

  • 浏览器环境:window
  • node环境:process.cwd()
Where does you code run? // 多选
(*) Browser // 浏览器环境
(*) Node // node环境
How would you like to define a style for your project?

指定怎样定义项目的代码风格

How would you like to define a style for your project?
> Use a popular style guide // 使用一个市面上的主流风格
	Answer questions about your style // 通过回答问题,形成一个风格
	Inspect your JavaScript file(s) // 根据JS代码文件,推断代码风格

一般选择一个市面上的主流风格,这样项目如果有新的成员加入,他会很快适应这个风格。

Which style guide do you want to follow?

选择上面的Use a popular style guide,ESLint提供3个风格选项:

Which style guide do you want to follow? 
	Airbnb: https://github.com/airbnb/javascript
> Standard: https://github.com/standard/standard
  Google: https://github.com/google/eslint-config-google   

Airbnb和Google分别是这两个公司的具体编码规范。

Standard是开源社区的编码规范,它最大的特点是不用在语句的末尾添加分号;

这里选择Standard

What format do you want your config file to be in?

指定配置文件的文件类型。

What format do you want your config file to be in? 
> JavaScript // 方便在配置文件中添加一些条件判断
  YAML
  JSON
Would you like to install them now with npm?

以上功能需要一些npm模块,这里提示是否安装它们。

Would you like to install them now with npm?  No / Yes
配置结束

一切完成之后,项目根目录下就会生成一个.eslintrc.js的配置文件。

执行检测命令

npx eslint index.js

它首先会提示语法错误。因为在JS代码中存在语法错误时,ESLint是没有办法检测 问题代码 和 代码风格的。

修复后再次执行会就报出问题代码错误,从而可以依次解决。

可以使用提示--fix自动修复大部分问题,报错中会提示有几个问题可以被--fix修复。

建议手动修复这些问题,已提升自己的代码开发质量。

总结

  1. ESLint 可以找出代码中的问题,问题包括:
    1. 语法错误
    2. 代码不合理
    3. 风格不统一
  2. ESLint 可以自动修复代码中的绝大多数的问题(--fix

ESLint 配置

eslint可以通过package.json的eslintConfig属性配置。

上面使用npx eslint --init创建的配置文件.eslintrc.js

它可以影响当前目录和所有子目录的文件。

ESLint配置文件最终会运行在node环境中,所以它的内容就是用CommonJS的方式,导出了一个配置对象。

在最新版本的ESLint,初始化的配置文件中,默认设置evn extends parseOptions rules 4个属性

env 运行环境

JavaScript在不同的运行环境,可以使用不同的API,这些API很多时候都是以全局变量的形式提供。例如浏览器环境的window,node环境的process。

配置文件中env属性用于标记当前代码最终的运行环境。

ESLint根据env判断哪些全局变量是否是可用的,从而避免代码中使用到了不存在的变量。

env中的每一个环境,对应着一组预定义的全局变量。

一旦开启了某个环境,这个环境当中所有的全局变量就都能够允许被使用。

注意事项

上例中,将evn中的browser设置为false,理论上ESLint就不允许代码中使用document等浏览器全局变量。

但是执行校验并没有报出错误。

这是因为上例使用的是 Standard 校验风格,最终ESLint配置结果会继承 Standard 中的配置。

而在 Standard 配置中,它也做了一些额外的配置。

比如 document 和 window 在任意环境中都允许使用。

可以在 node_modules 中寻找 eslint-config-standard 查看源码求证。

校验风格对应的模块名,就是eslint-config-<extends中配置的风格名称>

可以看到这个模块的功能就是导出eslintrc.json文件的内容。

查看这个文件,可以看到它是通过globals属性将document navigator window设置为了全局只读(readonly)的成员。

所以此时可以使用alert来校验配置browser:false是否成功。

env 可配置的所有环境 及 对应的全局变量
  • browser - 浏览器环境中的全局变量
  • node - Node.js 全局变量和 Node.js 作用域
  • commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的,只在浏览器环境运行的代码)
  • shared-node-browser - Node.js 和 Browser 通用全局变量
  • es6 - 启用除了 modules 以外的所有 ECMAScript 6 特性 (该选项会自动设置 ecmaVersion 解析器选项 为 6)
  • es2017 - 增加所有 ECMAScript 2017 全局变量,以及自动设置 ecmaVersion 解析器选项为 8
  • es2020 - 增加所有 ECMAScript 2020 全局变量,以及自动设置 ecmaVersion 解析器选项为 11
  • worker - Web Workers 全局变量
  • amd - 将 require()define() 定义为像 AMD 一样的全局变量
  • mocha - 添加所有 Mocha 测试全局变量
  • jasmine - 添加所有 Jasmine 1.3 和 2.0 版本的测试全局变量
  • jest - Jest 全局变量
  • phantomjs - PhantomJS 全局变量
  • protractor - Protractor 全局变量
  • qunit - QUnit 全局变量
  • jquery - jQuery 全局变量
  • prototypejs - Prototype.js 全局变量
  • shelljs - ShellJS 全局变量
  • meteor - Meteor 全局变量
  • mongo - MongoDB 全局变量
  • applescript - AppleScript 全局变量
  • nashorn - Java 8 Nashorn 全局变量
  • serviceworker - Service Worker 全局变量
  • atomtest - Atom 测试全局变量
  • embertest - Ember 测试全局变量
  • webextensions - WebExtensions 全局变量
  • greasemonkey - GreaseMonkey 全局变量

这些环境并不是互斥的,可以同时开启多个环境。

extends 配置继承 / 共享配置

继承一些共享的配置。

实际上就是指定ESLint使用的校验风格,最终ESLint配置会继承这些风格的配置。

它可以配置为:

  • String:一个配置文件的路径 或 可共享配置的名称。
  • Array[String]:多个配置组合,后面的配置继承并覆盖前面的配置。

如果使用的是配置风格模块的名称,可以在 node_modules 中寻找到名为 eslint-config-<名称> 的校验风格模块。

也可以自定义一些公共配置的文件或模块,使用extends去继承这些配置。

parserOptions 语法解析器

语法解析器用于控制是否使用某个ES版本的 语法

sourceType

值为 script (默认)或 module,表示使用ESM的方式。

ecmaVersion

指定使用ES的版本。

  • 可以是版本号:3,5(默认),6,7,8,9,10,11
  • 5版本之后的也可以使用年份:2015,2016,2017,2018,2019,2020

设置parserOptions.ecmaVersion:5最高解析ES5版本的语法,使const校验失败。

注意:

当前配置使用了 Standard ,Standard配置中parserOptions.sourceTypemodule

即使用 ESM 新语法的方式,但ES5不支持,所以此时会报错:

sourceType 'module' is not supported when ecmaVersion < 2015

“当ES版本低于2015时,不支持sourceType为module。”

可以将node_modules/eslint-config-standard中的sourceType配置为script

也可以修改当前配置中的parserOptions.sourceType

执行校验提示:The keyword 'const' is reserved

ecmaFeatures

定义一个对象,指示要使用的其他语言的功能/特性。

例如使用 jsx

module.exports = {
  parserOptions: {
    ecmaFeature: {
      jsx: true
    }
  }
}
注意事项

parserOptions 中的 ecmaVersion 以及 ecmaFeature,影响的只是「语法检测」,不代表这些ES版本或语言的全局变量可用。

使用某个ES版本的全局变量可用,必须通过环境选项env配置。

而且,通过环境env配置 ES 版本,会自动启用对应版本的语法支持。

例如:

  • {"env": {"es6":true}} 自动启用ES6语法
  • 但是{"parserOptions": {"ecmaVersion": 6}} 不会自动启用ES6全局变量

rules

配置 ESLint 配置中具体某个校验的开启 / 关闭。

使用方式就是向 rules 对象添加具体的校验规则属性:

  • key:内置的校验规则名称
  • value:可以为字符串或数组
    • String:设置错误级别(rule ID),'no-alert':'error',值为以下3个之一
      • off or 0:关闭这个规则
      • warn or 1:启用这个规则,触发时发出warning警告(不会影响 exit code,即不会退出)
      • error or 2:启用这个规则,触发时会报错(触发时 exit code 为 1,即会退出)
    • Array:元素1为 这个规则的错误级别,后面的元素为这个规则的选项,`‘quotes’:[‘error’, ‘double’]

Exit codes:当检测代码时,ESLint会在 exit code 为以下值时退出:

  • 0:检测成功,并且没有错误。
  • 1:检测成功,并且至少存在一个错误,或者警告数量超过--max-warnings选项允许的数量。
  • 2:由于配置问题或内部错误,导致检测失败。

Rules可以扩展规则集:

  • 规则集中如果为使用某个规则,则可以通过rules开启某个规则
  • 规则集中如果配置了某个规则,可以通过rules修改这个配置:
    • value设置为字符串则只会 覆盖 当前配置的规则集 中 这个规则 的 错误等级。
    • value设置为数组,则会直接覆盖这个规则的配置。

开启no-alert校验规则,使代码中不能使用alert

module.exports = {
  rules: {
    'no-alert': true
  }
}

ESLint 官网给出了所有可以使用的内置校验规则列表:ESLint Rules

globals

no-undef规则将警告:“使用但未在同一文件中定义的变量”这个行为。

globals 可以额外的声明代码中可以使用的全局变量。

globals 的值是一个对象:

  • key:要使用的全局变量的名称
  • value:可以配置为以下:
    • 'writable':可以访问,可写,允许被覆盖
    • 'readonly' :可以访问,只读,禁止覆盖
    • 'off':禁用该全局变量
  • 由于历史原因,以下value等效于上面对应的值,但不建议使用这些旧值:
    • false or read:等同于readonly
    • true or writeable:等同于writable

globals 同 rules 一样,会覆盖最终配置结果。

plugins

每一个eslint插件是一个命名格式为eslint-plugin-<plugin-name>的npm模块,比如eslint-plugin-react

在ESLint中使用插件时,需省略eslint-plugin-前缀,ESLint在内部只使用没有前缀的名称去定位插件。

在plugins中添加了插件,相当于在配置文件require(插件)。

使用插件的规则需要手动开启才能使用。插件可以这样使用(而不需要在plugins中添加插件):

  1. rules属性中启用或配置插件的某个规则:

    1. rules: {
        '<plugin-name>/<rule-name>': 'off'
      }
      
  2. extends属性中启用插件的配置

    1. extends: [
        'plugin:<plugin-name>/<config-name>'
      ]
      
  3. env属性中定义,在一个插件中使用某个环境

    1. env: {
        '<plugin-name>/<env-name>': true
      }
      

settings

ESLint支持在配置文件添加共享设置。settings对象将提供给每一个将被执行的规则。

例如提供一个指定react版本的共享配置:

settings: {
  react: {
    version: 'detect' // detect自动检测实际安装的版本
  }
}

parser

「语法解析器」。默认使用Expree。常用的与ESLint兼容的解析器:

  • babel-eslint:包含babel解析的解析器。
  • @typescript-eslint/parser:typescript解析器,将TypeScript转换成与ESTree兼容的形式,以便可以在ESLint中使用它。

ESTree 是一种json风格的AST(抽象语法树)规范,它是社区中的一个非官方的语法表达标准。

当前流行的babel和eslint的实现都是基于ESTree。

ESLint 配置注释

配置注释:将配置直接通过注释的方式写在脚本文件中,然后再去执行代码校验。

配置注释的作用:

  1. 临时禁用规则:某行代码或某块代码
  2. 声明全局变量:影响当前脚本
  3. 修改某个规则的配置:影响当前脚本
  4. 临时开启某个环境:影响当前脚本

在开发中使用 ESLint,难免会遇到一两个违反配置规则的地方。

这种情况下,不能因为这一两个点推翻整个校验规则的配置。

这时就可以使用 ESLint 的配置注释,解决类似的问题。

更多使用查看官方文档。

// 对单行代码禁用规则
// standard 不允许这样使用字符串模板语法
const str1 = '${name} is a coder' // eslint-disable-line no-template-curly-in-string

console.log(str1)

// 对某块代码禁用规则
/* eslint-disable no-unused-vars, no-undef */
const str2 = 'no-unused-vars'
console.log(str3)
/* eslint-enable no-unused-vars, no-undef */

// 声明全局变量,可以在当前脚本任意位置使用
console.log(str4)
/* global str4, str5:readonly */
console.log(str5)

// 临时修改某个规则配置,影响当前脚本
// 不会被修改的变量,应该用const声明
let str6 = 'prefer-const'
// 强制使用“三等号”
if (str6 == 'eqeqeq') {
  console.log('eqeqeq')
}
/* eslint prefer-const: 'warn', eqeqeq: [1, 'always'] */

// 启用 node 环境,影响当前脚本
console.log(__dirname)
/* eslint-env node */

ESLint 结合自动化工具

集成 ESLint 到自动化构建工作流中的优点:

  1. 集成之后,确保ESLint 一定会工作。
  2. 与项目统一,管理更加方便。

Gulp 集成 ESLint

示例代码参考:notes\note_code\04-ESLint\02-gulp-integrate-eslint。

安装模块 eslint 和 插件 gulp-eslint

在配置文件gulpfile.js中找到编译JS的任务,在babel处理之前将eslint集成进去,因为应该用eslint校验源代码。

// gulpfile.js
const script = () => {
  return src('src/assets/scripts/*.js', { base: 'src' })
    .pipe(plugins.eslint())
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}

记得初始化ESLint的配置文件并安装相应的npm包。

向JS脚本中添加问题代码,执行script任务,任务成功执行,eslint并没有报错。

并没有实现「eslint发现问题,并直接体现出来,同时能够终止后续的编译任务」的效果。

原因是,这里的 gulp-eslint 插件,默认只会检查代码中的问题,并不会根据检查的结果做出任何的反馈。

解决方法是:

  1. 使用 gulp-eslint 插件的 format()方法,将结果打印到控制台。
  2. 使用插件的 failAfterError()方法,使检测到错误代码exit code1时,退出进程。
const script = () => {
  return src('src/assets/scripts/*.js', { base: 'src' })
    .pipe(plugins.eslint())
    .pipe(plugins.eslint.format())
    .pipe(plugins.eslint.failAfterError())
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}

Webpack 集成 ESLint

webpack 集成 ESLint ,是通过 Loader 而不是 Plugins 集成的。

这样就可以在实现打包JS代码之前,先通过 eslint 的加载器校验JS代码。

React项目示例代码参考:notes\note_code\04-ESLint\03-webpack-integrate-eslint。

安装eslinteslint-loader,初始化eslint配置文件并安装相应模块。

在babel-loader前添加eslint-loader,或者使用enforce属性指定eslint-loader的执行顺序。

module.exports = {
  // ...
	{
    test: /\.js$/,
    exclude: /node_modules/,
    use: 'babel-loader',
  },
    {
    test: /\.js$/,
    exclude: /node_modules/,
    use: 'eslint-loader',
    enforce: 'pre',
  },
}

执行npx webpack打包就会执行eslint校验。

配置 ESLint 支持 React

上例执行打包后,eslint 校验到 React 使用有问题:

导入了React和App模块,但是没有被使用到(实际上在JSX中使用了)

这时ESLint就需要额外的插件来支持React的JSX语法。

社区中为React专门提供了一个插件eslint-plugin-react

安装这个插件,并配置。

在配置文件中的plugins数组中添加这个插件。

注意:使用插件时,需省略eslint-plugin-前缀,ESLint在内部只使用没有前缀的名称去定位插件和规则:

module.exports = {
  env: {
    browser: true,
    es2020: true,
  },
  extends: [
    'standard',
    // 可以在extends中开启插件提供的配置
    'plugin:react/recommended' // 使用插件提供的配置 recommended
  ],
  parserOptions: {
    ecmaVersion: 11,
  },
  rules: {
    // 可以在rules中单独开启插件的规则
    // 'react/jsx-uses-react': 2, // 防止React被标记为未使用
    // 'react/jsx-uses-vars': 2, // 防止在JSX中使用的变量被标记为未使用
  },
  plugins: ['react'],
}

现代化项目集成 ESLint

类似 Vue.js 和 React 这种主流框架,它们CLI工具中已经集成了 Webpack 和 ESLint 等工具,不需要单独去配置。

以vue-cli创建的项目为例:

全局安装vue-cli:npm install @vue/cli -g

创建vue项目:vue create vue-app,vue会询问配置问题。

其中当询问Pick additional lint features应该在何时使用lint校验?

  • 选项1:Lint on save真正含义是「在webpack构建时自动校验」,而不是「文件保存时自动校验」。
    • 因为一般我们使用监视模式,在文件改动后,webpack就会自动执行编译,所以这里就称为保存(save)时校验。
  • 选项2:Lint and fix on commit,利用git hook钩子,在commit时修复和校验。

一般建议两个都勾选。

ESLint 检查 TypeScript

以前对TypeScript的检查都是使用tslint工具。

后来由于tslint官方放弃维护,转而建议使用eslint配合 TypeScript 插件 实现对代码的校验。

npx eslint --init初始化eslint配置文件

注意,如果没有先安装typescript模块,初始化eslint配置时就会提示错误信息。

但是,配置文件依然安装成功,之后安装typescript模块,也可以正常使用。

Error: An error occurred while generating your JavaScript config file. A config file was still generated, but the config file itself may not follow your linting rules.
// 提示 typescript 解析器(parser)依赖typescript模块
Error: Failed to load parser '@typescript-eslint/parser' declared in 'BaseConfig': Cannot find module 'typescript'
// eslint配置
module.exports = {
    "env": {
        "browser": true,
        "es2020": true
    },
    "extends": [
        "standard"
    ],
    "parser": "@typescript-eslint/parser", // 使用typescript解析器
    "parserOptions": {
        "ecmaVersion": 11
    },
    "plugins": [
        "@typescript-eslint" // 加载typescript规则,等待被配置后使用
    ],
    "rules": {
    }
};

Stylelint 介绍

CSS代码的lint操作,一般使用Stylelint工具。

它与 ESLint 使用基本一致:

  • 提供默认的代码检查规则,可以在配置中选择性的开启或关闭某项规则。
  • 提供CLI工具,可以在终端中执行校验命令。
  • 通过插件支持 Sass Less PostCSS 这些CSS衍生语法的代码检查。
  • 支持 Gulp 或 Webpack 集成

快速使用

安装

npm install stylelint -D

配置

与ESLint一样,使用Stylelint,也必须有一个配置文件。

Stylelint 使用 cosmiconfig工具从当前工作目录查找并加载配置信息。

当找到一个目标后,就停止搜索,也可以使用--config命令快速指定配置文件。

配置信息来源:

  • package.jsonstylelint属性(ESLint是eslintConfig
  • 一个.stylelintrc文件
    • 文件无后缀名,则内容可以为json或yaml
    • 也可以指定后缀名:.json .js .yaml .yml
  • 一个导出一个对象的stylelint.config.js文件

Stylelint没有提供像ESLint一样的--init初始化配置文件的命令,所以需要手动创建配置文件。

extends 配置继承 / 共享配置

Stylelint 默认并没有提供一个共享配置,像 ESLint的 eslint:recommended

需要安装使用的配置模块,常用的共享配置模块:

  • stylelint-config-recommended
  • stylelint-config-standard

与ESLint的区别就是,添加配置的名称,必须是完整的:

  • Stylelint 完整名称:extends: 'stylelint-config-standard'
  • ESLint 省略eslint-config- 前缀:extends:'standard'
module.exports = {
  extends: "stylelint-config-standard"
}
使用

npx stylelint ./index.css

注意,Stylelint 检查的文件路径中的目录分隔符必须为/,使用\会报错:

Error: No files matching the pattern ".\index.css" were found.

自动修复:

npx stylelint index.css --fix

校验 Sass

校验Sass,需要安装一个配置模块stylelint-config-sass-guidelines

module.exports = {
  extends: ['stylelint-config-standard', 'stylelint-config-sass-guidelines'],
}

Prettier

近年来使用频率特别高的通用的前端代码格式化工具。

几乎可以完成所有类型代码的格式化工作。

通过Prettier自动化格式功能,就可以落实前端项目中的规范化标准。

安装:npm install prettier -D

执行格式化命名:npx prettier style.css

这个命令默认会将格式化后的代码输出到控制台中,而不是覆盖修改源文件。

添加--write使其覆盖源文件:npx prettier style.css --write

也可以使用通配符,格式化当前目录下所有文件及下级文件:npx prettier . --write

Git Hooks

通过lint工具确保代码规范的落地,但是在过程中还有遗漏的问题。

比如,代码提交至仓库之前未执行lint工作(未使用或忘记使用lint工具),直接将有问题的代码提交到了远端仓库。

在后期进行项目集成时,导致项目代码有可能不被CI通过。

这种情况,lint工具就丧失了它的意义。

相比口头要求团队成员在提交代码前执行一次lint命名。

更好的方案是,通过某种方式(Git Hooks) 在代码提交前 强制 lint。

Git Hooks 介绍

Git Hooks 也称为 Git 钩子,每个钩子都对应一个任务或具体的Git操作,例如 push、commit。

通过编写 shell 脚本,定义一些钩子任务触发时,具体要执行的操作。

Git Hooks 使用

新建一个git仓库,查看.git/hooks目录,里面的每个.sample文件就是每一个钩子。

当前只需要使用到pre-commit.sample钩子。

它对应的就是commit操作。

当执行commit操作时,就会触发这个钩子中所定义的任务。

复制这个文件,重命名为pre-commit(也就是去掉.sample后缀),编写其中的脚本内容:

保留执行环境代码:#!/bin/sh

编写一段测试脚本:echo "before commit"

再次执行commit操作时,就会执行echo命令,在终端输出before commit

#!/bin/sh
echo "before commit"

Husky - ESLint 结合 Git Hooks

很多前端开发者并不擅长使用shell。

并且.git/hooks中的文件不会被提交到远端仓库中,无法自动令团队成员使用。

所有有人开发了一个可以实现 Git Hooks 的使用需求 的工具模块:Husky

使用 Husky 就可以在不编写shell脚本的情况下,使用Git Hooks 钩子。

安装这个模块后,就会自动在.git/hooks目录下添加Git钩子文件。

注意,使用之前,请确认上例中创建的pre-commit 自定义文件已被删掉,否则会影响 Husky的使用。

安装

npm install husky -d

模块安装完成后,可以看到.git/hooks目录下多了一些Husky自定义的钩子,如pre-commit

它们负责完成一些任务,但不需要关心它们如何实现。

npm uninstall husky -d 卸载Husky后会同步删除Husky创建的 Git hooks 钩子。

注意:使用npm安装Husky,因为yarn无法在终端执行husky命令,commit 触发 husky的git hooks可行(也有说不可行的)。

npx也无法自动识别本地的husky。

如果node_modules中已经包含了husky,可以通过npm rebuild重新安装它的Git Hooks。

配置

package.json中添加一个husky字段并配置。

// package.json
{
  // ...
  "scripts": {
    // 可以使用--fix或prettier --write(慎用)自动修复
    "lint": "eslint ."
  },
  "husky": {
    // 在hooks中定义一些钩子任务
    "hooks": {
      // 当进行commit提交时,就会运行scripts中的test脚本
      "pre-commit": "npm run lint"
    }
  }
}

也可以通过配置文件配置:.huskyrc, .huskyrc.json, .huskyrc.js or husky.config.js

// .husky.json
{
    "hooks": {
        // 当进行commit提交时,就会运行scripts中的test脚本
        "pre-commit": "npm run lint"
    }
}
影响范围

如果仓库包含多个package.json(多项目),安装Husky,会直接在根目录的.git/hooks中添加钩子文件。

并且在提交本仓库的代码时,配置了husky.hooks的任务,都会触发。

但是仍然建议在根目录的package.json中配置husky。

lint-staged

上例使用husky在代码提交前执行lint校验。

但是校验的是项目全部文件,包括不提交的文件。

lint-staged 是一个在git暂存文件上运行linters的工具。

可以实现提交代码执行 lint 校验时,只 lint 提交的文件代码。

lint-staged包含一个脚本,它可以 运行任意的 shell任务,并将 [由指定的glob模式过滤的] [一系列 暂存(Staged)文件] 作为参数。

Git文件的4种状态:

  • Untracked:未跟踪,此文件在文件夹中,但并没有加入到git库中,不参与版本控制。
    • 通过git add将状态变为Staged
  • Unmodify:文件已经入库,未修改,即版本库中的文件快照内容与文件夹中完全一致。
    • 这种状态的文件有两种去处:
      • 如果被修改会变为Modified
      • 如果使用git rm移出版本库,则成为Untracked文件
  • Modified:文件已修改,仅仅是修改,并没有进行其他操作。
    • 这个文件也有两种去除:
      • 通过git add可进入暂存状态Staged
      • 使用git checkout从库中取出文件,覆盖当前文件,状态变为Unmodify
  • Staged:暂存状态。
    • 执行git commit则将修改同步到库中,这时库中的文件和本地文件又变为一直,文件状态变为Unmodify
    • 执行git reset HEAD filename取消暂存,文件状态为Modified

因为暂存文件都是提交的文件,所以仅对它们进行lint,可以省略项目其他未提交文件的lint。

简单使用

在上例husky的基础上,安装npm install lint-staged -D

在package.json中配置任务,并添加执行lint-staged命令的脚本,最终在husky的pre-commit钩子任务中执行这个脚本。

{
  // ...
  "scripts": {
    "lint": "eslint .",
    "precommit": "lint-staged"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run precommit"
    }
  },
  "lint-staged": {
    // key是glob匹配字符串
    // value是执行的任务,多任务可以使用数组
    "./*.js": "eslint"
  }
}
快速使用

最快速的方式就是执行npx mrm lint-staged命令。

它会根据package.js中依赖的lint工具,安装和配置husky和lint-staged。

所以请确认在执行这个命令前,已经安装了package.json中的依赖,并配置好代码质量工具,如Prettier,ESLint。

mrm模块在尽可能保证配置不变的情况下,添加配置。

它提供很多配置任务,例如

  • mrm gitignore:创建一个.gitignore文件
  • mrm eslint --init:初始化eslint配置文件,同eslint --init一样
  • mrm lint-staged任务:
    • 根据npm scripts 推断lint命令
    • 在package.json中添加lint-staged配置,并将推断的lint命令添加到里面
    • 设置一个pre-commit Git钩子,用于执行lint-staged命令
    • 安装相关依赖:husky lint-staged

mrm虽然会覆盖规则,但会尽量保留开发者自定义的规则。

npx mrm lint-staged执行后的package.json

{
  // ...
  "devDependencies": {
    // ...
    "husky": "^4.2.5",
    "lint-staged": "^10.2.11"
  },
  "scripts": {
    "lint": "eslint ."
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.js": "eslint --cache --fix"
  }
}

配置

lint-staged的配置也可以使用配置文件:.lint-stagedrc lint-staged.config.js

推荐文章

手把手教你 ESLint

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值