Skip to content

前端工程化

EditorConfig

EditorConfig是编辑器级别的,通过在项目中添加配置文件.editorconfig,EditrConfig插件读取配置文件,并根据配置文件来设置编辑的设置

editorconfig
root = true #表示是最顶层的配置文件,设为 true 时,停止向上查找

[*]
charset = utf-8 # 编码字符集
indent_style = space #设置缩进为 tab 或 space 。如果为tab,输入tab变现为为indent_size个空格,实际上是添加制表符;如果为space,会把tab替换为indent_size个空格
indent_size = 2 #设置缩进所占列数
end_of_line = lf #设置换行符,值为lf、cr和crlf
insert_final_newline = true #设为 true 表示使文件以一个空白行结尾
trim_trailing_whitespace = true #设为 true 表示会去除行尾的空白字符

[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

注意:

  • vscode需要安装插件,才会应用配置文件的规则

    image-20230825174639784

Prettier

Prettier官网

整体认识

  • Prettier包

    是统一代码风格的工具,需要通过npm下载到项目中,通过prettier --write触发格式化(一般用Git Hooks自动触发,后面会详细介绍)

  • 编译器的Prettier插件

    依赖于Prettier包(先在项目中安装Prettier包)才能实现其功能,用于格式化代码,我们能够通过编译器对Prettier插件的设置,调整触发格式化的时机(可以设置保存自动触发,或者将编译器格式化工具设置为Prettier,手动格式化)

  • Prettier配置

    Prettier包和Prettier插件均需要识别配置文件,按照配置文件的规则格式化文件

    Prettier将从要格式化的文件的位置开始解析,并向上搜索文件树,直到找到(或没有)配置文件就停止查找

    如不存在配置文件,Prettier 将依照默认值处理

    同一级别的不同类型的配置文件的优先级:

    text
    package.json 中的 prettier 字段
    .prettierrc 文件
    .prettierrc.json 文件
    .prettierrc.js 文件
    .prettierrc.toml 文件
  • Prettier包支持处理的文件类型

    Prettier通过解析器(parser),根据文件类型自动推断使用哪种解析器来进行工作

    image-20220322110236602

  • 注意

    1. 既然有Prettier包,通过命令可以格式化,为什么还要安装Prettier插件?

      在编写代码中,反复执行prettier --write命令,是比较浪费时间的,如果使用Prettier插件,我们可以设置保存自动触发格式化,这样我们编写代码的过程中,就能实时的看到Prettier的格式化效果

    2. Prettier的配置中,存在与EditorConfig同样功能的字段,编译器按照哪个配置文件处理?

      对于一条功能重叠的属性,优先级关系是:Prettier 配置 > editorconfig 配置 > Prettier 默认值。下面的EditorConfig配置,Prettier 会将其解析转换为相应的 Prettier 配置

      EditorConfig配置Prettier配置
      end_of_lineendOfLine
      indent_styleuseTabs
      indent_size/tab_widthtabWidth
      max_line_lengthprintWidth

细节学习

  • Prettier包

    shell
    npm install -D prettier

    安装依赖之后,命令行调用 prettier --write [file/dir/glob] 即可对指定的文件、目录、匹配项进行代码格式化。

    但通常我们不会选择手动调用,而是集成到 Git Hooks 中,使其成为自动化流程中的一部分。

  • Prettier插件

    WebStrom中内置了Prettier插件不必自动安装,但是必须要先安装Prettier包,才能起作用

    image-20220327171314327

    WebStorm中还提供了,commmand+option+shift+p的快捷键,作为专门使用Prettier进行格式化的快捷键

  • Prettier配置

    下面是Prettier配置的所有细项,且下面给的值,就是Prettier的默认值

    js
    //prettierrc  使用时去掉注释
    {
      
        //—————基本配置————
        "printWidth": 80, //每行最大宽度,设置了这个并不一定保证每行一定最大是80,而是尽可能的按照这个标准
        "tabWidth": 2, // tab键的缩进宽度
        "useTabs": false, //缩进风格是否为tab,false时缩进风格时space。与EditorConfig的indent_style相似
        "semi": true, //是否使用分号结尾
        "singleQuote": false, //是否使用单引号;对html的属性、vue的html部分,默认为双引号,这个属性只能作用于JS部分
        "bracketSpacing": true, //是否保留对象内侧两端的空格,比如 { foo:bar } 和 {foo:bar} 的区别,对【HTML,Vue,JSXVue,Angular】中的HTML代码起作用
        "bracketSameLine": true, //详见,下文
        "arrowParens": "always",// 箭头函数参数使用圆括号包裹 比如 (x) => x 和 x => x 的区别;  "always" 总是包裹 ;"avoid" 尽可能避免包裹
        "endOfLine": "lf", // 指定换行符
        "proseWrap": "preserve", //超出`printWidth`设置的宽度后,发生折行。"always" 当超出print width(上面有这个参数)时就折行(添加了\n);"never" 如果超出printWidth,只进行软折行;"perserve" 按照文件原样折行
        "trailingComma": "es5",// 对象有多行时,是否结尾添加逗号。"es5" ES5中允许逗号的容器中添加逗号;"all" 尽可能添加逗号;"none" 不允许添加逗
        "singleAttributePerLine": false,//true为强制在html、vue、JSX中,每行只有一个属性
    
    
    
    
        //————格式化文件内容配置————
        "vueIndentScriptAndStyle": false, // 是否对 Vue 文件中 <script> 和 <style> 标签内的代码应用缩进
        "embeddedLanguageFormatting": "auto", // 是否格式化嵌入引用代码,比如 markdown 文件中嵌入的代码块; "auto" 自动识别并格式化;"off" 关闭自动格式化
        "htmlWhitespaceSensitivity": "css",
    
    
    
        //————格式化代码范围————
        "rangeStart": 0,// 只格式化文件中的一部分,范围开始于第几行
        "rangeEnd": Infinity,// 只格式化文件中的一部分,范围结束于第几行
        "requirePragma": false,// 限制只格式化在文件顶部做了特殊标识(详情在下面)的文件,适用于在大型未格式化项目中,先指定少量文件格式化
        "insertPragma": false, //格式化后,在被格式化的文件开头插入 @format 标记
    
    
    
        //————JSX相关————
        "jsxSingleQuotes": false,// JSX中使用单引号,默认是 false
        "jsxBracketSameLine": false, // 多行 JSX 的元素是否能和属性同行,默认是 false
    
    
    
        //————其他————
        // "parser": "none",  指定解析器,Prettier会根据文件路径自动推断解析器,比如 .js 文件使用 babel 解析,.scss 文件使用 post-scss 解析 ,默认为不设置,自动推断,所以一般不用设置这个字段
    
        "quoteProps": "as-needed",
    
    }

    bracketSameLine

    不适用于自闭合元素

    html
    <!--ture-->
    <button
      className="prettier-class"
      id="prettier-id"
      onClick={this.handleClick}>
      Click Here
    </button>
    html
    <!--false-->
    <button
      className="prettier-class"
      id="prettier-id"
      onClick={this.handleClick}
    >  <!--注意这里,换行了-->
      Click Here
    </button>

    requirePragma

    值为true,则只格式化文件开头是以下标记的文件

    text
    /**
     * @prettier
     */
    
    或者
    
     /**
     * @format
     */

    trailingComma

    这个属性在vue文件中不生效,在js文件中生效

    js
    //none
    let a = {
      name: 'jack',
      age: 19
    };
    
    //all和es5
    let a = {
      name: 'jack',
      age: 19, //重点是结尾的逗号
    };

ESlint

Prettier只涉及代码风格的处理,而不涉及代码质量检查。通过使用ESlint对代码质量进行检查(ESLint也有部分配置,是针对于代码风格的,比如加不加分号,使用tab还是空格,这部分与Prettier会发生冲突,这个问题如何解决,后面会介绍)

ESLint中文网

整体认识

  • ESLint包

    代码质量检查的工具,需要通过npm下载到项目中,通过命令触发代码检查(--ext)或修复(--fix)

    ESLint包中文网:https://eslint.bootcss.com/

  • ESLint插件

    依赖于ESlint包(先在项目中安装ESlint包)才能实现其功能。

    Eslint包才具有对代码进行检查的功能,而Eslint插件仅仅是和编译器结合起来,将检查出来的问题在编辑器中做出提示(见下图)等等功能。

    image-20221030162601887

    我们能够通过编译器对ESlint插件进行设置,调整触发ESLint检查的时机(可以设置保存自动触发)

  • ESLint配置

    ESLint包和ESLint插件均需要识别ESLint的配置文件,按照配置文件的规则检查文件,与Prettier不同的是,只有在你的配置文件中扩展了一个可分享的配置或者明确开启一个规则,ESLint 才会去校验你的代码。如果项目下没有ESLint的配置文件,就不会去检查代码【提示:Prettier没有配置文件,会遵从默认的规则进行格式化;Prettier配置文件中和EditorConfig配置文件中没有配置的项,也会按照Prettier的默认规则去格式化】

    ESLint与Prettier查找配置文件的方式不同,是自成一派,以下述顺序排序优先级。在找到配置文件后会继续向上查找,找到"root": true 的文件为止,然后合并所有文件的配置对象。对于重复的配置项,要检查的文件所在目录中的那个配置文件,优先级更高。这种模式的优点在于自动实现按目录层级继承。

    同一级别的不同类型的配置文件的优先级:

    text
    .eslintrc.js
    .eslintrc.yaml
    .eslintrc.yml
    .eslintrc.json
    .eslintrc
    package.json的eslintConfig字段

前世今生

ESLint之前有JSLint和JSHint,之所以ESLint能大火是因为 ES6 的出现。ES6 发布后,因为新增了很多语法,JSHint 短期内无法提供支持,而从上面的原理分析,我们就能知道 ESLint 只需要有合适的解析器就能够进行 lint 检查。当时 babel 为 ESLint 提供了支持,开发了 babel-eslint,让ESLint 成为最快支持 ES6 语法的 lint 工具

细节学习

  • ESLint包

    npm install -d eslint

    安装依赖之后,命令行调用下面的命令即可对指定的文件、目录、匹配项进行ESLint检查和修复

    与Prettier一样,通常我们不会选择手动调用,而是集成到 Git Hooks 中,使其成为自动化流程中的一部分。

    shell
    # 命令格式
    eslint [options] [file|dir|glob]*
    
    # 指定eslint作用路径,这里是任意路径下的js文件
    eslint **/*.js 
    
    # 在指定目录下,指定要检查的文件类型(默认为.js)。可以指定多个类型,用逗号分隔
    # 注意这里的文件目录不能具体到文件,否则--ext会被忽略,就是成了上个命令的情况了
    eslint  --ext .js,.ts <文件目>  
    
    # --fix修复
    eslint --fix --ext .js,.ts <文件路>

    注意:并非所有的ESLint规则,都可以使用--fix修复,请查阅ESLint规则大全

    image-20220323185257385

  • ESLint插件

    WebStrom中内置了ESLint插件不必自动安装,但是必须要先安装ESLint包,才能起作用

    ESLint是对代码质量的检查,我们可以设置保存自动修复(实际上就是自动执行了 eslint --fix),但是并不是所有ESLint规则,都可以自动修复( 规则大全中可以查看哪些ESLint规则支持自动修复),很多情况需要我们自己根据ESLint的规则手动修改代码,所以ESLint设置里没有"使用ESLint格式化"这种选项,因为ESLint主要功能不是用来改变代码格式的(也有部分ESLInt规则是),而是代码质量的检查

    image-20220323100746808

    另一个重要的设置,这里可以设置WebStrom按照ESLint配置文件进行检查(默认也是这样),如果违反ESLint规则就是在代码中,用波浪线标识出来

    image-20220323102158132

  • ESLint配置文件

    安装eslint

    shell
    npm install eslint

    初始化eslintrc.js配置文件

    shell
    npm create @eslint/config
    js
    module.exports = {
      	//表示这个是顶层的eslint配置文件,eslint不会再向上层查找文件了
      	"root":true
      
      	//不同环境内置的全局变量。下面的举例的document、Promise、console等都没引入就能使用,就是因为其是对应的环境中内置的全局对象。eslint记录了不同环境内置的全局对象,开启就不会提示语法问题
        "env": {
            "browser": true, //支持浏览器,比如document的方法,console.log()
            "es2021": true, //支持ES6语法,比如Promise
            "node": true //支持node语法,比如require()方法,(用于引入模块)
        },
      
      
      	//全局变量,有些全局变量,不是env这几种环境中内置的,例如:小程序内置的app函数,只需要在这里配置,不声明就使用app这个变量,不会报错
      	"globals":{
          "app":"readonly" //"readonly"代表app变量只读,不允许赋值、"writable"代表app变量可读可赋值
        },
    
      
      	//语法规则的支持
        "parserOptions": {
            "ecmaVersion": "latest", //支持es语法
          	"sourceType":"module", //开启后支持import语法
          	"ecmaFeatures":{ 
              "jsx":true//支持jsx
    				}
        },
      
      	"parser":"esprima", //指定语法解析器,默认使用的是espress,使用其他解析器需要安装 npm install esprima
      
      
      	//插件(携带额外的规则配置到rules中、部分规则的集合配置到extends中),插件命名格式为:eslint-plugin-xxx,配置在plugins字段中可以省略'eslint-plugin'
      	"plugins":[],
      	//规则集合,第三方规则结合的使用格式:plugin:xxx
        "extends": ["eslint:recommended"],
      	//rules中配置的规则会覆盖extends字段中指定的规则集合
        "rules": {
          "quotes":["error","double"] //双引号,错误等级error。第一个参数:是错误等级,有error或2(错误)、warn或1(警告)、off或0(关闭)三种等级。前面讲的ESLint插件,也会读取错误的等级,在编辑器中做出不同的错误提示。剩下的参数是对规则的配置
        }
    }

    extends、rules、plugins三者的关系

    单独拿出来说下:

    安装eslint依赖后,查看node_modules目录

    • extends字段指定的其实是一些(eslint内置规则的集合)+(rules指定的规则错误等级、规则的参数)。这个命名一般代表了最佳实践的eslint规则

      js
      "extends": "eslint:recommended",

      image-20221106202130343

    • 这个目录下可以看到每个eslint包内置的规则的实现

      eslint包内置的所有规则查阅:ESLint规则大全

      自动生成ESLint配置:ESLint生成

      image-20221106202332824

    rules字段:可以单独指定某条规则,且会覆盖extends中指定的规则集合中的同名规则

    plugins字段:从上面的截图中可以,eslint包内置了大量的规则,如果我们使用的是TS呢,eslint中内置的规则不足以应对。

    我们可以安装下面的插件,这个包中也带了大量的规则,这些规则是eslint包中

    shell
    npm install @typescript-eslint/eslint-plugin

    下图是@typescript-eslint/eslint-plugin中的规则

    image-20221106203359481

    下图是@typescript-eslint/eslint-plugin中导出的规则集合

    image-20221106203601786

    那么,如何使用插件呢?

    添加到plugins字段,使用rules指定启用的规则:

    js
    "plugins":['@typescript-eslint/eslint-plugin'], //可省略写成:@typescript-eslint'
    "rules": {
      "@typescript-eslint/no-inferrable-types":["error"] //这个规则就是插件中的规则。格式:插件名/规则名,插件名@typescript-eslint/eslint-plugin需要省略为@typescript-eslint
    }

    使用extend指定 (@typescript-eslint/recommended就是这个包里推荐的一些插件规则+启用的插件中的规则,等于上面的两个字段)

    js
    "extends":[
      "plugin:@typescript-eslint/recommended"
    ]

工作原理

ESLint 的底层要素是 语法树(AST) 和 规则(Rules)。ESLint 的内部工作步骤可以概括为:

  • ESLint 通过解析器(parser,ESLint默认使用的解析器是espress)将源代码解析成语法树(AST)

  • 深度遍历 AST,遍历到节点和路径时触发特定的钩子

  • Rule 在钩子上挂载检测逻辑;执行检测逻辑时发现当前语法不符合规范,直接向 ESLint 上报错误信息。

常用ESLint插件

支持vue文件中js的检查

shell
npm install -d eslint-plugin-vue

eslint配置文件配置

js
extends: [
    'plugin:vue/essential',// 识别vue语法,并提供vue默认校验规则
],

支持TS文件

shell
npm install typescript  @typescript-eslint/parser @typescript-eslint/eslint-plugin
  • @typescript-eslint/parser :TS的解析器
  • @typescript-eslint/eslint-plugin :定义了大量TS规则的插件
js
module.exports = {
  //插件
  "plugins":['@typescript-eslint/eslint-plugin'],
  
  //插件中的带的规则集合
	"extends": ["eslint:recommended","plugin:@typescript-eslint/recommended"],
  
  //解析器
  "parser":"@typescript-eslint/parser",
}

可以看到webstorm提示的eslint校验错误,这个规则就是@typescript-eslint/eslint-plugin中的

image-20221106205820231

自定义ESlint插件

B站视频课程课程代码

自定义插件

自定义规则

插件的命名格式为 eslint-plugin-<plugin-name> 的 npm 模块,比如 eslint-plugin-jquery。你也可以用这样的格式 @<scope>/eslint-plugin-<plugin-name> 限定在包作用域下,比如 @jquery/eslint-plugin-jquery

自定义插件关键是自定义其中的规则、规则集合

安装生产ESlint结构的脚手(generator-eslint

shell
sudo npm install -g yo generator-eslint

初始化项目模板

shell
yo eslint:plugin

image-20221107215048755

image-20221107214920903

生成自定义的规则模板

shell
yo eslint:rule

image-20221107215141506

可以看到从刚才的基础上,多了docs目录还有其中的no-var.mdno-var.js等文件

image-20221113115011768

定义no-var规则在lib/rules/no-var.js文件中,如下是该格式

image-20221107223344214

规则文件的字段含义、内置的参数的使用方法:https://eslint.bootcss.com/docs/developer-guide/working-with-rules

简单案例:hlint插件中的定义了no-var规则,代码详见下面地址:

https://gitee.com/hyj1270433876/example-learn/tree/master/customRuler

代码结构:

image-20221113112528264

eslint-usage项目中的提示:

image-20221113112758860

补充下pnpm:

packages下的eslint-plugin-hlint的文件夹是自定义的插件。如何让eslint-usage文件夹下的项目使用呢?使用下面的命令,就会把命令安装到了顶层目录customRuler下的node_modules下,eslint-usage就可以使用插件了

shell
pnpm install eslint-plugin-hlint@workspace -w

第三方

腾讯 AlloyTeam 团队出品的 eslint-config-alloy 开源规范库

工作流自动化集成

Git Hooks

Git预先定义了一些事件钩子,如commit-msgpre-commit等,当我们执行对应的Git操作时会触发它们,然后项目根目录下的.git/hooks 目录中对应的脚本就会执行,如图所示:

image-20220323191501634

默认情况下,这里shell脚本都是.sample结尾的,所以我们执行对应的Git操作时,并不会触发对应的脚本执行。我们可以将.sample结尾去掉,就会触发执行,其中的shell脚本了。同时,我们可以编写shell脚本,就能让Git触发勾子事件时,按照我们要求去执行任务了

但前端工程师大多对linux/windows shell并不擅长, 因此我们通过编写git hooks脚本来优化前端工作流的这条道路十分艰难。但是,Nodejs的出现改变了这一切,它让JS拥有了控制“操作系统”的能力,你只需要安装npm包husky,它会帮我们自动生成.git/hooks目录下的shell script,我们便可以很轻松的使用更熟悉的JS处理git hooks任务,而无需关注shell脚本的实现细节

图中,pre-commit文件之所以,没有.sample结尾,就是我安装了husky包,然后在package中配置触发的任务后,husky自动帮我生成脚本放入其中,并去掉.sample

husky旧版本

安装husky

shell
npm install -D husky@3.1.0

package.json中配置husky

json
"scripts": {
    "test": "node test.js"
},
"husky": {
    "hooks": {
      // 可以执行一个js文件,将控制权转移给我们更熟悉的nodejs
      "pre-commit": "node test.js", 
      // 也可以调用其他脚本或者执行一段原生shell命令
      "commit-msg": "npm run test && echo succeed" 
      
    }
}

常用下面的方式集成钩子

json
"husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
      "pre-commit": "lint-staged"
    }
  },

husky新版本

新版本引入破坏性变动,使用方式和旧版本有较大出入

新版不在使用默认的.git/hooks目录存储脚本,而是指定了项目内的文件夹为脚本目录

安装husky

shell
npm install -D husky

package.json中添加

prepare脚本会在npm install(不带参数)之后自动执行

当我们执行npm install安装完项目依赖后会执行 husky install命令,该命令会在当前目录创建.husky/目录并指定该目录为git hooks所在的目录。【默认git hooks目录在.git/hooks下,这个目录是不会被提交到仓库的】

如果不添加为prepare脚本,即使.husky文件夹被提交到git仓库,其他人在clone项目后,本地的git不会将Git钩子的目录指定为项目中的.husky目录

image-20220324180608409

json
//手动在package.json中添加
{
  "scripts": {
    "prepare": "husky install"
  }
}

//使用npm命令添加
npm set-script prepare "husky install"

添加git hooks

husky add:第一个参数是在.husky目录下新建的文件名,第二个参数是文件中的写入的脚本

在.husky目录下新建pre-commit脚本,

shell
npx husky add .husky/pre-commit "npx lint-staged"

image-20220327171214174

在.husky目录下新建commit-msg脚本

shell
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
#--no-install 参数表示强制npx使用项目中node_modules目录中的commitlint包

image-20220327171056231

这里提到的,在脚本中添加的几个命令,会在后面提到

lint-staged

Git Hooks可以让我们在提交流程中触发自定义操作,完成各种工作的自动化集成。

通常情况下,我们只需要对自己的本次提交变更的代码,进行各种校验或修复

lint-staged就能完成这样的任务,可以让我们的操作只针对于暂存区的代码

安装

shell
npm install -D lint-staged

配置

基本格式

"lint-staged": {
    "文件格式": [
      "命令1",
      "命令2",
      "...其他命令"
    ]
}

例子:对暂存区中的js、jsx、vue文件,使用eslint修复命令。因为eslint修复后,代码可能会出现变化,这些可能出现的变化放自动放入到暂存区

json
"lint-staged": {
    "*.{js,jsx,vue}": [
      "eslint --fix --ext .js app/",
    ]
}

集成commitlint

规范化提交,更便于在仓库中查找某次提交

可以直接用规范化的commit message生成change log

commitlint官方网站

  • 安装

    • @commitlint/cli 是commitlint提供的命令行工具,安装后会将cli脚本放置在./node_modules/.bin/目录下

    • @commitlint/config-conventional是社区中一些共享的配置,我们可以扩展这些配置,也可以不安装这个包自定义配置

      shell
      npm install -D @commitlint/cli 
      npm install -D @commitlint/config-conventional
  • 提交规范

    commit message 由 header(必须) 、body(可选)、footer(可选)

    text
    <type>[scope]: <subject>
    [body]
    [footer]
    • header

      text
      <type>[scope]: <subject>

      type:表示提交的类型,@commitlint/config-conventional中包含的可选值有

      text
      feat: 新功能
      
      fix: bug 修复
      
      docs: 仅修改文档
      
      style: 修改格式(空格,格式化,省略分号等),对代码运行没有影响
      
      refactor: 重构(既不是修 bug ,也不是加功能)
      
      build: 构建流程、外部依赖变更,比如升级 npm 包、修改 webpack 配置等
      
      perf: 性能优化
      
      test: 测试相关
      
      chore: 对构建过程或辅助工具和库(如文档生成)的更改
      
      ci: ci 相关的更改
      
      revert: 当前提交是为了撤销之前的某次提交,应该用 revert 开头,后面加上被撤销的提交的 header,在 body 中应该注明:This reverts commit <hash>. ,hash 指的就是将要被撤销的 commit SHA 
      // 例如
      revert: feat(user): add user type
      This reverts commit ca16a365467e17915f0273392f4a13331b17617d.

      scope:表示本次提交代码的影响的范围

      subject:表示对本次提交代码的简短描述

    • body

      body 部分是对本地 commit 的详细描述,可以分成多行

    • footer

      基本用在这两种情况:

      • 不兼容的改动( Breaking Changes ),通常用 BREAKING CHANGE: 开头,后面跟一个空格或两个换行符。剩余的部分就是用来说明这个变动的信息和迁移方法等。

        shell
        refactor: 
        BREAKING CHANGE:某某发生了更改
            按照下面的例子迁移代码:
            Before:
            scope: {
              myAttr: 'attribute',
              myBind: 'bind',
              myExpression: 'expression'
            }
            After:
            scope: {
              myAttr: '@',
              myBind: '@',
              myExpression: '&'
            }
            某某发生了更改
      • 关闭 Issue(Closes #Issue号)

        shell
        fix: 修复用户登陆注册
        Closes #2314, #3421
  • 初始化@commitlint/cli的配置文件

    项目根目录下,创建commitlint.config.js文件,也可以是.commitlintrc.js

    官网给出的配置文件完整的格式

    js
    module.exports = {
      /*
       * Resolve and load @commitlint/config-conventional from node_modules.
       * Referenced packages must be installed
       */
      extends: ['@commitlint/config-conventional'],
      /*
       * Resolve and load conventional-changelog-atom from node_modules.
       * Referenced packages must be installed
       */
      parserPreset: 'conventional-changelog-atom',
      /*
       * Resolve and load @commitlint/format from node_modules.
       * Referenced package must be installed
       */
      formatter: '@commitlint/format',
      /*
       * Any rules defined here will override rules from @commitlint/config-conventional
       */
      rules: {
        'type-enum': [2, 'always', ['foo']],
      },
      /*
       * Functions that return true if commitlint should ignore the given message.
       */
      ignores: [(commit) => commit === ''],
      /*
       * Whether commitlint uses the default ignore rules.
       */
      defaultIgnores: true,
      /*
       * Custom URL to show upon failure
       */
      helpUrl:
        'https://github.com/conventional-changelog/commitlint/#what-is-commitlint',
      /*
       * Custom prompt configs
       */
      prompt: {
        messages: {},
        questions: {
          type: {
            description: 'please input type:',
          },
        },
      },
    };

    通常我们使用第一步安装的第三方配置就可以了

    js
    /*使用第一步安装的第三方配置*/
    module.exports = {
        extends: ['@commitlint/config-conventional'],
    }

    如果想要自定义一些配置

    js
    module.exports = {
        extends: ['@commitlint/config-conventional'],
      	/*可以在下面,继续写其他字段的配置,这些配置会覆盖@commitlint/config-conventional中对应的配置*/
    }

    比如Rules,按照官网的Rules字段配置,这里我们讲下配置的格式

    text
    '规则名':[Level,Applicable,Value]
    
    //规则名:从官网查到所有的规则名的第一部分都是commit message的不同部分,例如:header-* 、scope-* 、type-*,表示规则作用的部分
    //Level : 错误提示等级,0是关闭提示,1是警告提示,2是错误提示
    //Applicable : always启用规则,never关闭规则
    //Value : 有些规则需要传递参数,在这里传递,比如 'header-max-length': [2, 'always', 72] 表示 header最长72

    例子:覆盖@commitlint/config-conventional中的rules字段

    js
    /**
     * feature:新功能
     * update:更新某功能
     * fixbug:修补某功能的bug
     * refactor:重构某个功能
     * optimize: 优化构建工具或运行时性能
     * style:仅样式改动
     * docs:仅文档新增/改动
     * chore:构建过程或辅助工具的变动
     */
    module.exports = {
        extends: ['@commitlint/config-conventional'],
      	
      	/*自定义配置,会覆盖@commitlint/config-conventional中的配置*/
        rules: {
          	'header-max-length': [2, 'never', 72], // header 最长72
          
            'body-leading-blank': [2, 'always'], // body换行
            
          	//type的枚举字段,提交时的type值,只能是这里的值,@commitlint/config-conventional中的可选值全部被覆盖了
            'type-enum': [2, 'always', ['feature', 'update', 'fixbug', 'refactor', 'optimize', 'style', 'docs', 'chore']],
        }
    }
  • 添加到Git钩子中

    旧版husky

    json
    //package.json文件中
    "husky": {
        "hooks": {
          "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 
        }
    }

    新版husky(参照上面Git Hooks章节的使用)

    shell
    npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
    #--no-install 参数表示强制npx使用项目中node_modules目录中的commitlint包
  • lint-staged

    这里仅仅是校验commit message,不是暂存区代码,所以不必使用lint-staged

  • 提交

    image-20220328142551798

  • 编写commit message的辅助工具

    commitzen是一款工具,可以通过在终端选择的方式,帮助我们编写合格的commit message

    shell
    npm install -D commitizen

    让commitzen其支持 Angular 的 Commit message 格式

    shell
    commitizen init cz-conventional-changelog --save-exact

    查看package.json,就会多出一句

    json
    "config": {
    	"commitizen": {
    		"path": "./node_modules/cz-conventional-changelog"
       }
    }

    以后,凡是用到git commit命令,一律改为使用git cz。这时,就会出现选项

    image-20220329203304247

