Day19 - 写出更有品质的程序码,信 eslint 得永生

前言

俗话说:「一千个人,就有一千种程序码的写法」,而且我们身在 JavaScript 的世界中,一段程序码可以用各种不同的方式来表达,例如该用单引号或双引号、空格或 Tab 等等的议题。

JavaScript 是世界上最棒的语言

如果深入到 React 中,会有使用 map 渲染 component 时忘记加 key ,或是者是 <Index></Index> 没有 children 却不使用 close tag 等情况,而且有一些程序码可能会导致 bug,或是这种写法可能会引发一些问题,但是难以发现。再加上导入 TypeScript、Next.js 後,有数不清的规则,只有文件规范一般人根本无法完全记住。

为了解决这些问题,所以我们需要 ESLint 帮助我们规范程序码的撰写方式,团队都必须遵照规范,让团队成员不会写出 ninja code。

除了 ESLint 之外,为了让团队撰写的程序码风格更为一致,还会再导入 Prettier,处理像是:

  • 单引号、双引号
  • 空格、Tab
  • 是否需要分号
  • 物件的最後一个栏位需不需要逗点

以上等等的问题都是我们经常遇到的问题,如同文章开头所述,每个人都有自己的程序码风格,随着专案逐渐扩大,将会使得程序码不易维护。所以使用 ESLint 搭配 Prettier 可以让程序自动帮我们维护程序码的风格,免得还需要用人工的方式检验程序码,不仅没有效率,而且也较不可靠。

在这篇文章中将会介绍如何在 Next.js + TypeScript 的环境中导入 ESLint 跟 Prettier 的设定,并且在文末将会介绍如何 husky 这项工具,在每次 git commit 时都可以自动帮助我们检查是否符合 ESLint 及 Prettier 的规范,让开发事半功倍。

建立一个全新的 Next.js + TypeScript 专案

首先,我们先来建立一个新的专案,可以使用以下指令 npxyarn 开启一个 Next.js + TypeScript 的专案:

npx create-next-app --typescript
# or
yarn create next-app --typescript

在 Next.js 11 版以後,ESLint 已经成为专案的标配,在建立完专案後就可以在资料夹中看到 .eslintrc.json 。预设的 ESLint 内容如下, 这是 Next.js 规范的 ESLint:

{
	"extends": "next/core-web-vitals"
}

