使用 ESlint+stylelint+prettier 对前端项目代码进行规范
说明:该规范主要针对的是使用的是 react+typescript+tsx 框架的代码进行相关规范
目录
- 项目初始化
- 添加eslint相关配置及规范约束
- 添加prettiter 项目配置及约束
- 添加stylelint相关配置及约束
- 设置git 代码提交检查及eslint修复命令配置
- 设置只对当前修改过的文件进行规范验证,并提示错误信息
- git 常见问题,及解决方式
- 编辑器规范统一配置
- 设置常用编辑器对eslint及stylelint 的格式化修复
1. 项目初始化
- 创建一个项目文件夹 eslint-stylelint-prettier 文件夹
- 在项目文件夹下运行 npm init -y 初始化项目将会自动生成package.json项目包依赖及其他相关配置的文件
- 创建eslint配置文件 .eslintrc.js,eslint的配置文件也可以是.eslintrc没有.js后缀的一个json格式的配置文件
- 创建eslint忽略文件的配置文件.eslintignore用于过滤掉不需要进行eslint校验的文件
- 创建stylelint配置文件.stylelintrc.js文件也可以是没有有.js后缀的.stylelintrc的json格式的配置文件
- 创建stylelint忽略文件的配置文件.stylelintignore用于过滤掉不需要进行stylelint校验的文件
- 创建prettier配置文件.prettierrc.js也可以是没有js后缀名的json格式配置文件
- 创建编辑器默认配置文件.editorconfig
- 创建git仓库管理忽略配置文件.gitignore
- 创建README.md 项目说明文件
- 创建src项目资源目录
注意:不要漏了文件名之前的点,之所以使用js文件名作为配置是为了复用代码
项目目录结构如下
eslint-stylelint-prettier | —— src // 项目代码存放文件夹 | —— .editorconfig // 编辑器配置文件 | —— .eslintignore // eslint忽略配置文件 | —— .eslintrc.js // eslint配置文件 | —— .gitignore // git忽略配置文件 | —— .prettierrc.js // prettiter配置文件 | —— .stylelintignore // stylelint忽略配置文件 | —— .stylelintrc.js // stylelint配置文件 | —— package.json // 项目包依赖及其他相关配置文件 | —— README.md // readme文件
2. 添加eslint相关配置及规范约束
- 打开eslint的的配置文件.eslintrc.js文件
- 编写以下配置
module.exports = { env: {}, extends: [], plugins: [], parse: '' parserOptions: {}, globals: {}, rules: {}, settings: {} }
配置说明:
- env 配置用于规定一个环境定义了一组预定义的全局变量,可配置的属性值参考地址
- extends 配置表示继承其他模块相关的eslint 配置, 可配置的属性方式参考地址
- plugin 配置表示以插件的模式进行复用第三方的eslint配置依赖包,可配置的属性值方式参考地址
- parserOptions 配置当前JavaScript语言的支持环境,默认是 ECMAScript 5 语法。该配置可以覆盖原有配置,以启用对 ECMAScript 其它版本和 JSX 的支持.属性值方式参考地址
- parse 配置eslint的解析器
- globals 配置用于添加该环境下的自定义的全局变量的变量名以防止eslint 报错,属性值配置方式参考地址
- rules 配置自定义eslint规则覆盖或者关闭原有相关配置,属性值配置方式参考地址
- settings 配置文件添加共享设置,或者自定义规则而且使它们可以访问到相同的信息, 配置产考地址
env配置选项编写:
env: { browser: true, // 浏览器环境 node: true, // node环境 es6: true, // es6 环境 },
extends配置选项编写:
extends: [ 'airbnb', 'airbnb/hooks', 'plugin:@typescript-eslint/recommended','plugin:jsdoc/recommended',
'prettier' ],
第一个 airbnb 表示继承该库的相关的eslint规则, 是一个比较通用且受欢迎的一个eslint 规范库, 使用该库需要安装以上的一些依赖,关于Airbnb的详细了解及保护规则可以直接查看npm包地址或者github仓库源码地址,需要安装一下这些依赖来支持Airbnb。
第二个 airbnb/hooks 表示使用该库的react/hooks 规范
说明: 我安装的是作为项目开发依赖是因为我是打算将该项目作为一个eslint 规范相关的公共包依赖,如果是直接在某个现有项目中使用请安装作为开发依赖 也就是 --save-dev
- npm install eslint --save
- npm install eslint-config-airbnb --save
- npm install eslint-plugin-import --save
- npm install eslint-plugin-react --save
- npm install eslint-plugin-jsx-a11y --save
-
npm install eslint-plugin-react-hooks --save
第三个@typescript-eslint/eslint-plugin 配置是用于规范Typescript , 需要进行安装以下依赖。需要查看详细规则的可以查看npm包地址
- npm install @typescript-eslint/eslint-plugin
- npm install typescript --save
第四个是 prettier 配置,需要安装以下依赖
- npm install prettier --save
- npm install eslint-config-prettier --save
- npm install eslint-plugin-prettier --save 用于插件配置
最后一个是js注释相关规范的,需要安装以下依赖
- npm install eslint-plugin-jsdoc --save
plugin配置选项编写:
plugins: [ 'jsdoc', 'react', 'jsx-a11y', 'import', 'prettier', '@typescript-eslint' ],
插件配置与上面extends配置基本差不多一样,
注意 jsx-a11y 中 a11y 是1234 的数字1 而不是字母 l, 一开始我写错误了导致错误 Error: Failed to load plugin 'jsx-ally' declared in '.eslintrc.js': Cannot find module 'eslint-plugin-jsx-ally'
parserOptions配置选项编写:
parserOptions: { node: true, ecmaVersion: 11, sourceType: 'module', ecmaFeatures: { jsx: true } },
上面的配置选项在配置选项地址有说明的非常清楚:https://eslint.bootcss.com/docs/user-guide/configuring#specifying-parser-options
添加 parse 选项配置用于规定eslint使用的解析器:
安装依赖:npm install @typescript-eslint/parser --save
parser: '@typescript-eslint/parser', // 定义ESLint的解析器
由于我所使用的项目是 typescript,所以选择了typescript解析器
添加globls选项配置,该配置因项目而异,并不是固定的,每个项目都可以不一样
globals: { it: 'writable', Context: 'writable', Next: 'writable', wx: 'readonly', },
需要注意的是该配置可以定义该全局变量是否可以修改或者是只读
rules选项配置:
rules: { // https://eslint.bootcss.com/docs/rules/ 基本规则参考文档地址 'no-console': 'off', // 允许使用 console radix: 'off', // parseInt方法不强制使用第二个参数 'linebreak-style': ['error', 'unix'], // 强制使用Linux的LF换行符 'guard-for-in': 'off', // 关闭要求 for-in 循环中有一个 if 语句 'no-return-await': 'off', // 允许直接返回 await 结果 'prefer-promise-reject-errors': 'off', // 不求使用 Error 对象作为 Promise 拒绝的原因 'no-continue': 'off', // 允许使用 continue 'spaced-comment': ['error', 'always'], // 注释必须有空格 'no-restricted-syntax': [ // 不允许使用的语法 'error', { selector: 'ForOfStatement', message: '不允许使用 for of 语法', }, { selector: 'LabeledStatement', message: 'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.', }, { selector: 'WithStatement', message: '不允许使用 with 语法', }, ], 'new-cap': 'error', // 函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用 camelcase: [ 'warn', { // 强制使用骆驼拼写法命名约定 properties: 'always', }, ], 'max-params': ['error', 4], // 函数最多四个参数 'no-underscore-dangle': 'off', // 标识符可以_开头或结尾 'no-nested-ternary': 'error', // 禁止使用嵌套的三元表达式,避免代码难以理解 'no-useless-constructor': 'error', // 关闭禁止不必要的构造函数 'no-plusplus': 'off', // 关闭禁止使用++,-- 'no-unreachable': 'error', // 禁止有不能执行的代码 'no-control-regex': 'off', // 关闭禁止在正则表达式中使用控制字符 'class-methods-use-this': 'off', // 关闭强制类方法使用 this 'no-use-before-define': 'off', // 关闭未定义前不能使用 'no-shadow': 'error', // 关闭外部作用域中的变量不能与它所包含的作用域中的变量或参数同名 'no-extra-semi': 'error', // 禁止多余的分号 eqeqeq: ['error', 'always'], // 要求使用 === 和 !== 'jsx-quotes': ['error', 'prefer-double'], // 强制在 JSX 属性中一致地使用双引号 // 相关文档地址:https://www.npmjs.com/package/eslint-plugin-react reactEsllint配置参考地址 'react/no-multi-comp': [ 'error', { // 禁止单个文件有多个组件定义, 允许多个无状态组件 ignoreStateless: true, }, ], 'react/no-array-index-key': 'warn', // 禁止使用数据索引作为元素的key值 'react/jsx-pascal-case': ['error'], // 为用户定义的 JSX 组件强制使用 PascalCase 'react/no-unknown-property': [ 'error', { // 禁止使用未知的DOM属性 ignore: ['crossOrigin'], }, ], 'react/jsx-filename-extension': [ 'error', { // 限制可能包含JSX的文件扩展名 extensions: ['.tsx', '.jsx', '.js'], }, ], 'react/prop-types': 'error', // 防止React组件定义中缺少道具验证 'react/static-property-placement': 'off', // 不限制静态属性书写位置 'react/destructuring-assignment': 'off', // 关闭执行支持、状态和上下文的解构赋值的一致使用, 'react/prefer-stateless-function': 'off', // 关闭强制将无状态组件编写为纯函数, // 相关文档地址:https://www.npmjs.com/package/eslint-plugin-import 'import/no-unresolved': [ 'error', { // 没有找到对应模块不报错 ignore: ['(png|jpg|jpeg|gif|svg)$'], }, ], 'import/extensions': [ // 允许导入的文件省略后缀 'error', 'ignorePackages', { js: 'never', mjs: 'never', jsx: 'never', ts: 'never', tsx: 'never', }, ], 'import/prefer-default-export': 'off', // 关闭单个导出时必须使用默认导出 // 相关文档地址:https://www.npmjs.com/package/eslint-plugin-jsx-a11y 'jsx-a11y/alt-text': 'error', // 强制要求可选文本的所有元素都具有有意义的信息,以便传回给最终用户。 'jsx-a11y/click-events-have-key-events': 'off', // 关闭强制一个可单击的非交互元素至少有一个键盘事件监听器。 'jsx-a11y/no-static-element-interactions': 'off', // 关闭强制要求有交互操作的静态标签设置role属性 'jsx-a11y/no-noninteractive-element-interactions': 'off', // 关闭强制要求非交互语义标签(main,hX,ul,ol,liarea)不包含交互事件(onClick等) // 相关文档地址:https://www.npmjs.com/package/@typescript-eslint/eslint-plugin '@typescript-eslint/no-unused-vars': 'error', // 不允许未使用的变量 '@typescript-eslint/explicit-member-accessibility': 'off', // 关闭要求类属性和方法上的显式可访问性修饰符 '@typescript-eslint/no-object-literal-type-assertion': 'off', // 关闭禁止对象字面值出现在类型断言表达式中(来自TSLint的no-object-literal-type-assertion) '@typescript-eslint/explicit-function-return-type': 'off', // 关闭要求函数和类方法的显式返回类型 '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', // 关闭在导出的函数和类的公共类方法上要求显式的返回和参数类型 '@typescript-eslint/no-use-before-define': ['error'], // 禁止在定义变量之前使用变量 '@typescript-eslint/no-shadow': ['error'], // 禁止变量声明隐藏在外部作用域中声明的变量 '@typescript-eslint/no-var-requires': 0, // 除了在import语句中,禁止使用require语句 // 注释规则 https://www.npmjs.com/package/eslint-plugin-jsdoc 'jsdoc/require-jsdoc': [ 'error', { contexts: [ // 排除一些常用声明周期函数 'MethodDefinition:not([key.name="componentDidMount"]):not([key.name="render"]):not([key.name="constructor"]):not([key.name="componentDidUpdate"]):not([key.name="shouldComponentUpdate"])', ], require: { FunctionDeclaration: true, ClassDeclaration: true, // 类及其方法注释 ArrowFunctionExpression: true, // 箭头函数也需要注释 ClassExpression: true, FunctionExpression: true, // 普通函数注释 }, }, ], 'jsdoc/check-tag-names': [ 'error', { // 防止与 prettier 冲突 definedTags: ['format'], }, ], 'jsdoc/require-param': 'error', 'jsdoc/require-param-description': 'error', // 函数参数描述 'jsdoc/require-param-name': 'error', // 参数名字 'jsdoc/require-param-type': 'error', // 函数的类型 'jsdoc/require-returns': 'error', // 函数的返回值 'jsdoc/require-description': 'error', // 所有功能都要有描述 'prettier/prettier': ['error'], // 应用 prettier },
setting选项配置:
settings: { 'import/resolver': { node: { extensions: ['.js', '.ts', '.jsx', '.tsx', '.json'], }, }, 'import/extensions': ['.js', '.ts', '.mjs', '.jsx', '.tsx'], jsdoc: { structuredTags: { format: { type: false, }, }, }, }
在这里我展示出当前我所使用的依赖的种类及包的版本,防止以后更新出现版本之间的不兼容错误,
"dependencies": { "@typescript-eslint/eslint-plugin": "^4.31.0", "@typescript-eslint/parser": "^4.31.0", "eslint": "^7.32.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.24.2", "eslint-plugin-jsdoc": "^36.1.0", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-react": "^7.25.1", "eslint-plugin-react-hooks": "^4.2.0", "prettier": "^2.4.0", "typescript": "^4.4.2" }
到此就已经配置完成 eslint的配置,然后我们进行简单的测试一下看eslint 的规则效果是否生效
如果你使用的是webstorm 2020以上版本 你需要在设置里面开启eslint配置,可以选择自动或者手动,如下图所示,如果使用的是其他编辑器可自行百度查找也是非常容易找到
注意:如果出现eslint 为找到 或者其他等依赖为找到的话,可能是没有安装依赖,或者是可能没有及时加载依赖,可以选择下载依赖或者重新启动编辑器让其生效
在src文件夹下创建一个index.js 文件,编写一些代码,发现编辑器有明显的错误提示,这些提示都是eslint 的提示,你可以使用鼠标右键修复eslint,但是也是只能修复一部分代码,有些还是需要自己补充上去
鼠标右键修复后的效果
可以发现任然存在一些eslint 错误无法自动修复,这个时候我们需要进行手动的修复,修复之后的代码如下,发现没有出现一个错误提示信息了
3. 添加prettiter 项目配置及约束
其实我们在配置eslint 的时候就已经开启了prettier 的代码校验了,只是我们没有进行相关配置 使用的是默认的配置。现在打开.prettierrc.js 配置文件进行添加相关配置,prettier的配置项相对eslint 而言要少很多。
详细配置可参考prettier官网
module.exports = { printWidth: 120, // 一行的最大字符数 semi: true, // 是否使用分号 singleQuote: true, // 是否使用单引号 trailingComma: 'all', // 末尾逗号在可能的地方都加上逗号 bracketSpacing: true, // 字面量对象括号中的空格开始和结束不需要 jsxBracketSameLine: true, // jsx元素结束放在最后一行结束 arrowParens: 'always', // 箭头函数中的括号在需要的时候添加 insertPragma: true, // 添加头注释 @format 表示已经被prettier格式化过 tabWidth: 2, // tab宽度 useTabs: true, // 使用tab缩进 eslintIntegration: true, // eslint 规则优先防止冲突 };
配置完毕之后进行简单的测试,由于是新增的prettier规则需要重新启动项目或者重新启动编辑器才能够使之生效
经过自动修复之后会在文件的头部添加一个 /** @format */ 字样的注释,表示你的prettier配置已经生效,需要注意的是,在每次进行修改prettier配置的时候都需要重新启动项目或者编辑器才能使新的prettier配置生效,我第一次修改配置的时候还以为是自己配置错误了,找了半天也不知道为什么配置不生效,而是在第二天来看项目的时候配置才看到生效,所以才知道是需要重新启动项目才能生效
到此就完成了prettier的配置
4. 添加stylelint相关配置及约束
打开.stylelintrc.js 文件进行书写stylelint 的相关配置, 编写如下代码
module.exports = { extends: ['stylelint-config-prettier', 'stylelint-config-recess-order', 'stylelint-config-standard'], plugins: ['stylelint-prettier', 'stylelint-order'], rules: { indentation: 2, 'order/properties-order': ['never'], 'max-nesting-depth': 4, }, };
需要进行安装相关依赖,所需依赖如下
- npm install stylelint --save
- npm install stylelint-config-prettier --save
- npm install stylelint-config-prettier --save
- npm install stylelint-config-standard --save
- npm install stylelint-config-recess-order --save
- npm install stylelint-order --save
- npm install stylelint-prettier --save
其中包含 css 样式书写顺序的规范以及缩进及一些常用的规范,具体的相关配置可产考stylelint官网
webstorm 2020 以上版本开启 stylelint 校验,默认可能是关闭的所有需要去设置里面搜索stylelint 进行勾选开启才能生效
开启配置之后再在src文件夹下新建一个css文件,进行相关的简单测试stylelint 会发现有stylelint 的报错提示则表示配置成功
进行stylelint 修复之后正常显示效果如下,修复之后就没有一处显示有错误的地方,有些stylelint 错误也是无法自动修复的,需要手动的去修复这些stylelint的错误
由于 webstorm没有自带修复stylelint 的功能,需要自己配置,配置方式如下
第一步,打开设置 --> 工具 --> 外部工具 --> 点击加号,效果如下图
点击加号之后会弹出配置选项弹框,编写如下配置即可,点击确定即可在鼠标右键看到 External Tool --> stylelint 点击就可以自动修复stylelint 错误
到此为止 stylelint 的相关配置也已经配置完毕
5. 设置git 代码提交检查及eslint修复命令配置
首先我们需要进行安装依赖
- npm install shelljs --save
- npm install husky --save
安装完成依赖之后,由于我使用的是新版本的 husky 与老版本的配置有所改变,进行了一番尝试才配置成功
第一步在 package.json 文件添加 script 脚本
"scripts": { "test": "echo "Error: no test specified" && exit 1", "prepare": "husky install", "checkEslint": "node checkEslint.js", "stylelintfix": "stylelint --config .stylelintrc.js **/*.{css,sass,scss,less} --fix", "lint": "eslint src koa --ext .js,.jsx,.ts,.tsx --cache --fix" },
说明:
- 第一个脚本自动生成的就不说了,
- 第二个脚本是用于 新版本 husky 配置的,在每次安装依赖的时候(npm install)就会自动执行该命令,会项目文件加下面生成一个.husky 文件夹
- 第三个脚本是用于git钩子在commit 提交代码时候进行代码校验的一个自定义脚本,等会会进行脚本的编写与说明
- 第四个脚本是用于自动修复项目下面的所有样式文件的 stylelint 规则 ,这个脚本不推荐使用,因为会修改项目下的所有文件
- 第五个脚本是用于自动修复项目下面的所有js、ts等文件的 eslint 规则,这个脚本也是会修改项目下面的所有文件
存在一个问题就是,我们现在只想对我们自己每次修改过的文件进行校验,而不想每次提交代码需要校验整个项目的所有文件,这个会导致修改文件过多,而且还会导致本不应该是你修改的文件导致你都进行了修改,一次性修改过多文件容易导致代码修改记录不好查找,那么我们指向对现有项目的修改过的文件进行相关的校验,我选择的是一个自己编写的简单脚本,来进行验证,在网上找了一些没有发现什么好用的,所以最后选择自己写
第二步 husky 脚本配置
找到项目下面的 一个 .husky 的文件夹下创建一个 名字叫per-commit 的脚本文件,如下图所示
在 pre-commit 脚本文件中编写如下脚本
#!/bin/sh . "$(dirname "$0")/_/husky.sh"
npm run checkEslint
说明: 表示在提交代码时候会自动触发 git 的钩子,会自动去运行配置的这个脚本文件 ,这个脚本文件会 运行 npm run checkEslint 自己编写的一个nodeJS 脚本
第三步:编写 checkEslint.js 脚本文件
/** @format */ const shell = require('shelljs'); let pass = 0; // 检查是否有安装 git if (!shell.which('git')) { shell.echo('Sorry, this script requires git'); shell.exit(1); } // 获取暂存区的所有文件名,过滤掉删除的文件 const res = shell.exec('git diff --cached --diff-filter=d --name-only'); // 筛选出需要的文件 const fileList = res.grep('.*.(js|jsx|ts|tsx|css|less|scss|sass)$').split(' '); const styleArr = [], scriptArr = []; // 将所有文件分为 样式文件和脚本文件 fileList.forEach(file => { if(/.(less|css|scss|sass)$/.test(file)){ styleArr.push(file); } if(/.(js|jsx|ts|tsx)$/.test(file)) { scriptArr.push(file); } }); // 如果有样式文件则进行 stylelint 校验 if(styleArr.length) { const script = styleArr.length === 1 ? styleArr.join() : `{${styleArr.join()}}`; const styleError = shell.exec(`stylelint --config .stylelintrc.js ${script}`); if(styleError.stdout) { pass = 1; } } // 如果有脚本文件则进行 eslint 校验 if(scriptArr.length) { const script = scriptArr.length === 1 ? scriptArr.join() : `{${scriptArr.join()}}`; const scriptError = shell.exec(`eslint --config .eslintrc.js ${script}`); if(scriptError.stdout) { pass = 1; } } console.log(styleArr, scriptArr); // 如果校验不通过则退出程序 if(pass) { shell.exit(1); }
这样就能够只校验当前修改过的文件,没有做修改的文件不会进行校验, 编写完成之后我们进行简单的测试, 我在项目的src文件夹下创建了几个样式文件和几个js文件
从图上我们可以看出,由于有几个文件的校验没有通过从而直接终止了该脚本的执行,从而阻止代码提交,那如果我们在某些时候不想要进行校验(绕过校验)那么我们可以这么做,使用一下命令就能绕过验证 直接提交代码
git commit -m 'test' --no-verify
6. 编辑器规范统一配置
打开项目文件夹下的 .editorconfig 添加如下代码
root = true [*] charset = utf-8 indent_style = tab indent_size = 2 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true
说明:表示应用于项目下的所有文件,编码格式为utf-8, 缩进方式为tab, 缩进大小为2,换行方式为 lf 换行,文件以一个空白行进行结尾, 去除一行尾部的多余的空格
注意:如果项目出现换行的问题,因为windows电脑和Mac 等电脑的换行方式不同可能导致换行冲突,window 默认使用的换行是 CTRL Mac电脑的换行符主要为 LF, 如果出现当你拉取代码出现,整个代码都是eslint错误,那么可以使用 改命令进行修改git的换行配置, 详细地址
git config --global core.autocrlf input
7. 代码整理及复用配置
项目的代码规范已经配置完成,但是还是无法很好的实现代码复用,也就是,当我有多个项目都想使用这一套代码规范时,就现在而言是只能通过复制粘贴到其他项目中去,这样就会存在一个问题,那么当使用的项目一多,我需要修改或者添加某个规则时,那么需要单独的去修改所有的项目配置。很明显我们并不想去这样修改,那么我们把这些代码规范整理成一个依赖包即可,我们进行一下代码的调整即可
将eslint的配置文件重新复制到在src目录下创建的一个index,js
将stylelint的配置重新复制到src目录下创建的一个stylelintConfig.js
将prettier的配置重新复制到scr目录下创建的一个prettierConfig.js
然后将配置文件修改为
.eslintrc.js
const eslintConfig = require('./src/index'); module.exports = eslintConfig;
.stylelintrc.js
const stylelintConfig = require('./src/stylelintConfig'); module.exports = stylelintConfig;
.prettierrc.js
const prettierConfig = require('./src/prettierConfig'); module.exports = prettierConfig;
如果是其他项目需要使用也就只需要安装该项目依赖,然后直接引入就能使用, 其他项目使用方式
1. 下载依赖 npm install eslint-stylelint-prettier -D
2. 然后直接在项目下 配置使用该依赖的文件即可复用代码,
{ "extends": "eslint-stylelint-prettier" }
此处遇到一个问题,暂未解决:出现加载失败的问题,正常一般是不会出现加载失败(Error: Failed to load config "eslint-stylelint-prettier" to extend from.),使用js配置文件进行加载又是可以。
github 地址:https://github.com/Liting1/eslint-stylelint-prettier
npmjs 地址:https://www.npmjs.com/package/eslint-stylelint-prettier