集成Changelog

如果你的所有 Commit 都符合 Angular 格式,那么发布新版本时, Change log 就可以用脚本自动生成

生成的文档包括以下三个部分。

  • New features
  • Bug fixes
  • Breaking changes.

每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容

shell
npm install -D conventional-changelog-cli

生成CHANGELOG.md文件

shell
conventional-changelog -p angular -i CHANGELOG.md -w #命令不会覆盖以前的 Change log,只会在CHANGELOG.md的头部加上自从上次发布以来的变动

conventional-changelog -p angular -i CHANGELOG.md -w -r 0 #生成所有的 Change log,要改为运行下面的命令

文件的格式大概是下面这个样子

image-20220329210029744

集成到package.json的脚本中

json
scripts: {
   "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md"
    }

集成Prettier

一般情况下,我们并不会把Prettier集成到自动化流程中

因为,如果我们对项目中其他人的页面进行修改,在提交时自动触发Prettier格式化,可能会将页面中其他人的代码格式化,这样在提交记录上来看,其他人的代码,变成了自己提交的代码

  • 安装

    shell
    npm install -D prettier
  • 根目录下新建配置文件prettierrc

    json
    {
        "printWidth": 80, 
        "tabWidth": 2, 
        "useTabs": false, 
        "semi": true,
        "singleQuote": false, 
        "bracketSpacing": true, 
        "bracketSameLine": true, 
        "endOfLine": "lf"
    }
  • package.json中配置

    这里仅仅是暂存区的文件需要进行Prettier格式化,所以使用了lint-staged

    json
    {
    	 "scripts": {
        "prettier": "prettier --write"
      },
      
      "lint-staged": {
        "*.{js,vue}": [
          "npm run prettier",
          "git add"
        ]
      }
    }
  • 添加Git Hooks

    shell
    npx husky add .husky/pre-commit "npx lint-staged"