这个设定基本上已经包含了大部分 React 会需要的 ESLint plugin:

  • [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react)
  • [eslint-plugin-react-hooks](https://www.npmjs.com/package/eslint-plugin-react-hooks)
  • [eslint-plugin-next](https://www.npmjs.com/package/@next/eslint-plugin-next)

如同这个设定的名称所述,它将会禁止两种会影响 core web vitals 的写法,其 ESLint 的等级都设置为 error,因此绝对无法通过 lint:

  • No sync scripts

    在 component 中使用 <script> 引入其他的 JavaScript 档案时一定要加上 asyncdefer ,否则同步的 <script> 将会影响 component 的效能:

    // bad
    <script src="some.js"></script>
    
    // good
    <script src="some.js" defer></script>
    
    // good
    <script src="some.js" async></script>
    

    还有另外一种合法的写法是使用目前在实验中的 next/script,它也会让在 component 中载入外部档案变成非同步的:

    import Script from "next/script";
    
    const Home = () => {
      return (
        <div class="container">
          <Script src="https://third-party-script.js"></Script>
          <div>Home Page</div>
        </div>
      );
    };
    
    export default Home;
    
  • No html link for pages
    这个规则禁止在 component 中使用原生 HTML 的 <a> 切换页面,如果需要切换页面,则是使用 next/link 提供的 <Link>

    ```javascript
    // bad
    <a href="/about">About Us</a>
    
    // good
    <Link href="/about">
    
    ```
    

如果是全新的 Next.js 专案,官方建议直接导入 next/core-web-vitals ,这个设定已经包含了 next 这个 config,你可能会在其他地方看到 extends 中同时包含 next/core-web-vitalsnext ,这个是较为旧的写法,大概是几个月前 XD

安装 Prettier

首先,我们需要安装以下两个套件:

yarn add -D prettier eslint-config-prettier

因为 ESLint 已经包含程序码 formatting 的规则,这些规则可能会与 Prettier 的设定发生冲突,所以为了解冲突,可以使用 eslint-config-prettier 关闭一些 ESLint 会与 Prettier 发生冲突的规则。

接着,我们需要为程序码风格做一些配置,例如单引号、分号、tab 几格、程序码宽度等等,至於其他设定就看团队的需求了:

// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "useTabs": false,
  "printWidth": 120
}

然後我们需要在 .eslintrc.json 中设定 eslint-config-prettier ,在 extends 的最後一个位置加上 "prettier" 的设定,如此一来才能覆盖 "next/core-web-vitals" 引入的 ESLint 设定:

// .eslintrc.json
{
  "extends": [
    "next/core-web-vitals",
    "prettier"
  ],
}

最後,我们会在 package.json 中设定 prettier 的指令,为的是可以在文章後面串接 git hook。 团队在开发时,一定会执行 git commit 将程序码记录在 git 上,这时可以触发 git hook,同时跑 prettier 帮我们把所有的程序码都「整理」过一次,如此一来可以确保推到 git 上的程序码都是符合团队规范的。

// package.json
{
  "scripts": {
    "prettier": "prettier '**/*.{js,jsx,ts,tsx}' --write"
  }
}

安装 @typescript-eslint/eslint-plugin

TypeScript 做为现在的趋势,许多专案都是用 TypeScript 撰写,强型别能够带来非常多的好处,能让前端的应用更为稳健,可维护性也更高。但是 TypeScript 也是有许多需要规范的写法,所以我们需要另外设置 @typescript-eslint/eslint-plugin ,让它帮我们纠察出 TypeScript 程序码不符合规范的地方。

你可能会听过 TSLint 这个套件,但是现在如果上 GitHub 上看 TSLint 这个 repo,它已经被 archived 了,主要是因为 ESLint 的处理效能比 TSLint 更好,而且许多专案都仍然用 ESLint,所以最後官方团队就把 TSLint 移植到 @typescript-eslint/eslint-plugin 上面了。

首先,我们使用以下指令安装套件:

yarn add -D @typescript-eslint/eslint-plugin

然後,同样在 .eslintrc.json 设定 @typescript-eslint/eslint-plugin

{
  "extends": [
    "next/core-web-vitals",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
}

使用 husky + lint-staged 在 git commit 时执行 ESLint 与 Prettier

husky (哈士奇) 是一个容易设定 git hook 的套件,像是我们希望在 pre-commit 时触发 eslint 与 prettier,就可以透过 husky 来帮我们执行。然而,如果 prettier 跟 ESLint 每次 commit 时都需要处理在专案中所有的档案,将会耗费非常多的时间在这些事情上,我们当然不会希望这样的情况发生,难以想像这样的开发流程。

所以,为了让开发体验更好,希望在 commit 时一样可以让 husky 帮我们触发 git hook,但可以只针对在 stage 的档案执行 ESLint 与 prettier。广大的社群已经想过一样的情况,有相对应的解决方案,那就是 lint-staged 这个套件。

我们使用以下指令安装 husky 跟 lint-staged 这两个套件:

yarn add -D husky lint-staged

在安装完毕後,接着初始化 hucky 的环境:

yarn husky install

你会在专案资料夹中看到多了 .husky 这个资料夹,在 hucky 7 以後设定 git hook 的方式不太一样,以前在前端我们可以写在 package.json 里面,但後来变成放在 .hucky 资料夹里面,好处是让设定更加弹性,可以直接在里面写 shell script。

接着,我们想要在 commit 时触发 prettier 跟 eslint 两个功能,可以使用以下指令建立 git hook,在 pre-commit 的时候会执行 lint-staged 这个指令,并且只针对在 git stage 的档案做处理:

yarn husky add .husky/pre-commit "yarn lint-staged"

最後,我们需要设定 lint-staged 会执行哪些指令,可以直接在 package.json 这个档案中设定跑已经设定好的 prettier 指令,以及 eslint 指令。

package.json

{
  "lint-staged": {
    "**/*.{ts,tsx,js,jsx}": [
      "yarn prettier",
      "eslint"
    ]
  }
}

也许你会想问为什麽这边不是用 yarn lint 这个指令,yarn lint 对应是 next lint ,但我们不能使用它,而是要用原生的 eslint

这是一个存在於 next.js 官方的 GitHub issue ,在 next.js 11.1.2 版本之前在 lint-staged 使用 yarn lint 会发生错误,目前在 11.1.3 版可以用原生的 eslint 指令解决,未来还需要等待更新的版本发布, 也许才能解决 lint-staged 不能执行 next lint 的问题。

小结

以上就是在 next.js 11.1.2 版本下设定 ESLint + Prettier + TypeScript + husky 的流程,现在我们知道了如何在专案中加入这些设定,让团队开发时能够写处更好维护的程序码,让程序帮我们维护程序。

Reference


<<:  Abstract Factory 抽象工厂模式

>>:  Day 21 [Python ML、资料视觉化] 长条图和热度图

Day 8 - 导入 Google Fonts

昨天讲了文字使用,今天来讲讲字体。在默认情况下,Tailwind 提供了三种字体系列:font-sa...

ES6 几个小重点

var vs const let var的scoopt是function let 和const的sc...

第 59 天 - 学会除了 --help 跟 -h 外,使用 man 查询指令使用方式

操作画面 : 主要 man 可以完全滑鼠,像读书一样分章节阅读 另外今天发现 forloop 1 到...

[Day 26] 交叉验证 K-Fold Cross-Validation

今日学习目标 了解 K-Fold 各种不同变形 K-Fold Cross-Validation Ne...

使用 Learner Lab 建立 WordPress 网站 (EC2)

使用 Learner Lab 建立 WordPress 网站 (EC2) AWS Academy L...