作者|Adeel Imran 译者|无明
想写出好代码, 却不知道从哪里开始? 想删除死代码? 想在代码库中找出未被使用的变量? 想在代码中找出有问题的模式?
你是多元化团队的负责人吗? 你的团队中有新来的开发人员吗? 你担心他们会写出不符合标准的代码吗? 在代码评审时是否花了一整天的时间去检查代码标准, 而不是实际的逻辑实现?
我一直在做这样的事情, 经常忙得像热锅上的蚂蚁. 但从现在开始, 我们要保证永远不再担心这类问题. 在阅读本文过程中, 如果遇到困难, 可以参考代码库(https://github.com/adeelibr/react-starter-kit).
本文更多地是针对 React 应用程序, 但同样适用于其他 web 项目.
让我们从 Prettier 开始吧 Prettier 是什么?
Prettier 是一种代码格式化程序, 它以特定的方式为你格式化代码.
请看这个 GIF:
我们为什么需要 Prettier?1. 清理现有代码库: 通过单个命令行清理代码库. 想象一下清理超过 20,000 行代码的代码库会是怎样的一种情景. 2. 易于适用: Prettier 在格式化代码时使用争议最少的编码风格. 因为是开源的, 很多人已经在修复一些边缘情况和优化体验方面进行了多次迭代. 3. 编写代码: 人们没有意识到的是, 他们花了很多时间用于格式化代码, 这浪费了他们太多的精神能量. 让 Prettier 来处理格式化的事情, 开发人员就可以专注在核心业务逻辑上. Prettier 可以将效率提高 10%.4. 帮助新手: 如果你是一位与优秀工程师并肩工作的新手, 并且你希望自己看起来很酷, 可以写出干净的代码, 那就使用 Prettier 吧. 如何设置 Prettier?
创建一个叫作 App 的文件夹, 进入该文件夹, 在命令行中敲入:
NPM init -y
这将在 App 文件夹中创建一个 package.JSON 文件.
我将在本文中使用 yarn, 但你也可以使用 NPM.
安装我们的第一个依赖项:
yarn add --dev prettier
这将安装 package.JSON 中指定的开发依赖项, 如下所示:
- {
- "name": "react-boiler-plate",
- "version": "1.0.0",
- "description": "A react boiler plate",
- "main": "src/index.js",
- "author": "Adeel Imran",
- "license": "MIT",
- "scripts": {
- "prettier": "prettier --write src/**/*.js"
- },
- "devDependencies": {
- "prettier": "^1.14.3"
- }
- }
稍后我会解释 "prettier": "prettier-write src/**/*.js" 的作用, 现在先让我们在 App 文件夹中创建一个 src/ 文件夹. 在 src/ 文件夹中, 再创建一个名为 index.JS 的文件 -- 名字可以随意起.
在 index.JS 文件中, 按原样粘贴这句话:
- let person = {
- name: "Yoda",
- designation: 'Jedi Master'
- };
- function trainJedi (jediWarrion) {
- if (jediWarrion.name === 'Yoda') {
- console.log('No need! already trained');
- }
- console.log(`Training ${jediWarrion.name} complete`)
- }
- trainJedi(person)
- trainJedi({ name: 'Adeel',
- designation: 'padawan'
- });
到目前为止, 我们有了一个 src/App/index.JS 文件, 包含了一些难看的代码.
我们可以做三件事:
手动缩进并格式化代码;
使用自动化工具;
保持不变(请不要这么做).
我打算选择第二项, 所以我们安装了一个依赖项, 并在 package.JSON 中声明了 Prettier.
现在在 App 根文件夹中创建一个 prettier.config.JS 文件, 并在其中添加一些 Prettier 规则:
- module.exports = {
- printWidth: 100,
- singleQuote: true,
- trailingComma: 'all',
- bracketSpacing: true,
- jsxBracketSameLine: false,
- tabWidth: 2,
- semi: true,
- };
printWidth 将确保你的单行代码不会超过 100 个字符.
singleQuote 会将所有双引号转换为单引号.
trailingComma 将确保在最后一个对象属性的末尾会有一个逗号.
bracketSpacing 在对象字面量之间打印空格:
- If bracketSpacing is true - Example: {
- foo: bar
- }
- If bracketSpacing is false - Example: {
- foo: bar
- }
jsxBracketSameLine 将在多行 JSX 元素的最后一行放置>:
- // true example
- <button
- className="prettier-class"
- id="prettier-id"
- onClick={this.handleClick}>
- Click Here
- </button>
- // false example
- <button
- className="prettier-class"
- id="prettier-id"
- onClick={this.handleClick}
- >
- Click Here
- </button>
tabWidth 指定单个缩进的空格数.
如果 semi 设置为 true, 将在语句末尾加上 ;.
现在让我们来说说这个脚本的作用:
"prettier": "prettier - write src/**/*.js"
它的意思是运行 prettier, 并让它在 src/ 文件夹中查找所有的. JS 文件.--write 标志告诉 prettier 要把格式化好的内容保存到文件中, 并找出格式化过程中发现的任何异常.
现在在终端中运行这个脚本:
yarn prettier
这是我在运行代码时看到的:
ESLint 什么是代码 linter?
代码 linting 是一种代码静态分析, 通常被用于查找不符合某些样式指南的有问题的模式或代码. 大多数编程语言都有代码 linting, 编译器有时会在编译过程中加入 linting.-- 来自 ESLint
为什么 JavaScript 需要 linter?
由于 JavaScript 是动态类型的, 而且是一种松散类型的语言, 因此开发人员在使用这门语言时很容易犯错. 因为不经过编译, 所以通常需要在执行. JS 文件的情况下才能发现语法或其他错误.
像 ESLint 这样的 linting 工具可以帮助开发人员在不执行 JavaScript 代码的情况下发现问题.
是什么让 ESLint 如此特别?
ESLint 中的所有东西都是可插拔的, 你甚至可以在运行时添加规则. 你添加的每个 linting 规则都是独立的, 任何一个规则都可以独自打开或关闭. 每个规则都可以设置为警告或错误级别.
现在有 2 个流行的风格指南:
- Google JavaScript Style Guide(https://google.github.io/styleguide/jsguide.html);
- Airbnb JavaScript Style Guide(https://github.com/airbnb/javascript#table-of-contents).
我一直在使用 Airbnb 的风格指南. 这个风格指南一直有人在维护, 在本文中, 我将使用受 Airbnb 风格指南启发的规则集.
首先更新 package.JSON 文件:
- {
- "name": "react-boiler-plate",
- "version": "1.0.0",
- "description": "A react boiler plate",
- "main": "src/index.js",
- "author": "Adeel Imran",
- "license": "MIT",
- "scripts": {
- "lint": "eslint --debug src/",
- "lint:write": "eslint --debug src/ --fix",
- "prettier": "prettier --write src/**/*.js"
- },
- "husky": {
- "hooks": {
- "pre-commit": "lint-staged"
- }
- },
- "lint-staged": {
- "*.(js|jsx)": ["npm run lint:write", "git add"]
- },
- "devDependencies": {
- "babel-eslint": "^8.2.3",
- "eslint": "^4.19.1",
- "eslint-config-airbnb": "^17.0.0",
- "eslint-config-jest-enzyme": "^6.0.2",
- "eslint-plugin-babel": "^5.1.0",
- "eslint-plugin-import": "^2.12.0",
- "eslint-plugin-jest": "^21.18.0",
- "eslint-plugin-jsx-a11y": "^6.0.3",
- "eslint-plugin-prettier": "^2.6.0",
- "eslint-plugin-react": "^7.9.1",
- "husky": "^1.1.2",
- "lint-staged": "^7.3.0",
- "prettier": "^1.14.3"
- }
- }
在开始进行配置之前, 先让我们来看看每个依赖包的功能.
babel-eslint: 这个包让你可以轻松在 Babel 上使用 lint. 如果你不使用 ESLint 尚不支持的 Flow 或实验性功能, 则不一定需要这个插件.
eslint: 这是 lint 代码所需的主要工具.
eslint-config-airbnb: 这个包提供了所有 Airbnb 的 ESLint 配置, 你可以修改它们.
eslint-plugin-babel:babel-eslint 的插件伴侣.
eslint-plugin-import: 这个插件旨在支持 ES2015+(ES6+)的导入 / 导出语法, 并防止出现拼写错误的文件路径和导入名称.
eslint-plugin-jsx-a11y: 适用于 JSX 元素可访问性规则的 linting 规则.
eslint-plugin-prettier: 让 ESLint 与 Prettier 的使用更顺畅.
eslint-plugin-react: 特定于 React 的 linting 规则.
eslint-config-jest-enzyme: 用于特定于 React 和 Enzyme 的全局变量. 这个 lint 配置让 ESLint 知道有哪些全局变量, 并且不会针对它们发出警告 -- 有点像断言 it 和 describe.
eslint-plugin-jest:Jest 的 ESLint 插件.
husky: 在自动化部分会进行更多介绍.
lint-staged: 在自动化部分会进行更多介绍.
现在我们已经有了基本的了解, 接下来可以开始了.
在 App/ 根目录创建. eslintrc.JS 文件:
- module.exports = {
- env: {
- es6: true,
- browser: true,
- node: true,
- },
- extends: ['airbnb', 'plugin:jest/recommended', 'jest-enzyme'],
- plugins: [
- 'babel',
- 'import',
- 'jsx-a11y',
- 'react',
- 'prettier',
- ],
- parser: 'babel-eslint',
- parserOptions: {
- ecmaVersion: 6,
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true
- }
- },
- rules: {
- 'linebreak-style': 'off', // Don't play nicely with Windows.
- 'arrow-parens': 'off', // Incompatible with prettier
- 'object-curly-newline': 'off', // Incompatible with prettier
- 'no-mixed-operators': 'off', // Incompatible with prettier
- 'arrow-body-style': 'off', // Not our taste?
- 'function-paren-newline': 'off', // Incompatible with prettier
- 'no-plusplus': 'off',
- 'space-before-function-paren': 0, // Incompatible with prettier
- 'max-len': ['error', 100, 2, { ignoreUrls: true, }], // airbnb is allowing some edge cases
- 'no-console': 'error', // airbnb is using warn
- 'no-alert': 'error', // airbnb is using warn
- 'no-param-reassign': 'off', // Not our taste?
- "radix": "off", // parseInt, parseFloat radix turned off. Not my taste.
- 'react/require-default-props': 'off', // airbnb use error
- 'react/forbid-prop-types': 'off', // airbnb use error
- 'react/jsx-filename-extension': ['error', { extensions: ['.js'] }], // airbnb is using .jsx
- 'prefer-destructuring': 'off',
- 'react/no-find-dom-node': 'off', // I don't know
- 'react/no-did-mount-set-state': 'off',
- 'react/no-unused-prop-types': 'off', // Is still buggy
- 'react/jsx-one-expression-per-line': 'off',
- "jsx-a11y/anchor-is-valid": ["error", { "components": ["Link"], "specialLink": ["to"] }],
- "jsx-a11y/label-has-for": [2, {
- "required": {
- "every": ["id"]
- }
- }], // for nested label htmlFor error
- 'prettier/prettier': ['error'],
- },
- };
还要在 App/ 根目录中添加. eslintignore 文件:
- /.Git
- /.vscode
- node_modules
我们先介绍一下. eslintrc.JS 文件的作用.
先把它拆分一下:
- module.exports = {
- env:{},
- extends: {},
- plugin: {},
- parser: {},
- parserOptions: {},
- rules: {},
- };
1. env: 用于预定义全局变量. 在我们的例子中, 可用的环境包括 es6,browser 和 es6.es6 将启用除模块之外的所有 ECMAScript 6 功能. browser 将添加所有浏览器全局变量, 如 Windows.node 将添加 Node 全局变量和 Node 作用域, 比如 global.
2. extends: 字符串数组 -- 扩展了之面配置的额外配置选项. 现在我们正在使用 airbnb 的 linting 规则, 这些规则被扩展到 jest, 然后是 jest-enzyme.
3. plugins: 插件基本上就是我们想要使用的 linting 规则. 现在我们正在使用 babel,import,jsx-a11y,react,prettier.
4. parser: 默认情况下, ESLint 使用 Espree, 但因为我们使用了 babel, 我们还需要使用 Babel-ESLint.
5. parserOptions: 如果我们将 Espree 的默认解析器更改为 babel-eslint, 需要指定 parserOptions-- 它是必需的. 我通过选项告诉 ESLint,ecmaVersion 是 6. 因为我们在 EcmaScript 模块 (而不是 script) 中编写代码, 所以我们将 sourceType 指定为 module. 由于我们使用了 React, 引入了 JSX, 所以在 ecmaFeatures 中加了 jsx 选项, 并将其设置为 true.
6. rules: 我们已经扩展并通过插件添加的所有规则, 我们可以更改或覆盖它们.
现在介绍一下. eslintignore
.eslintignore 里包含了我们不希望 ESLint 对它们进行 lint 的路径列表. 这里我只指定三个:
1. /.Git-- 我不希望 Git 相关文件被 lint.
2. /.vscode-- 由于我使用的是 VS Code, 这个编辑器提供了自己的配置文件, 我不希望配置文件被 lint.
3. node_modules-- 我不希望依赖项被 lint, 所以把这个目录也添加到列表中.
接下来让我们来看看 package.JSON 中新添加的脚本.
- "lint": "eslint --debug src/"
- "lint:write": "eslint --debug src/ --fix"
$ yarn lint-- 运行这个命令, 它将遍历 src/ 中的所有文件, 并在每个找到错误的文件中提供详细日志, 你可以手动打开这些文件并更正错误.
$ yarn lint:write-- 运行这个命令, 它将执行与上述命令相同的操作. 不同的地方在于, 如果它可以纠正它发现的错误, 它将纠正它们, 并尝试从代码中尽可能多地移除代码坏气味.
让它更自动化一些
到目前为止, 我们设置好了 prettier 和 eslint, 但每次我们都要运行脚本. 接下来我们让它更加自动化一些.
1. 在编辑器中按下 ctrl + s 时格式化和 lint 代码.
2. 每次提交代码时, 自动对代码进行 lint 和格式化.
3. 要在保存代码时进行格式化和 lint, 需要使用像 VS Code 这样的编辑器:
安装 ESLint 扩展插件. 在此 (https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) 下载插件或在 VS Code 编辑器中按下 ctrl + shift + x 打开扩展模块, 搜索 eslint, 将出现一系列插件. 安装 Dirk Baeumer 开发的那个. 安装完成后, 点击 reload 按钮重新启动编辑器.
安装好这个插件后, 在 App/ 根文件夹中创建一个名为. vscode/ 的文件夹 -- 不要忘了那个点号, 这个非常重要.
在文件夹中创建一个 settings.JSON 文件, 如下所示:
- {
- "editor.formatOnSave": false,
- "eslint.autoFixOnSave": true,
- }
editor.formatOnSave-- 我在这里将它设置为 false, 因为我不希望文件格式的默认编辑器配置与 ESLint 和 Prettier 发生冲突.
eslint.autoFixOnSave-- 我在这里将它设置为 true, 因为我希望每次在保存文件时安装的插件都能正常工作. 由于 ESLint 的配置关联了 Prettier 的配置, 所以每次在点击保存时, 它都会格式化和 lint 你的代码.
需要注意的是, 当你运行 yarn lint:write 时, 它也会 lint 和美化你的代码.
试想一下, 如果你有 2 万行代码, 然后通过手动的方式进行审计和改进, 然后再想象一下用一个命令就可以完成所有事情. 手动方法可能需要 30 天, 而自动方法可能只需要 30 秒.
脚本已经设置好了, 每次点击保存时, 编辑器都会对特定文件做出神奇的回应. 但是, 并不是团队中的每个人都会选择使用 VS Code. 不过没关系, 我们可以更自动化一些.
husky husky 是什么?
husky(https://github.com/typicode/husky)是一个 Git 钩子, 你可以在提交代码前或在将代码推送到分支时执行某些特定的操作.
你所要做的就是安装 husky:
yarn add --dev husky
然后在 package.JSON 文件中添加以下内容:
- "husky": {
- "hooks": {
- "pre-commit": "YOUR_COMMAND_HERE",
- "pre-push": "YOUR_COMMAND_HERE"
- }
- },
每次在提交或推送代码时, 它都会执行某个脚本或命令 -- 比如运行测试用例或格式化代码.
lint-staged lint-staged 是什么?
lint-staged(https://github.com/okonet/lint-staged)可以在暂存 (Git staged) 文件上运行 linter, 这样就不会将错误的代码推送到分支上.
为什么要用 lint-staged?
在提交代码之前进行 lint 是很有意义的, 你可以确保没有错误进入到代码库中, 并且可以强制应用代码样式. 但在整个项目上运行 lint 过程会很慢, 而且有些 lint 结果可能无关紧要. 你可能只想对要提交的文件进行 lint.
这个项目提供了一个脚本, 这个脚本将执行任意的 shell 任务, 并将暂存文件列表作为参数, 按指定的通配模式进行文件过滤.
你要做的是安装 lint-staged:
yarn add --dev lint-staged
然后在 package.JSON 文件中添加:
- "lint-staged": {
- "*.(js|jsx)": ["npm run lint:write", "git add"]
- },
这段配置的意思是先运行 lint:write 命令, 然后将文件添加到暂存区域. 它仅针对. JS 和. jsx 文件运行这个命令, 但你也可以根据需要针对其他文件运行这个命令.
husky 与 lint-staged 一起使用
每次提交代码之前, 都会运行一个叫作 lint-staged 的脚本, 这个脚本将运行 NPM run lint:write 命令, 这个将 lint 并格式化你的代码, 然后将代码添加到暂存区并提交.
最终的 package.JSON 文件应如下所示.
- {
- "name": "react-boiler-plate",
- "version": "1.0.0",
- "description": "A react boiler plate",
- "main": "src/index.js",
- "author": "Adeel Imran",
- "license": "MIT",
- "scripts": {
- "lint": "eslint --debug src/",
- "lint:write": "eslint --debug src/ --fix",
- "prettier": "prettier --write src/**/*.js"
- },
- "husky": {
- "hooks": {
- "pre-commit": "lint-staged"
- }
- },
- "lint-staged": {
- "*.(js|jsx)": ["npm run lint:write", "git add"]
- },
- "devDependencies": {
- "babel-eslint": "^8.2.3",
- "eslint": "^4.19.1",
- "eslint-config-airbnb": "^17.0.0",
- "eslint-config-jest-enzyme": "^6.0.2",
- "eslint-plugin-babel": "^5.1.0",
- "eslint-plugin-import": "^2.12.0",
- "eslint-plugin-jest": "^21.18.0",
- "eslint-plugin-jsx-a11y": "^6.0.3",
- "eslint-plugin-prettier": "^2.6.0",
- "eslint-plugin-react": "^7.9.1",
- "husky": "^1.1.2",
- "lint-staged": "^7.3.0",
- "prettier": "^1.14.3"
- }
- }
现在, 每当你提交代码时:
- $ Git add .
- $ Git commit -m "some descriptive message here"
它将根据. eslintrc.JS 文件的所有规则对代码进行 lint 和格式化. 有了这个, 你就可以确保没有坏代码被推到生产环境中.
现在介绍一下 EditorConfig
首先在 App/ 根文件夹中创建一个. editorconfig 文件, 然后在该文件中粘贴以下代码:
- # EditorConfig is awesome: http://EditorConfig.org
- # top-most EditorConfig file
- root = true
- [*.md]
- trim_trailing_whitespace = false
- [*.JS]
- trim_trailing_whitespace = true
- # Unix-style newlines with a newline ending every file
- [*]
- indent_style = space
- indent_size = 2
- end_of_line = lf
- charset = utf-8
- insert_final_newline = true
- max_line_length = 100
那么 EditorConfig 是什么东西?
并不是每个人都会使用 VS Code, 所以为了让每个人保持统一(例如在制表符空格或换行方面), 我们使用. editorconfig, 这样有助于强制执行某些规则.
支持 EditorConfig(https://editorconfig.org/)的编辑器包括 Web Storm,App Code,Atom,Eclipse,Emacs,bbedit, 等等.
上述的配置将执行以下操作:
去掉. md 和. JS 文件中的尾部空格;
将缩进样式设置为空格而不是制表符;
缩进大小为 2;
行尾是 lf, 这样每个人不管使用的是哪种操作系统, 都会有相同的行尾;
文件末尾应该有一个新行;
单行的最大度应为 100 个字符.
来源: https://www.cnblogs.com/Yanss/p/10159628.html