Git官网介绍了,所有的Git勾子的详细信息

流程:

  • Git Hooks在Git提交的某个阶段触发的勾子
  • 勾子中使用lint-staged,使得格式化工具只作用于暂存区代码

自动化,只会用到提交工作流钩子,提交工作流包含 4 个钩子:

flow
st=>start: git commit -m "提交文本"
op1=>operation: pre-commit
op2=>operation: prepare-commit-msg
op3=>operation: commit-msg
op4=>operation: post-commit
e=>end: 提交完成
st->op1->op2->op3->op4
op4->e
  • pre-commit 钩子在键入提交信息前运行,在这个阶段加入 代码检查 流程,会代码

  • prepare-commit-msg 钩子在启动提交信息编辑器之前,默认信息被创建之后运行。它对一般的提交来说并没有什么用;然而对那些会自动产生默认信息的提交,如提交信息模板、合并提交、压缩提交和修订提交等非常实用。 你可以结合提交模板来使用它,动态地插入信息「可在这个阶段加载 commitizen 之类的辅助填写工具」

  • commit-msg 钩子在即将提交前运行,勾子接收一个参数,即存有当前提交信息的临时文件的路径,可在这个阶段借助 commitlint 进行提交信息规范性检查;

  • post-commit 钩子在整个提交过程完成后运行,它不接收任何参数,在这个阶段一般做一些通知操作。

使用 Git 钩子最直观的方式是操作 .git/hooks 下的示例文件,将对应钩子文件的 .sample 后缀名移除即可启用。然而这种操作方式存在弊端:

  1. 需要操作项目范围外的 .git 目录(有系统级别、全局级别的.git配置文件)
  2. 无法同步 .git/hooks 到远程仓库(.git是本地的git配置文件,不会被提交)

可以将Git勾子的目录设置在项目的根目录下

shell
# 指定 Git hooksPath 为根目录下的 .githooks 目录(原来是 .git/hooks 下的文件 )
git config core.hooksPath .githooks

安装husky

shell
npm install -d husky

安装lint-staged

shell
npm install -d lint-staged

在package.json

json
//在hooks中可以定有Git勾子
"husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": ""
    }
},

//针对暂存区进行操作
"lint-staged": {
  	//指定 什么类型的文件:["执行命令1","执行的命令2"]
  	//一般把命令放在script字段里,这里直接调用其中的命令
  	//最后以一个命令是git add ,将前面命令做的代码变更重新加到暂存区
    "**/*.{js,vue}":[
      "npm run lint",
      "npm run prettier",
      "git add" 
    ]
},

//
"scripts": {
    "dev": "xxxxx",
    "build": "xxxxx",
  	//eslint修复 --fix是自动修复
    "lint-fix": "eslint --fix --ext .js app/",
  	//eslint --ext指定文件类型和目录(支持glob方式)
    "lint": "eslint --ext .js app/",
  
  	//prettier
  	"prettier":"prettier --write",
  
  	//
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
},

待补充

其他配置文件

.gitignore

.gitignore
#mac系统下,记录文件夹位置的文件
.DS_Store

#依赖安装目录
node_modules

#打包路径
/dist

# local env files
.env.local
.env.*.local

# 日志文件
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# 编辑器配置文件
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

总结

EditorConfig 作用于预览和输入阶段,Prettier 在保存和提交阶段重新组织代码,Prettier 会成为代码形态的最终决定者

参考

深入理解 ESLint

Eslint中plugins和extends的区别

ESLint中文网

前端代码规范化:EditorConfig + Prettier + ESLint

让你的 commit 更有价值(规范)

Commit message 和 Change log 编写指南——阮一峰

最后更新时间:

Released under the MIT License.