從零開始配置 TypeScript 項目

前言

本文是算法與 TypeScript 實現中 TypeScript 項目總體的環境配置過程介紹。主要包括瞭如下一些配置內容:javascript

  • Git Commit Message
  • TypeScript
  • ESLint
  • Prettier
  • Lint Staged
  • Jest
  • Npm Script Hook
  • Vuepress
  • Github Actions

若是你對以上的某些配置很是熟悉,則能夠跳過閱讀。若是你不清楚是否要繼續閱讀其中的一些配置信息,則能夠經過工程問題來決定是否要繼續閱讀相關的內容。html

算法與 TypeScript 實現 關於當前配置的改造在 feat/framework 分支上,但願剛興趣的同窗能夠 star 一波。學習文檔 目前仍然是老版本的學習文檔,以後會進行持續更新。前端

舒適提示:若是你但願在項目中製做基於 TypeScript 實現的簡單易用的工具函數庫,你可使用一些成熟的 "零配置" 腳手架,例如 tsdxmicrobundle 以及 typescript-starter 等。若是功能不能知足你的項目需求,你也能夠基於這些工具進行團隊的定製化改造,例如 ts-lib-scriptsvue

配置問題

但願你讀完這篇文章可以瞭解如下一些問題(頗有可能成爲工程配置方面的面試題哦,細節決定成敗):java

  • 在使用 Git 的時候如何規範 Git 的提交說明(Commit 信息)?
  • 簡述符合 Angular 規範的提交說明的結構組成?
  • Commit 信息如何和 Github Issues 關聯?
  • 在設計一些庫包時如何生成版本日誌?
  • TypeScript 如何自動生成庫包的聲明文件?
  • TypeScript 目前是採用 TSLint 仍是 ESLint 進行代碼校驗,爲何?
  • 列舉你知道的全部構建工具並說說這些工具的優缺點?這些構建工具在不一樣的場景下應該如何選型?
  • Babel 對於 TypeScript 的支持有哪些限制?
  • 列舉你所知道的 ESLint 功能?
  • 如何確保構建和上傳的代碼無 ESLint 錯誤信息?
  • ESLint 和 Prettier 的區別是什麼?二者在一塊兒工做時會產生問題嗎?
  • Linters 有哪兩種類型的校驗規則?
  • 如何有效的識別 ESLint 和 Prettier 可能產生衝突的格式規則?如何解決此類規則衝突問題?
  • git hook 在項目中哪些做用?
  • git hook 中客戶端和服務端鉤子各自用於什麼做用?
  • git hook 中經常使用的鉤子有哪些?
  • pre-commitcommit-msg 鉤子的區別是什麼?各自可用於作什麼?
  • husky 以及 ghook 等工具製做 git hook 的原理是什麼?
  • 如何設計一個通用的 git hook ?
  • git hook 能夠採用 Node 腳本進行設計嗎?如何作到?
  • lint-staged 的功能是什麼?
  • VS Code 配置中的用戶和工做區有什麼區別?
  • VS Code 的插件能夠只對當前項目生效嗎?
  • 談談你所理解的 npm scripts,它有哪些功能?
  • 你所知道的測試有哪些測試類型?
  • 你所知道的測試框架有哪些?
  • 什麼是 e2e 測試?有哪些 e2e 的測試框架?
  • 假設如今有一個插入排序算法,如何對該算法進行單元測試?
  • 假設你本身實現的 React 或 Vue 的組件庫要設計演示文檔,你會如何設計?設計的文檔須要實現哪些功能?
  • 在設計工具庫包的時候你是如何設計 API 文檔的?
  • 在一般的腳手架項目中進行熱更新(hot module replacement)時如何作到 ESLint 實時打印校驗錯誤信息?
  • Vuepress 有哪些功能特色?
  • 你所知道的 CI / CD 工具備哪些?在項目中有接觸過相似的流程嗎?
  • CI 和 CD 的區別是什麼?
  • Github Actions 的特色是什麼?

除此以外若是你對其餘相關的知識感興趣(非本文相關的知識),但願你能額外深刻去探索:node

  • TypeScript 的特色?
  • CommonJS 和 ES Module 有哪些區別?
  • Tree Shaking 的做用是什麼?什麼狀況下可使用 Tree Shaking 的能力?
  • 如何引入 ES Module 庫包?在構建層面和包描述文件層面須要注意哪些方面?
  • 談談你對 TypeScript 聲明文件的理解?在製做庫包時如何對外識別聲明文件?在外部使用時有哪些好處?
  • 在製做工具包的時候如何考慮按需引入和全量引入的優雅引入設計?
  • 你知道哪些製做工具函數庫的腳手架?
  • 瞭解 Vue CLI 3.x 的功能特色嗎?如何基於 Vue CLI 3.x 定製符合團隊項目的腳手架?
  • 瞭解 react-scripts 嗎?
  • 工程化配置領域的設計能夠有哪些設計階段(例如 react-scripts 和 vue ui 在設計以及使用形態上的區別)?
  • 工程化配置監控(使用版本信息、版本兼容性報錯信息分析、使用功能分析等)?

舒適提示:有些問題在本文中可以獲得答案,有些問題須要本身擴展閱讀或查看源碼才能獲得答案(做者一樣是工程化配置領域的小白,以上的這些問題一樣在問本身)。python

配置框架

須要注意文檔中的配置說明可能會省略某些細節步驟(例如某些依賴的 npm 包安裝、某些配置文件說明等),若是想要知道更多細節信息,可查看各個配置的 Commit 提交信息:react

  • 項目初始化 (afaa458)
  • framework: 新增 Git Commit Message 規範提交能力 (d04e259)
  • framework: 新增 TypeScript 編譯能力 (ebecee9)
  • framework: 新增 ESLint 代碼校驗能力 (dca67d4)
  • framework: 新增 Prettier 自動格式化能力 (7f3487a)
  • framework: 新增 Lint Staged 上傳校驗能力 (b440186)
  • framework: 新增 Jest 單元測試能力 (6f086f2)
  • framework: 新增 Npm Scripts Hook 能力 (93e597a)
  • framework: 新增 Vuepress 演示文檔能力 (66e38d1)
  • framework: 新增 Github Actions 能力 (1cc85a4)

舒適提示:以上都是使用 npm run changelog 自動生成的版本日誌信息,你也能夠經過倉庫的 CHANGELOG.md 進行查看。webpack

Git Commit Message

Commitizen 是一個規範 Git 提交說明(Commit Message)的 CLI 工具,具體如何配置可查看 Cz 工具集使用介紹(這篇文章對於 Commit Message 的配置介紹已經很是詳細清楚,所以這裏再也不過多介紹)。本項目中主要使用瞭如下一些工具:git

配置後會產生如下一些特性:

  • 使用 git cz 代替 git commit 進行符合 Angular 規範的 Commit Message 信息提交
  • 代碼提交以前會經過 husky 配合 git hook 進行提交信息校驗,一旦提交信息不符合 Angular 規範,則提交會失敗
  • 執行 npm run changelog 會在根目錄下自動生成 CHANGELOG.md 版本日誌

舒適提示:husky 中文的意思是哈士奇,你們能夠想象一下爲何這個工具叫哈士奇,是否是咬着你不放的意思(or more 🐶 woof!),一旦它咬着你的代碼提交不放,這將會是很是有趣的一件事情,在後續的工具配置中,咱們仍然將於哈士奇見面,看看它會具體咬什麼東西!

例如當你提交了一個不符合規範的 Commit Message(此時提交失敗):

PS C:\Code\Git\algorithms> git commit -m "這是一個不符合規範的 Commit Message"
husky > commit-msg (node v12.13.1)
⧗   input: 這是一個不符合規範的 Commit Message
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

husky > commit-msg hook failed (add --no-verify to bypass)
複製代碼

舒適提示:若是不知道什麼是 CLI (命令行接口),可查看 使用 NPM 發佈和使用 CLI 工具

TypeScript

TypeScript 背景

工具函數庫的實現採用 TypeScript,除了能夠自動生成 ts 聲明文件供外部更好的提示使用以外,也能夠避免 JavaScript 動態性所帶來的一些沒法預料的錯誤信息(具體可查看 Top 10 JavaScript errors from 1000+ projects (and how to avoid them)),從而使算法的設計更加嚴謹。 TypeScript 的構建方式有不少種,除了原生編譯器 tsc 之外,還包括 Webpack、Rollup、Babel 以及 Gulp 等(更多構建工具的集成可查看 Integrating with Build Tools):

  • Webpack 主要用於頁面應用的模塊化構建,使用 Webpack 構建會增長構建庫的體積,所以簡單工具庫的製做使用 Webpack 徹底是 "殺雞用牛刀"。
  • Rollup 是一個構建工具庫很是不錯的輕量選擇,它持有的 Tree Shaking 以及構建 ES Module 的特性使得它被 tsdx、microbundle 甚至 Vue 等普遍使用。
  • Babel 對於 TypeScript 可以使用 @babel/preset-typescript 去除 TypeScript 類型標記,可是不作類型編譯檢查,更多關於 Babel 對於 TypeScript 支持的限制可查看 @babel/plugin-transform-typescript - CaveatsBabel 7 or TypeScript
  • Gulp 是一個很是輕量的構建工具,而且也是 TypeScript 官方推薦的構建工具,具體可查看 TypeScript - Building,簡單的 Gulp 配置可查看 TypeScript 中文網 - Gulp

因爲算法的函數工具庫功能很是單一簡單,所以採用 TypeScript 官方推薦的 Gulp 工具進行構建便可知足需求。

舒適提示:更多構建工具能夠了解 esbuildparcel以及 backpack 等。固然若是你想要更多瞭解這些構建工具的差別以及在什麼項目環境下應該作如何選型,能夠自行搜索前端構建工具的對比或差別,這裏推薦一篇我的以爲總結不錯的文章 前端構建:3 類 13 種熱門工具的選型參考

TypeScript 配置

本項目會構建輸出 CommonJS 工具包(npm 包)供外部使用,採用 TypeScript 設計並輸出聲明文件有助於外部更好的使用該資源包進行 API 的提示。TypeScript 編譯採用官方文檔推薦的 Gulp 工具並配合 gulp-typescripttsconfig.json 配置文件。在根目錄下新建 tsconfig.json 文件並新增如下配置:

{
  "compilerOptions": {
    // 指定 ECMAScript 目標版本 "ES3"(默認), "ES5", "ES6" / "ES2015", "ES2016", "ES2017" 或 "ESNext"。
    "target": "ES5",
    // 構建的目標代碼刪除全部註釋,除了以 /!* 開頭的版權信息
    "removeComments": true,
    // 可配合 gulp-typescript 生成相應的 .d.ts 文件
    "declaration": true,
    // 啓用全部嚴格類型檢查選項。啓用 --strict 至關於啓用 --noImplicitAny, --noImplicitThis, --alwaysStrict, --strictNullChecks, --strictFunctionTypes 和 --strictPropertyInitialization
    "strict": true,
    // 禁止對同一個文件的不一致的引用
    "forceConsistentCasingInFileNames": true,
    // 報錯時不生成輸出文件
    "noEmitOnError": true
  }
}
複製代碼

舒適提示:這裏沒有新增 module 配置信息,由於默認輸出 CommonJS 規範,更多關於 TypeScript 配置信息可查看TypeScript 官方文檔 / 編譯選項。若是對於 CommonJS 和 ES modules 的區別不是很清晰,這裏有一些很是好的文檔能夠供你們閱讀:ES modules: A cartoon deep-diveES6 modules。若是想了解如何對外提供 ES Module 能夠查看 pkg.module

同時在根目錄下新建 gulpfile.js 文件:

const gulp = require("gulp");
const ts = require("gulp-typescript");
const tsProject = ts.createProject("tsconfig.json");

// 輸出 CommonJS 規範到 dist 目錄下
gulp.task("default", function () {
  const tsResult = tsProject.src().pipe(tsProject());
  return tsResult.js.pipe(gulp.dest("dist"));
});
複製代碼

package.json 中新增 npm script 腳本:

"scripts": {
  "build": "rimraf dist && gulp"
},
複製代碼

其中 rimfaf 用於在構建以前清除 dist 目錄文件內容。此時在 src 目錄下新增 TypeScript 源碼並使用 npm run build 命令能夠進行項目構建並輸出 CommonJS 規範的目標代碼到 dist 目錄下。

除此以外,此項目但願能夠快速生成聲明文件供外部進行代碼提示,此時仍然能夠藉助 gulp-typescript 工具自動生成聲明文件。在 gulpfile.js 中新增如下配置

const gulp = require("gulp");
const ts = require("gulp-typescript");
const tsProject = ts.createProject("tsconfig.json");
const merge = require("merge2");

// 輸出 CommonJS 規範到 dist 目錄下
gulp.task("default", function () {
  const tsResult = tsProject.src().pipe(tsProject());

  return merge([
    tsResult.dts.pipe(gulp.dest("types")),
    tsResult.js.pipe(gulp.dest("dist")),
  ]);
});
複製代碼

修改 build 命令使其在構建以前同時能夠刪除 types 目錄:

"scripts": {
  "build": "rimraf dist types && gulp",
},
複製代碼

再次執行 npm run build 會在項目根目錄下生成 types 文件夾,該文件夾主要存放自動生成的 TypeScript 聲明文件。

須要注意發佈 npm 包時默認會將當前項目的全部文件進行發佈處理,但這裏但願發佈的包只包含使用者須要的編譯文件 disttypes,所以能夠經過package.json 中的 files(用於指定發佈的 npm 包包含哪些文件) 字段信息進行控制:

"files": [
  "dist",
  "types"
],
複製代碼

舒適提示:發佈的 npm 包中某些文件將忽視 files 字段信息的配置,包括 package.jsonLICENSEREADME.md 等。

除此以外,若是但願發佈的 npm 包經過 require('algorithms-utils')import 形式引入時指向 dist/index.js 文件,須要配置 package.json 中的 main 字段信息:

"main": "dist/index.js"
複製代碼

舒適提示: 對於工具包使用全量引入的方式並非一個好的選擇,能夠經過具體的工具方法進行按需引入。

ESLint

ESLint 背景

TypeScript 的代碼檢查工具主要有 TSLint 和 ESLint 兩種。早期的 TypeScript 項目通常採用 TSLint 進行檢查。TSLint 和 TypeScript 採用一樣的 AST 格式進行編譯,但主要問題是對於 JavaScript 生態的項目支持不夠友好,所以 TypeScript 團隊在 2019 年宣佈全面轉向 ESLint(具體可查看 TypeScript 官方倉庫的 .eslintrc.json 配置),更多關於轉向 ESLint 的緣由可查看:

TypeScript 和 ESLint 使用不一樣的 AST 進行解析,所以爲了在 ESLint 中支持 TypeScript 代碼檢查須要製做額外的自定義解析器(Custom Parsers,ESLint 的自定義解析器功能須要基於 ESTree),目的是爲了可以解析 TypeScript 語法並轉成與 ESLint 兼容的 AST。@typescript-eslint/parser 在這樣的背景下誕生,它會處理全部 ESLint 特定的配置並調用 @typescript-eslint/typescript-estree 生成 ESTree-compatible AST(須要注意不只僅兼容 ESLint,也能兼容 Prettier)。

@typescript-eslint 是一個採用 Lerna 進行設計的 Monorepo 結構倉庫,除了上述提到的 npm 包以外,還包含如下兩個重要的 npm 包:

舒適提示:若是你正在使用 TSLint,而且你但願兼容 ESLint 或者向 ESLint 進行過渡(TSLint 和 ESLint 並存), 可查看 Migrating from TSLint to ESLint。除此以外,以上所介紹的這些包發佈時版本一致(爲了聯合使用的兼容性),須要額外注意@typescript-eslint 對於 TypeScript 和 ESLint 的版本支持性,更多可查看 @typescript-eslint/parser 的倉庫信息。

ESLint 配置

從背景的介紹中能夠理解,對於全新的 TypeScript 項目(直接拋棄 TSLint)須要包含解析 AST 的解析器 @typescript-eslint/parser 和使用校驗規則的插件 @typescript-eslint/eslint-plugin,這裏須要在項目中進行安裝:

npm i --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
複製代碼

在根目錄新建 .eslintrc.js 配置文件,並設置如下配置:

module.exports = {
  root: true,
  parser: "@typescript-eslint/parser",
  plugins: ["@typescript-eslint"],
  extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
};
複製代碼

其中:

  • parser: '@typescript-eslint/parser':使用 ESLint 解析 TypeScript 語法
  • plugins: ['@typescript-eslint']:在 ESLint 中加載插件 @typescript-eslint/eslint-plugin,該插件可用於配置 TypeScript 校驗規則。
  • extends: [ ... ]:在 ESLint 中使用共享規則配置,其中 eslint:recommended 是 ESLint 內置的推薦校驗規則配置(也被稱做最佳規則實踐),plugin:@typescript-eslint/recommended 是相似於 eslint:recommended 的 TypeScript 推薦校驗規則配置。

舒適提示:若是你稍微閱讀一下 recommanded 源碼你會發現,其實內部能夠理解爲推薦校驗規則的集合。所以若是想基於 @typescript-eslint/eslint-plugin 進行自定義規則,則可參考 TypeScript Supported Rules

配置完成後在 package.json 中設置校驗命令

"scripts": {
  "lint": "eslint src",
}
複製代碼

此時若是在 src 目錄下書寫錯誤的語法,執行 npm run lint 就會輸出錯誤信息:

> eslint src


C:\Code\Git\algorithms\src\greet.ts
  2:16  warning  Missing return type on function @typescript-eslint/explicit-module-boundary-types ✖ 1 problem (0 errors, 1 warning) 複製代碼

舒適提示:輸出的錯誤信息是經過 ESLint Formatters 生成,查看 ESLint 源代碼並調試可發現默認採用的是 stylish formatter

ESLint 插件

若是不使用插件,很難發現代碼可能存在 TypeScript 格式錯誤,由於在書寫代碼的時候除了手動執行 npm run lint 之外沒有任何的實時提示信息(你固然也能夠經過 gulp監聽文件的變化並執行 npm run lint)。爲了能夠實時看到 TypeScript 錯誤信息,能夠經過 VS Code 插件進行處理。安裝 ESLint 插件後可進行代碼的實時提示,具體以下圖所示:

固然爲了防止不須要被校驗的文件出現校驗信息,能夠經過 .eslintignore 文件進行配置(例如如下都是一些不須要格式校驗的配置文件):

# gulp
gulpfile.js

# eslint
.eslintrc.js

# commitizen
commitlint.config.js

# jest
jest.config.js

# build
dist
複製代碼

此時能夠發現以前執行 lint 命令的錯誤經過插件的形式可實時在 VS Code 編輯器中進行顯示。除此以外,一些 ESLint 的格式校驗錯誤(例如多餘的; 等)可經過配置 Save Auto Fix 進行保存自動格式化處理。具體 VS Code 的配置可參考 ESLint 插件 的文檔說明,這邊應該須要進行以下配置:

"editor.codeActionsOnSave": {
  "source.fixAll": true,
  "source.fixAll.eslint": true
}
複製代碼

舒適提示:VS Code 的配置分爲兩種類型(用戶和工做區),針對上述通用的配置主要放在用戶裏,針對不一樣項目的不一樣配置則能夠放入工做區進行處理。

ESLint 確保構建

VS Code 插件並不能確保代碼上傳或構建前無任何錯誤信息,此時仍然須要額外的流程可以避免錯誤。在構建前進行 ESLint 校驗可以確保構建時無任何錯誤信息,一旦 ESLint 校驗不經過則不容許進行源碼的構建操做:

"scripts": {
  "lint": "eslint src --max-warnings 0",
  "build": "npm run lint && rimraf dist types && gulp",
}
複製代碼

須要注意在構建時進行校驗的嚴格控制,一旦 lint 拋出 warning 或者 error 則立馬終止構建(詳情可查看 ESLint 退出代碼)。

舒適提示:須要注意 Shell 中的 &&& 是有差別的,&& 主要用於繼發執行,只有前一個任務執行成功,纔會執行下一個任務,& 主要用於併發執行,表示兩個腳本同時執行。這裏構建的命令須要等待 lint 命令執行經過才能進行,一旦 lint 失敗那麼構建命令將再也不執行。

ESLint 確保代碼上傳

儘管可能配置了 ESLint 的校驗腳本 以及 VS Code 插件,可是有些 ESLint 的規則校驗是沒法經過 Save Auto Fix 進行格式化修復的(例如質量規則),所以還須要一層保障可以確保代碼提交以前全部的代碼可以經過 ESLint 校驗,這個配置將在 Lint Staged 中進行講解。

Prettier

Prettier 背景

Prettier 是一個統一代碼格式風格的工具,若是你不清楚爲何須要使用 Prettier,能夠查看 Why Prettier?。不少人可能疑惑,ESLint 已經可以規範咱們的代碼風格,爲何還須要 Prettier?在 Prettier vs Linters 中詳細說明了二者的區別,Linters 有兩種類型的規則:

ESLint 的規則校驗同時包含了 格式規則質量規則,可是大部分狀況下只有 格式規則 能夠經過 --fix 或 VS Code 插件的 Sava Auto Fix 功能一鍵修復,而 質量規則 更多的是發現代碼可能出現的 Bug 從而防止代碼出錯,這類規則每每須要手動修復。所以 格式規則 並非必須的,而 質量規則 則是必須的。Prettier 與 ESLint 的區別在於 Prettier 專一於統一的格式規則,從而減輕 ESLint 在格式規則上的校驗,而對於質量規則 則交給專業的 ESLint 進行處理。總結一句話就是:Prettier for formatting and linters for catching bugs!(ESLint 是必須的,Prettier 是可選的!)

須要注意若是 ESLint(TSLint) 和 Prettier 配合使用時格式規則有重複且產生了衝突,那麼在編輯器中使用 Sava Auto Fix 時會讓你的一鍵格式化啼笑皆非。此時應該讓二者把各自注重的規則功能區分開,使用 ESLint 校驗質量規則,使用 Prettier 校驗格式規則,更多信息可查看 Integrating with Linters

舒適提示:在 VS Code 中使用 ESLint 匹配到相應的規則時會產生黃色波浪線以及紅色文件名進行錯誤提醒。Prettier 更但願你對格式規則無感知,從而不會讓你以爲有任何使用的負擔。若是想要了解更多 Prettier,還能夠查看 Prettier 的背後思想 Option Philosophy,我的認爲了解一個產品設計的哲學能更好的指導你使用該產品。

Prettier 配置

首先安裝 Prettier 所須要的依賴:

npm i  prettier eslint-config-prettier --save-dev
複製代碼

其中:

  • eslint-config-prettier: 用於解決 ESLint 和 Prettier 配合使用時容易產生的格式規則衝突問題,其做用就是關閉 ESLint 中配置的一些格式規則,除此以外還包括關閉 @typescript-eslint/eslint-plugineslint-plugin-babeleslint-plugin-reacteslint-plugin-vueeslint-plugin-standard 等格式規則。

理論上而言,在項目中開啓 ESLint 的 extends 中設置的帶有格式規則校驗的規則集,那麼就須要經過 eslint-config-prettier 插件關閉可能產生衝突的格式規則:

{
  "extends": [
    "plugin:@typescript-eslint/recommended",
    // 用於關閉 ESLint 相關的格式規則集,具體可查看 https://github.com/prettier/eslint-config-prettier/blob/master/index.js
    "prettier",
    // 用於關閉 @typescript-eslint/eslint-plugin 插件相關的格式規則集,具體可查看 https://github.com/prettier/eslint-config-prettier/blob/master/%40typescript-eslint.js
    "prettier/@typescript-eslint",
  ]
}
複製代碼

配置完成後,能夠經過命令行接口運行 Prettier:

"scripts": {
  "prettier": "prettier src test --write",
},
複製代碼

--write 參數相似於 ESLint 中的 --fix(在 ESLint 中使用該參數仍是須要謹慎哈,建議仍是使用 VS Code 的 Save Auto Fix 功能),主要用於自動修復格式錯誤。此時書寫格式的錯誤代碼:

import great from "@/greet";

// 中間這麼多空行
export default {
  great,
};
複製代碼

執行 npm run prettier 進行格式修復:

PS C:\Code\Git\algorithms> npm run prettier

> algorithms-utils@1.0.0 prettier C:\Code\Git\algorithms
> prettier src test --write

src\greet.ts 149ms
src\index.ts 5ms
test\greet.spec.ts 11ms
複製代碼

修復以後的的文件格式以下:

import great from "@/greet";

export default {
  great,
};
複製代碼

須要注意若是某些規則集沒有對應的 eslint-config-prettier 關閉配置,那麼能夠先經過 CLI helper tool 檢測是否有重複的格式規則集在生效,而後能夠經過手動配置 eslintrc.js 的形式進行關閉:

PS C:\Code\Git\algorithms> npx eslint --print-config src/index.ts | npx eslint-config-prettier-check
No rules that are unnecessary or conflict with Prettier were found.
複製代碼

例如把 eslint-config-prettier 的配置去除,此時進行檢查重複規則:

PS C:\Code\Git\algorithms> npx eslint --print-config src/index.ts | npx eslint-config-prettier-check
The following rules are unnecessary or might conflict with Prettier:

- @typescript-eslint/no-extra-semi
- no-mixed-spaces-and-tabs

The following rules are enabled but cannot be automatically checked. See:
https://github.com/prettier/eslint-config-prettier#special-rules

- no-unexpected-multiline
複製代碼

此時假設 eslint-config-prettier 沒有相似的關閉格式規則集(例如本項目中配置的 plugin:jest/recommended 可能存在規則衝突),那麼能夠經過配置 .eslintrc.js 的形式本身手動關閉相應衝突的格式規則。

舒適提示:ESLint 能夠對不一樣的文件支持不一樣的規則校驗, 所以 --print-config 只能對應單個文件的衝突格式規則檢查。 因爲一般的項目是一套規則對應一整個項目,所以對於整個項目全部的規則只須要校驗一個文件是否有格式規則衝突便可。

Prettier 插件

經過命令行接口 --write 的形式能夠進行格式自動修復,可是相似 ESLint,咱們更但願項目在實時編輯時能夠經過保存就能自動格式化代碼(鬼知道 --fix 以及 --write 格式了什麼文件,固然更但願經過肉眼的形式當即感知代碼的格式化變化),此時能夠經過配置 VS Code 的 Prettier - Code formatter 插件進行 Save Auto Fix,具體的配置查看插件文檔。

Prettier 確保代碼上傳

和 ESLint 同樣,儘管可能配置了 Prettier 的自動修復格式腳本以及 VS Code 插件,可是沒法確保格式遺漏的狀況,所以還須要一層保障可以確保代碼提交以前可以進行 Prettier 格式化,這個配置將在 Lint Staged 中講解,更多配置方案也能夠查看 Prettier - Pre-commit Hook

Lint Staged

Lint Staged 背景

在 Git Commit Message 中使用了 commitlint 工具配合 husky 能夠防止生成不規範的 Git Commit Message,從而阻止用戶進行不規範的 Git 代碼提交,其原理就是監聽了 Git Hook 的執行腳本(會在特定的 Git 執行命令諸如 commitpushmerge 等觸發以前或以後執行相應的腳本鉤子)。Git Hook 實際上是進行項目約束很是好用的工具,它的做用包括但不限於:

  • Git Commit Message 規範強制統一
  • ESLint 規則統一,防止不符合規範的代碼提交
  • Prettier 自動格式化(相似的還包括 Style 樣式格式等)
  • 代碼穩定性提交,提交以前確保測試用例所有經過
  • 發送郵件通知
  • CI 集成(服務端鉤子)

Git Hook 的鉤子很是多,可是在客戶端中可能經常使用的鉤子是如下兩個:

  • pre-commit:Git 中 pre 系列鉤子容許終止即將發生的 Git 操做,而post 系列每每用做通知行爲。pre-commit 鉤子在鍵入提交信息(運行 git commitgit cz)前運行,主要用於檢查當前即將被提交的代碼快照,例如提交遺漏、測試用例以及代碼等。該鉤子若是以非零值退出則 Git 將放棄本次提交。固然你也能夠經過配置命令行參數 git commit --no-verify 繞過鉤子的運行。
  • commit-msg:該鉤子在用戶輸入 Commit Message 後被調用,接收存有當前 Commit Message 信息的臨時文件路徑做爲惟一參數,所以能夠利用該鉤子來覈對 Commit Meesage 信息(在 Git Commit Message 中使用了該鉤子對提交信息進行了是否符合 Angular 規範的校驗)。該鉤子和 pre-commit 相似,一旦以非零值退出 Git 將放棄本次提交。

除了上述經常使用的客戶端鉤子,還有兩個經常使用的服務端鉤子:

  • pre-receive:該鉤子會在遠程倉庫接收 git push 推送的代碼時執行(注意不是本地倉庫),該鉤子會比 pre-commit 更加有約束力(總會有這樣或那樣的開發人員不喜歡提交代碼時所作的一堆檢測,他們可能會選擇繞過這些鉤子)。pre-receive 鉤子可用於接收代碼時的強制規範校驗,若是某個開發人員採用了繞過 pre-commit 鉤子的方式提交了一堆 💩 同樣的代碼,那麼經過設置該鉤子能夠拒絕代碼提交。固然該鉤子最經常使用的操做仍是用於檢查是否有權限推送代碼、非快速向前合併等。
  • post-receive:該鉤子在推送代碼成功後執行,適合用於發送郵件通知或者觸發 CI 。

舒適提示:想了解更多 Git Hook 信息能夠查看 Git Hook 官方文檔Git 鉤子:自定義你的工做流

須要注意初始化 Git 以後默認會在 .git/hooks 目錄下生成全部 Git 鉤子的 Shell 示例腳本,這些腳本是能夠被定製化的。對於前端開發而言去更改這些示例腳本適配前端項目很是不友好(大多數前端開發同窗壓根不會設計 Shell 腳本,儘管這個對於製做工具是一件很是高效的事情),所以社區就出現了相似的加強工具,它們對外拋出的是簡單的鉤子配置(例如 ghookspackage.json 中只須要進行簡單的鉤子屬性配置),而在內部則經過替換 Git 鉤子示例腳本的形式使得外部配置的鉤子能夠被執行,例如 husky、ghooks 以及 pre-commit 等。

舒適提示: Git Hook 還能夠定製腳本執行的語言環境,例如對於前端而言固然但願使用熟悉的 Node 進行腳本設計,此時能夠經過在腳本文件的頭部設置 #! /usr/bin/env node 將 Node 做爲可執行文件的環境解釋器,若是你以前看過 使用 NPM 發佈和使用 CLI 工具 可能會對這個環境解析器相對熟悉,這裏也給出一個使用 Node 解釋器的示例:ghooks - hook.template.raw,ghooks 的實現很是簡單,感興趣的同窗能夠仔細閱讀一些源碼的實現。

介紹 Git Hook 是爲了讓你們清晰的認知到使用 Hook 能夠在前端的工程化項目中作不少事情(原本應該放在 Git Commit Message 中介紹相對合適,可是鑑於那個小節引用了另一篇文章,所以將這個信息放在本小節進行科普)。

以前提到使用 Git Hook 能夠進行 ESLint 規範約束,所以你們其實應該可以猜到使用 pre-commit 鉤子(固然須要藉助 Git Hook 加強工具,本項目中一概選擇 husky)配合 ESLint 能夠進行提交說明前的項目代碼規則校驗,可是若是項目愈來愈大,ESLint 校驗的時間可能愈來愈長,這對於頻繁的代碼提交者而言多是一件相對痛苦的事情,所以能夠藉助 lint-staged 工具(聽這個工具的名字就可以猜想 lint 的是已經放入 Git Stage 暫存區中的代碼,ed 在英文中代表已經作過)減小代碼的檢測量。

Lint Staged 配置

使用 commitlint 工具能夠防止生成不規範的 Git Commit Message,從而阻止用戶進行 Git 代碼提交。可是若是想要防止團隊協做時開發者提交不符合 ESLint 規則的代碼則能夠經過 lint-staged 工具來實現。lint-staged 能夠在用戶提交代碼以前(生成 Git Commit Message 信息以前)使用 ESLint 檢查 Git 暫存區中的代碼信息(git add 以後的修改代碼),一旦存在 💩 同樣不符合校驗規則的代碼,則能夠終止提交行爲。須要注意的是 lint-staged 不會檢查項目的全量代碼(全量使用 ESLint 校驗對於較大的項目可能會是一個相對耗時的過程),而只會檢查添加到 Git 暫存區中的代碼。根據官方文檔執行如下命令自動生成配置項信息:

npx mrm lint-staged
複製代碼

須要注意默認生成的配置文件是針對 JavaScript 環境的,手動修改 package.json 中的配置信息進行 TypeScript 適配:

// 咱們的哈士奇再次上場,此次它是要咬着你的 ESLint 不放了,這裏我簡稱它的動做爲 "咬 💩" ~~~
"husky": {
  "hooks": {
    "pre-commit": "lint-staged"
  }
},
"lint-staged": {
  // 這裏須要注意 ESLint 腳本的 --max-warnings 0
  // 不然就算存在 warning 也不會終止提交行爲
  // 這裏追加了 Prettier 的自動格式化,確保代碼提交以前全部的格式可以修復
  "*.ts": ["npm run lint", "npm run prettier"]
}
複製代碼

此時若是將要提交的代碼有 💩 , 則提交時會提示錯誤信息且提交會被強制終止:

husky > pre-commit (node v12.13.1)
[STARTED] Preparing...
[SUCCESS] Preparing...
[STARTED] Running tasks...
[STARTED] Running tasks for *.ts
[STARTED] npm run lint-strict
[FAILED] npm run lint-strict [FAILED]
[FAILED] npm run lint-strict [FAILED]
[SUCCESS] Running tasks...
[STARTED] Applying modifications...
[SKIPPED] Skipped because of errors from tasks.
[STARTED] Reverting to original state because of errors...
[SUCCESS] Reverting to original state because of errors...
[STARTED] Cleaning up...
[SUCCESS] Cleaning up...

× npm run lint-strict:
ESLint found too many warnings (maximum: 0).
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! algorithms-utils@1.0.0 lint-strict: `eslint src --max-warnings 0 "C:/Code/Git/algorithms/src/greet.ts"`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the algorithms-utils@1.0.0 lint-strict script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\子弈\AppData\Roaming\npm-cache\_logs\2020-07-11T07_25_39_102Z-debug.log

> algorithms-utils@1.0.0 lint-strict C:\Code\Git\algorithms
> eslint src --max-warnings 0 "C:/Code/Git/algorithms/src/greet.ts"


C:\Code\Git\algorithms\src\greet.ts
  2:16  warning  Missing return type on function @typescript-eslint/explicit-module-boundary-types 2:34 warning Argument 'name' should be typed @typescript-eslint/explicit-module-boundary-types ✖ 2 problems (0 errors, 2 warnings) husky > pre-commit hook failed (add --no-verify to bypass) 複製代碼

husky 在 package.json 中配置了 pre-commitcommit-msg 兩個 Git 鉤子,優先使用 pre-commit 鉤子執行 ESLint 校驗,若是校驗失敗則終止運行。若是校驗成功則會繼續執行 commit-msg 校驗 Git Commit Message,例如如下是 ESLint 校驗經過可是 Commit Message 校驗失敗的例子:

PS C:\Code\Git\algorithms> git commit -m "這是一個不符合規範的 Commit Message"
// pre-commit 鉤子 ESLint 校驗經過
husky > pre-commit (node v12.13.1)
[STARTED] Preparing...
[SUCCESS] Preparing...
[STARTED] Running tasks...
[STARTED] Running tasks for *.ts
[STARTED] npm run lint-strict
[SUCCESS] npm run lint-strict
[SUCCESS] Running tasks for *.ts
[SUCCESS] Running tasks...
[STARTED] Applying modifications...
[SUCCESS] Applying modifications...
[STARTED] Cleaning up...
[SUCCESS] Cleaning up...
// commit-msg 鉤子 Git Commit Message 校驗失敗
husky > commit-msg (node v12.13.1)
⧗   input: 這是一個不符合規範的 Commit Message
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]

✖   found 2 problems, 0 warnings
ⓘ   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

husky > commit-msg hook failed (add --no-verify to bypass)
複製代碼

Jest

測試背景

若是對於測試的概念和框架不是特別清楚,這裏推薦一些可查看的文章:

除此以外,若是想了解一些額外的測試技巧,這裏推薦一些社區的最佳實踐:

因爲這裏只是 Node 環境工具庫包的單元測試,在對比了各個測試框架以後決定採用 Jest 進行單元測試:

  • 內置斷言庫可實現開箱即用(從 itexpect, Jest 將整個工具包放在一個地方)
  • Jest 能夠可靠地並行運行測試,而且爲了讓加速測試進程,Jest 會優先運行以前失敗的測試用例
  • 內置覆蓋率報告,無需額外進行配置
  • 優秀的報錯信息

舒適提示:前端測試框架不少,相比簡單的單元測試,e2e 測試會更復雜一些(無論是測試框架的支持以及測試用例的設計)。以前使用過 Karma 測試管理工具配合 Mocha 進行瀏覽器環境測試,也使用過 PhantomJS 以及 Nightwatch(使用的都是皮毛),印象最深入的是使用 testcafe 測試框架(複雜的 API 官方文檔),除此以外若是還感興趣,也能夠了解一下 cypress 測試框架。

Jest 配置

本項目的單元測試主要採用了 Jest 測試框架。Jest 若是須要對 TypeScript 進行支持,能夠經過配合 Babel 的形式,具體可查看 Jest - Using TypeScript,可是採用 Babel 會產生一些限制(具體可查看 Babel 7 or TypeScript)。因爲本項目沒有采用 Babel 進行轉譯,而且但願可以完美支持類型檢查,所以採用 ts-jest 進行單元測試。按照官方教程進行依賴安裝和項目初始化:

npm install --save-dev jest typescript ts-jest @types/jest
npx ts-jest config:init
複製代碼

子啊根目錄的 ject.config.js 文件中進行 Jest 配置修改:

module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
  // 輸出覆蓋信息文件的目錄
  coverageDirectory: "./coverage/",
  // 覆蓋信息的忽略文件模式
  testPathIgnorePatterns: ["<rootDir>/node_modules/"],
  // 若是測試覆蓋率未達到 100%,則測試失敗
  // 這裏可用於預防代碼構建和提交
  coverageThreshold: {
    global: {
      branches: 100,
      functions: 100,
      lines: 100,
      statements: 100,
    },
  },
  // 路徑映射配置,具體可查看 https://kulshekhar.github.io/ts-jest/user/config/#paths-mapping
  // 須要配合 TypeScript 路徑映射,具體可查看:https://www.tslang.cn/docs/handbook/module-resolution.html
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1",
  },
};
複製代碼

須要注意路徑映射也須要配置 tsconfig.json 中的 paths 信息,同時注意將測試代碼包含到 TypeScript 的編譯目錄中。配置完成後在 package.json 中配置測試命令:

"scripts": {
  "lint": "eslint src --max-warnings 0",
  "test": "jest --bail --coverage",
  "build": "npm run lint && npm run jest && rimraf dist types && gulp",
}
複製代碼

須要注意 Jest 中的這些配置信息(更多配置信息可查看 Jest CLI Options):

  • bail 的配置做用相對相似於 ESLint 中的 max-warnings,設置爲 true 則代表一旦發現單元測試用例錯誤則中止運行其他測試用例,從而能夠防止運行用例過多時須要一直等待用例所有運行完畢的狀況。
  • coverage 主要用於在當前根目錄下生成 coverage 代碼的測試覆蓋率報告,該報告還能夠上傳 coveralls 進行 Github 項目的 Badges 顯示。

舒適提示:Jest CLI Options 中的 findRelatedTests 可用於配合 pre-commit 鉤子去運行最少許的單元測試用例,可配合 lint-staged 實現相似於 ESLint 的做用,更多細節可查看 lint-staged - Use environment variables with linting commands

在當前根目錄的 test 目錄下新建 greet.spec.ts 文件,並設計如下測試代碼:

import greet from "@/greet";

describe("src/greet.ts", () => {
  it("name param test", () => {
    expect(greet("world")).toBe("Hello from world 1");
  });
});
複製代碼

舒適提示:測試文件有兩種放置風格,一種是新建 test 文件夾,而後將全部的測試代碼集中在 test 目錄下進行管理,另一種是在各個源碼文件的同級目錄下新建 __test__ 目錄,進行就近測試。大部分的項目可能都會傾向於採用第一種目錄結構(能夠隨便找一些 github 上的開源項目進行查看,這裏 ts-test 則是採用了第二種測試結構)。除此以外,須要注意 Jest 經過配置 testMatchtestRegex 可使得項目識別特定格式文件做爲測試文件進行運行(本項目採用默認配置可識別後綴爲 .spec 的文件進行單元測試)。

Jest 確保構建

單獨經過執行 npm run test 命令進行單元測試,這裏演示執行構建命令時的單元測試(須要保證構建以前全部的單元測試用例都能經過)。若是測試失敗,那麼應該防止繼續構建,例如進行失敗的構建行爲:

PS C:\Code\Git\algorithms> npm run build

> algorithms-utils@1.0.0 build C:\Code\Git\algorithms
> npm run lint-strict && npm run jest && rimraf dist types && gulp


> algorithms-utils@1.0.0 lint-strict C:\Code\Git\algorithms
> eslint src --max-warnings 0


> algorithms-utils@1.0.0 jest C:\Code\Git\algorithms
> jest --coverage

 PASS  dist/test/greet.spec.js
 FAIL  test/greet.spec.ts
  ● src/greet.ts › name param test

    expect(received).toBe(expected) // Object.is equality

    Expected: "Hello from world 1"
    Received: "Hello from world"

      3 | describe("src/greet.ts", () => {
      4 |   it("name param test", () => {
    > 5 |     expect(greet("world")).toBe("Hello from world 1");
        |                            ^
      6 |   });
      7 | });
      8 |

      at Object.<anonymous> (test/greet.spec.ts:5:28)

----------|---------|----------|---------|---------|-------------------
| File       | % Stmts   | % Branch   | % Funcs   | % Lines   | Uncovered Line #s   |
| ---------- | --------- | ---------- | --------- | --------- | ------------------- |
| All files  | 100       | 100        | 100       | 100       |
| greet.ts   | 100       | 100        | 100       | 100       |
| ---------- | --------- | ---------- | --------- | --------- | ------------------- |
Test Suites: 1 failed, 1 passed, 2 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        3.45 s
Ran all test suites.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! algorithms-utils@1.0.0 jest: `jest --coverage`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the algorithms-utils@1.0.0 jest script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\子弈\AppData\Roaming\npm-cache\_logs\2020-07-12T13_42_11_628Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! algorithms-utils@1.0.0 build: `npm run lint-strict && npm run jest && rimraf dist types && gulp`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the algorithms-utils@1.0.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\子弈\AppData\Roaming\npm-cache\_logs\2020-07-12T13_42_11_673Z-debug.log
複製代碼

須要注意因爲是並行(&&)執行腳本,所以執行構建命令時(npm run build)會先執行 ESLint 校驗,若是 ESLint 校驗失敗那麼退出構建,不然繼續進行 Jest 單元測試。若是單元測試失敗那麼退出構建,只有當二者都經過時纔會進行源碼構建。

Jest 確保代碼上傳

除了預防不負責任的代碼構建之外,還須要預防不負責任的代碼提交。配合 lint-staged 能夠防止未跑通單元測試的代碼進行遠程提交:

"scripts": {
  "lint": "eslint src --max-warnings 0",
  "test": "jest --bail --coverage",
},
"lint-staged": {
  "*.ts": [
    "npm run lint",
    "npm run test"
  ]
}
複製代碼

此時若是單元測試有誤,都會中止代碼提交:

husky > pre-commit (node v12.13.1)
[STARTED] Preparing...
[SUCCESS] Preparing...
[STARTED] Running tasks...
[STARTED] Running tasks for *.ts
[STARTED] npm run lint
[SUCCESS] npm run lint
[STARTED] npm run jest
[FAILED] npm run jest [FAILED]
[FAILED] npm run jest [FAILED]
[SUCCESS] Running tasks...
[STARTED] Applying modifications...
[SKIPPED] Skipped because of errors from tasks.
[STARTED] Reverting to original state because of errors...
[SUCCESS] Reverting to original state because of errors...
[STARTED] Cleaning up...
[SUCCESS] Cleaning up...

× npm run jest:
FAIL test/greet.spec.ts
  src/greet.ts
    × name param test (4 ms)

  ● src/greet.ts › name param test

    expect(received).toBe(expected) // Object.is equality

    Expected: "Hello from world 1"
    Received: "Hello from world"

      3 | describe("src/greet.ts", () => {
      4 |   it("name param test", () => {
    > 5 |     expect(greet("world")).toBe("Hello from world 1");
        |                            ^
      6 |   });
      7 | });
      8 |

      at Object.<anonymous> (test/greet.spec.ts:5:28)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        1.339 s, estimated 3 s
Ran all test suites related to files matching /C:\\Code\\Git\\algorithms\\src\\index.ts|C:\\Code\\Git\\algorithms\\test\\greet.spec.ts/i.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! algorithms-utils@1.0.0 jest: `jest --bail --findRelatedTests --coverage "C:/Code/Git/algorithms/src/index.ts" "C:/Code/Git/algorithms/test/greet.spec.ts"`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the algorithms-utils@1.0.0 jest script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\子弈\AppData\Roaming\npm-cache\_logs\2020-07-12T14_33_51_183Z-debug.log

> algorithms-utils@1.0.0 jest C:\Code\Git\algorithms
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the algorithms-utils@1.0.0 jest script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\子弈\AppData\Roaming\npm-cache\_logs\2020-07-12T14_33_51_183Z-debug.log

> algorithms-utils@1.0.0 jest C:\Code\Git\algorithms
> jest --bail --findRelatedTests --coverage "C:/Code/Git/algorithms/src/index.ts" "C:/Code/Git/algorithms/test/greet.spec.ts"

----------|---------|----------|---------|---------|-------------------
| File       | % Stmts   | % Branch   | % Funcs   | % Lines   | Uncovered Line #s   |
| ---------- | --------- | ---------- | --------- | --------- | ------------------- |
| All files  | 0         | 0          | 0         | 0         |
| ---------- | --------- | ---------- | --------- | --------- | ------------------- |
husky > pre-commit hook failed (add --no-verify to bypass)
git exited with error code 1
複製代碼

舒適提示:想要了解更多關於 Jest 的生態能夠查看 awesome-jest

Jest 對於 ESLint 支持

src 目錄下的源碼經過配置 @typescript-eslint/eslint-plugin 可進行推薦規則的 ESLint 校驗,爲了使得 test 目錄下的測試代碼可以進行符合 Jest 推薦規則的 ESLint 校驗,能夠經過配置 eslint-plugin-jest 進行支持(ts-jest 項目就是採用了該插件進行 ESLint 校驗,具體可查看配置文件 ts-jest/.eslintrc.js),這裏仍然採用推薦的規則配置:

module.exports = {
  root: true,
  parser: "@typescript-eslint/parser",
  plugins: ["@typescript-eslint"],
  extends: [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    // 新增推薦的 ESLint 校驗規則
    // 全部規則集查看:https://github.com/jest-community/eslint-plugin-jest#rules(recommended 標識代表是推薦規則)
    "plugin:jest/recommended",
  ],
};
複製代碼

爲了驗證推薦規則是否生效,這裏能夠找一個 no-identical-title 規則進行驗證:

import greet from "@/greet";
describe("src/greet.ts", () => {
  it("name param test", () => {
    expect(greet("world")).toBe("Hello from world 1");
  });
});

// 這裏輸入了重複的 title
describe("src/greet.ts", () => {
  it("name param test", () => {
    expect(greet("world")).toBe("Hello from world 1");
  });
});
複製代碼

須要注意修改 package.json 中的 ESLint 校驗範圍:

"scripts": {
  // 這裏對 src 和 test 目錄進行 ESLint 校驗
  "lint": "eslint src test --max-warnings 0",
},
複製代碼

執行 npm run lint 進行單元測試的格式校驗:

PS C:\Code\Git\algorithms> npm run lint

> algorithms-utils@1.0.0 lint C:\Code\Git\algorithms
> eslint src test --max-warnings 0


C:\Code\Git\algorithms\test\greet.spec.ts
  9:10  error  Describe block title is used multiple times in the same describe block  jest/no-identical-title

✖ 1 problem (1 error, 0 warnings)

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! algorithms-utils@1.0.0 lint: `eslint src test --max-warnings 0`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the algorithms-utils@1.0.0 lint script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\子弈\AppData\Roaming\npm-cache\_logs\2020-07-13T02_25_12_043Z-debug.log
複製代碼

此時會發現 ESLint 拋出了相應的錯誤信息。須要注意採用此 ESLint 校驗以後也會在 VS Code 中實時生成錯誤提示(相應的代碼下會有紅色波浪線,鼠標移入後會產生 Tooltip 提示該錯誤的相應規則信息,除此以外當前工程目錄下對應的文件名也會變成紅色),此後的 Git 提交以及 Build 構建都會失敗

舒適提示:若是你但願 Jest 測試的代碼須要一些格式規範,那麼能夠查看 eslint-plugin-jest-formatting 插件。

Npm Script Hook

當你查看前端開源項目時第一時間可能會找 package.json 中的 mainbin 以及 files 等字段信息,除此以外若是還想深刻了解項目的結構,可能還會查看 scripts 腳本字段信息用於瞭解項目的開發、構建、測試以及安裝等流程。npm 的腳本功能很是強大,你能夠利用腳本製做項目須要的任何流程工具。本文不會過多介紹 npm 腳本的功能,只是講解一下其中用到的 鉤子 功能。

目前在本項目中使用的一些腳本命令以下(就目前而言腳本相對較少,定義還蠻清晰的):

"lint": "eslint src test --max-warnings 0",
"test": "jest --bail --coverage",
"build": "npm run lint && npm run prettier && npm run test && rimraf dist types && gulp",
"changelog": "rimraf CHANGELOG.md && conventional-changelog -p angular -i CHANGELOG.md -s"
複製代碼

重點看下 build 腳本命令,會發現這個腳本命令包含了大量的繼發執行腳本,但真正和 build 相關的只有 rimraf dist types && gulp 這兩個腳本。這裏經過 npm 的腳本鉤子 prepost 將腳本的功能區分開,從而使腳本的語義更加清晰(固然腳本愈來愈多的時候也可能容易增長開發者的認知負擔)。npm 除了指定一些特殊的腳本鉤子之外(例如 prepublishpostpublishpreinstallpostinstall等),還能夠對任意腳本增長 prepost 鉤子,這裏經過自定義鉤子將併發執行的腳本進行簡化:

"lint": "eslint src test --max-warnings 0",
"test": "jest --bail --coverage",
"prebuild": "npm run lint && npm run prettier && npm run test",
"build": "rimraf dist types && gulp",
"changelog": "rimraf CHANGELOG.md && conventional-changelog -p angular -i CHANGELOG.md -s"
複製代碼

此時若是執行 npm run build 命令時事實上相似於執行了如下命令:

npm run prebuild && npm run build
複製代碼

以後設計的腳本若是繼發執行繁多,那麼都會採用 npm scripts hook 進行設計。

舒適提示:你們可能會奇怪什麼地方須要相似於 preinstallpreuninstall 這樣的鉤子,例如查看 husky - package.json,husky 在安裝的時候由於要植入 Git Hook 腳本從而帶來了一些反作用(此時固然能夠經過 preinstall 觸發 Git Hook 腳本植入的邏輯)。若是不想使用 husky,那麼卸載後須要清除植入的腳本從而不妨礙原有的 Git Hook 功能。 固然若是想要了解更多關於 npm 腳本的信息,能夠查看 npm-scriptsnpm scripts 使用指南

Vuepress

Vuepress 背景

通常組件庫或工具庫都須要設計一個演示文檔(提供良好的開發體驗)。通常的工具庫能夠採用 tsdocjsdocesdoc 等工具進行 API 文檔的自動生成,但每每須要符合一些註釋規範,這些註釋規範在某種程度上可能會帶來開發負擔,固然也能夠交給 VS Code 的插件進行一鍵生成,例如 Document This For jsdocTSDoc Comment

組件庫 Element UI 採用 vue-markdown-loader(Convert Markdown file to Vue Component using markdown-it) 進行組件的 Demo 演示設計,可是配置相對複雜。更簡單的方式是配合 Vuepress 進行設計,它的功能很是強大,但前提是熟悉 Vue,由於能夠在 Markdown 中使用 Vue 語法。固然若是是 React 組件庫的 Demo 演示,則能夠採用 dumi 生成組件 Demo 演示文檔(不知道沒有更加好用的類 Vuepress 的 React 組件文檔生成器, 更多和 React 文檔相關也能夠了解 react-markdownreact-static 等)。

因爲以前採用過 Vuepress 設計 Vue 組件庫的 Demo 演示文檔,所以這裏仍然沿用它來設計工具庫包的 API 文檔(若是你想自動生成 API 文檔,也能夠額外配合 tsdoc 工具)。採用 Vuepress 設計文檔的主要特色以下:

  • 能夠在 Markdown 中直接使用 Vue(還能夠自定義 Vue 文檔視圖組件)
  • 內置了不少 Markdown 拓展
  • 可使用 Webpack 進行構建定製化配置
  • 默認主題支持搜索能力
  • 能夠安裝 Vuepress 插件(後續須要支持的 Latex 排版就能夠利用現有的插件能力生成)
  • 默認響應式

Vuepress 配置

先按照官方的 快速上手 文檔進行依賴安裝和 npm scripts 腳本設置:

"scripts": {
  "docs:dev": "vuepress dev docs",
  "docs:build": "vuepress build docs"
}
複製代碼

按照 Vuepress 官網約定優於配置的原則進行演示文檔的目錄結構設計,官方的文檔可能一會兒難以理解,能夠先設計一個最簡單的目錄:

.
├── docs
│   ├── .vuepress
│   │   └── config.js       # 配置文件
│   └── README.md           # 文檔首頁
└── package.json
複製代碼

根據默認主題 / 首頁docs/README.md 進行首頁設計:

---
home: true
# heroImage: /hero.png
heroText: algorithms-utils
tagline: 算法與 TypeScript 實現
actionText: 開始學習
actionLink: /guide/
features:
  - title: 精簡理論
    details: 精簡《算法導論》的內容,幫助本身更容易學習算法理論知識。
  - title: 習題練習
    details: 解答《算法導論》的習題,幫助本身更好的實踐算法理論知識。
  - title: 面題精選
    details: 蒐集常見的面試題目,提高本身的算法編程能力以及面試經過率。
footer: MIT Licensed | Copyright © 2020-present 子弈
---
複製代碼

根據配置docs/.vuepress/config.js 文件進行基本配置:

const packageJson = require("../../package.json");

module.exports = {
  // 配置網站標題
  title: packageJson.name,
  // 配置網站描述
  description: packageJson.description,
  // 配置基本路徑
  base: "/algorithms/",
  // 配置基本端口
  port: "8080",
};
複製代碼

此時經過 npm run docs:dev 進行開發態文檔預覽:

PS C:\Code\Git\algorithms> npm run docs:dev

> algorithms-utils@1.0.0 docs:dev C:\Code\Git\algorithms
> vuepress dev docs

wait Extracting site metadata...
tip Apply theme @vuepress/theme-default ...
tip Apply plugin container (i.e. "vuepress-plugin-container") ...
tip Apply plugin @vuepress/register-components (i.e. "@vuepress/plugin-register-components") ...
tip Apply plugin @vuepress/active-header-links (i.e. "@vuepress/plugin-active-header-links") ...
tip Apply plugin @vuepress/search (i.e. "@vuepress/plugin-search") ...
tip Apply plugin @vuepress/nprogress (i.e. "@vuepress/plugin-nprogress") ...

√ Client
  Compiled successfully in 5.31s

i 「wds」: Project is running at http://0.0.0.0:8080/
i 「wds」: webpack output is served from /algorithms-utils/
i 「wds」: Content not from webpack is served from C:\Code\Git\algorithms\docs\.vuepress\public
i 「wds」: 404s will fallback to /index.html
success [23:13:14] Build 10b15a finished in 5311 ms!
> VuePress dev server listening at http://localhost:8080/algorithms-utils/
複製代碼

效果以下:

固然除了以上設計的首頁,在本項目中還會設計導航欄側邊欄、使用插件使用組件等。這裏重點講解一下 Webpack 構建 配置。

爲了在 Markdown 文檔中可使用 src 目錄的 TypeScript 代碼,這裏對 .vuepress/config.js 文件進行配置處理:

const packageJson = require("../../package.json");
const sidebar = require("./config/sidebar.js");
const nav = require("./config/nav.js");
const path = require("path");

module.exports = {
  title: packageJson.name,
  description: packageJson.description,
  base: "/algorithms/",
  port: "8080",

  themeConfig: {
    nav,
    sidebar,
  },

  plugins: [
    "vuepress-plugin-cat",
    [
      "mathjax",
      {
        target: "svg",
        macros: {
          "*": "\\times",
        },
      },
    ],
    // 增長 Markdown 文檔對於 TypeScript 語法的支持
    [
      "vuepress-plugin-typescript",
      {
        tsLoaderOptions: {
          // ts-loader 的全部配置項
        },
      },
    ],
  ],

  chainWebpack: (config) => {
    config.resolve.alias.set("image", path.resolve(__dirname, "public"));

    // 在文檔中模擬庫包的引入方式
    // 例如發佈了 algorithms-utils 庫包以後,
    // import greet from 'algorithms-utils/greet.ts' 在 Vuepress 演示文檔中等同於
    // import greet from '~/src/greet.ts',
    // 其中 ~ 在這裏只是表示項目根目錄
    config.resolve.alias.set(
      "algorithms-utils",
      path.resolve(__dirname, "../../src")
    );
  },
};
複製代碼

舒適提示:這裏的 Webpack 配置採用了 webpack-chain 鏈式操做,若是想要採用 Webpack 對象的配置方式則能夠查看 Vuepress - 構建流程 - configurewebpack

此時能夠在 Vuepress 的 Markdown 文檔中進行 TypeScript 引入的演示文檔設計:

# Test vuepress

::: danger 測試 Vuepress
引入 greet.ts 並進行調用測試。
:::

<template> <collapse title="查看答案">{{msg}}</collapse> </template>

<template> <div>{{msg}}</div> </template>

<script lang="ts"> import greet from 'algorithms-utils/greet' const msg = greet('ziyi') export default { data() { return { msg } }, } </script>

複製代碼

啓動 Vuepress 查看演示文檔:

能夠發如今 Markdown 中引入的 src/greet.ts 代碼生效了,最終經過 npm run docs:build 能夠生成演示文檔的靜態資源進行部署和訪問。

舒適提示:更多本項目的 Vuepress 配置信息可查看 Commit 信息,除此以外若是還想知道更多 Vuepress 的生態,例若有哪些有趣插件或主題,可查看 awesome-vuepressVuepress 社區

文檔工具和規範

一般在書寫文檔的時候不少同窗都不注重文檔的潔癖,其實書寫文檔和書寫代碼同樣須要一些格式規範。markdownlint 是相似於 ESLint 的 Markdown 格式校驗工具,經過它能夠更好的規範咱們書寫的文檔。固然 Markdown 的格式校驗不須要像 ESLint 或者 Prettier 校驗那樣進行強約束,簡單的可以作到提示和 Save Auto Fix 便可。

經過安裝 Vs Code 插件 markdownlint 並進行 Save Auto Fix 配置(在插件中明確列出了哪些規則是能夠被 Fix 的)。安裝完成後查看剛剛進行的測試文件:

此時會發現插件生效了,可是在 Markdown 中插入 html 是必須的一個能力(Vuepress 支持的能力就是在 Markdown 中使用 Vue),所以能夠經過 .markdownlintrc 文件將相應的規則屏蔽掉。

舒適提示:若是你但願在代碼提交以前或文檔構建以前可以進行 Markdown 格式校驗,則能夠嘗試它的命令行接口 markdownlint-cli。除此以外,若是對文檔的設計沒有想法或者不清楚如何書寫好的技術文檔,能夠查看 技術文章的寫做技巧分享,必定能讓你有所收穫。

Github Actions

CI / CD 背景

前提提示:我的對於 CI / CD 可能相對不夠熟悉,只是簡單的玩過 Travis、Gitlab CI / CD 以及 Jenkins。

關於 CI / CD 的背景這裏就再也不過多介紹,有興趣的同窗能夠看看如下一些好文:

Introduction to CI/CD with GitLab(中文版) 中你能夠清晰的瞭解到 CI 和 CD 的職責功能:

經過如下圖能夠更清晰的發現 Gitlab 在每一個階段可用的功能:

因爲本項目依賴 Github,所以無法使用 Gitlab 默認集成的能力。以前的 Github 項目採用了 Travis 進行項目的 CI / CD 集成,如今由於有了更方便的 Github Actions,所以決定採用 Github 自帶的 Actions 進行 CI / CD 能力集成(你們若是想更多瞭解這些 CI / CD 的差別請自行 Google 哈)。Github Actions 所帶來的好處在於:

  • 可複用的 Actions(之前你須要寫複雜的腳本,如今能夠複用別人寫好的腳本,能夠簡單理解爲 CI 腳本插件化)
  • 支持更多的 webhook,這些固然是 Github 生態特有的競爭力

固然也會產生一些限制,這些限制主要是和執行時間以及次數相關。須要注意相似於 Jenkins 等支持本地鏈接運行,Github Actions 也支持鏈接到本地機器運行 workflow,所以部分限制可能不受本地運行的限制。

舒適提示:本項目中使用到的 CI / CD 功能相對簡單,若是想了解更多通用的 Actions,可查看 官方 Actionsawesome-actions。最近在使用 Jenkins 作前端的自動化構建優化,後續可能會出一篇簡單的教程文章(固然會跟普通講解的用法會有所不一樣嘍)。

Github Actions 配置

本項目的配置可能會包含如下三個方面:

  • 自動更新靜態資源流程
  • 發佈庫包流程
  • 提交 Pull Request 流程

這裏主要講解自動更新靜態資源流程,大體須要分爲如下幾個步驟(如下都是在 Github 服務器上進行操做,你能夠理解爲新的服務環境):

  • 拉取當前 Github 倉庫代碼並切換到相應的分支
  • 安裝 Node 和 Npm 環境
  • 安裝項目的依賴
  • 構建庫包和演示文檔的靜態資源
  • 發佈演示文檔的靜態資源

經過查看 官方 Actionsawesome-actions,找到所需的 Actions:

  • Checkout: 從 Github 拉取倉庫代碼到 Github 服務器的 $GITHUB_WORKSPACE 目錄下
  • cache: 緩存 npm
  • setup-node: 安裝 Node 和 Npm 環境
  • actions-gh-pages: 在 Github 上發佈靜態資源

舒適提示:可用的 Action 不少,這裏只是設置了一個簡單的流程。

.github/workflows 下新增 mian.yml 配置文件:

# 如下都是官方文檔的簡單翻譯
# 當前的 yml(.yaml) 文件是一個 workflow,是持續集成一次運行的一個過程,必須放置在項目的 .github/workflow 目錄下
# 若是不清楚 .yml 文件格式語法,能夠查看 https://www.codeproject.com/Articles/1214409/Learn-YAML-in-five-minutes
# 初次編寫不免會產生格式問題,可使用 VS Code 插件進行格式檢測,https://marketplace.visualstudio.com/items?itemName=OmarTawfik.github-actions-vscode

# 具體各個配置屬性可查看 https: //docs.github.com/en/actions/reference/workflow-syntax-for-github-actions

# workflow 的執行仍然會受到一些限制,例如
# - 每一個 job 最多執行 6 小時(本地機器不受限制)
# - 每一個 workflow 最多執行 72 小時
# - 併發 job 的數量會受到限制
# - 更多查看 https: //docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#usage-limits

# name: 當前 workflow 的名稱
name: Algorithms

# on: 指定 workflow 觸發的 event
#
# event 有如下幾種類型
# - webhook
# - scheduled
# - manual
on:
  # push: 一個 webhook event,用於提交代碼時觸發 workflow,也能夠是觸發列表,例如 [push, pull_request]

  # workflows 觸發的 event 大部分是基於 webhook 配置,如下列舉幾個常見的 webhook:
  # - delete: 刪除一個 branch 或 tag 時觸發
  # - fork / watch: 某人 fork / watch 項目時觸發(你問有什麼用,發送郵件通知不香嗎?)
  # - pull_request: 提交 PR 時觸發
  # - page_build: 提交 Github Pages-enabled 分支代碼時觸發
  # - push: 提交代碼到特定分支時觸發
  # - registry_package: 發佈或跟新 package 時觸發
  # 更多 webhook 可查看 https: //docs.github.com/en/actions/reference/events-that-trigger-workflows
  # 從這裏能夠看出 Git Actions 的一大特色就是 Gihub 官方提供的一系列 webhook
  push:
    # branches: 指定 push 觸發的特定分支,這裏你能夠經過列表的形式指定多個分支
    branches:
      - feat/framework
    #
    # branches 的指定能夠是通配符類型,例如如下配置能夠匹配 refs/heads/releases/10
    # - 'releases/**'
    #
    # branches 也可使用反向匹配,例如如下不會匹配 refs/heads/releases/10
    # - '!releases/**'
    #
    # branches-ignore: 只對 [push, pull_request] 兩個 webhook 起做用,用於指定當前 webhook 不觸發的分支
    # 須要注意在同一個 webhook 中不能和 branches 同時使用
    #
    # tags: 只對 [push, pull_request] 兩個 webhook 起做用,用於指定當前 webhook 觸發的 tag
    #
    # tags:
    # - v1 # Push events to v1 tag
    # - v1.* # Push events to v1.0, v1.1, and v1.9 tags
    #
    # tags-ignore: 相似於 branches-ignore
    #
    # paths、paths-ignore...
    #
    # 更多關於特定過濾模式可查看 https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#filter-pattern-cheat-sheet
    #
    # 其餘的 webhook 控制項還包括 types(不是全部的 webhook 都有 types),例如已 issues 爲例,能夠在 issues 被 open、reopened、closed 等狀況下觸發 workflow
    # 更多 webhook 的 types 可查看 https: //docs.github.com/en/actions/reference/events-that-trigger-workflows#webhook-events
    #
    # on:
    # issues:
    # types: [opened, edited, closed]

  # 除此以外若是對於每一個分支有不一樣的 webhook 觸發,則能夠經過如下形式進行多個 webhook 配置
  #
  # push:
  # branches:
  # - master
  # pull_request:
  # branches:
  # - dev
  #
  # 除了以上所說的 webhook event,還有 scheduled event 和 manual event
  # scheduled event: 用於定時構建,例如最小的時間間隔是 5 min 構建一次
  # 具體可查看 https: //docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events

# env: 指定環境變量(全部的 job 生效,每個 job 能夠獨立經過 jobs.<job_id>.env、jobs.<job_id>.steps.env 配置)
# defaults / defaults.run: 全部的 job 生效,每個 job 能夠獨立經過 jobs.<job_id>.defaults 配置
# deafults
# defaults.run

# jobs: 一個 workflow 由一個或多個 job 組成
jobs:
  # job id: 是 job 的惟一標識,能夠經過 _ 進行鏈接,例如: my_first_job,例如這裏的 build 就是一個 job id
  build_and_deploy:
    # name: 在 Github 中顯示的 job 名稱
    name: Build And Deploy
    #
    # needs: 用於繼發執行 job,例如當前 job build 必須在 job1 和 job2 都執行成功的基礎上執行
    # needs: [job1, job2]
    #
    # runs-on: job 運行的環境配置,包括:
    # - windows-latest
    # - windows-2019
    # - ubuntu-20.04
    # - ubuntu-latest
    # - ubuntu-18.04
    # - ubuntu-16.04
    # - macos-latest
    # - macos-10.15
    # - self-hosted(本地機器,具體可查看 https: //docs.github.com/en/actions/hosting-your-own-runners/using-self-hosted-runners-in-a-workflow)
    runs-on: ubuntu-latest
    #
    # outputs: 用於輸出信息
    #
    # env: 用於設置環境變量
    #
    # defaults: 當前全部 step 的默認配置
    #
    # defaults.run

    # if: 知足條件執行當前 job

    # steps: 一個 job 由多個 step 組成,step 能夠
    # - 執行一系列 tasks
    # - 執行命令
    # - 執行 action
    # - 執行公共的 repository
    # - 在 Docker registry 中的 action
    steps:
      #
      # id: 相似於 job id
      #
      # if: 相似於 job if
      #
      # name: 當前 step 的名字
      - name: Checkout
        #
        # uses: 用於執行 action
        #
        # action: 能夠重複使用的單元代碼
        # - 爲了 workflow 的安全和穩定建議指定 action 的發佈版本或 commit SHA
        # - 使用指定 action 的 major 版本,這樣能夠容許你接收 fixs 以及 安全補丁並同時保持兼容性
        # - 儘可能不建議使用 master 版本,由於 master 頗有可能會被髮布新的 major 版本從而破壞了 action 的兼容性
        # - action 多是 JavaScript 文件或 Docker 容器,若是是 Docker 容器,那麼 runs-on 必須指定 Linux 環境
        #
        # 指定固定 commit SHA
        # uses: actions/setup-node@74bc508
        # 指定一個 major 發佈版本
        # uses: actions/setup-node@v1
        # 指定一個 minor 發佈版本
        # uses: actions/setup-node@v1.2
        # 指定一個分支
        # uses: actions/setup-node@master
        # 指定一個 Github 倉庫子目錄的特定分支、ref 或 SHA
        # uses: actions/aws/ec2@master
        # 指定當前倉庫所在 workflows 的目錄地址
        # uses: ./.github/actions/my-action
        # 指定在 Dock Hub 發佈的 Docker 鏡像地址
        # uses: docker: //alpine: 3.8
        # A Docker image in a public registry
        # uses: docker: //gcr.io/cloud-builders/gradle

        # checkout action 主要用於向 github 倉庫拉取源代碼(須要注意 workflow 是運行在服務器上,所以須要向當前 github 拉取倉庫源代碼)
        # 它的功能包括但不限於
        # - Fetch all history for all tags and branches
        # - Checkout a different branch
        # - Checkout HEAD^
        # - Checkout multiple repos (side by side)
        # - Checkout multiple repos (nested)
        # - Checkout multiple repos (private)
        # - Checkout pull request HEAD commit instead of merge commit
        # - Checkout pull request on closed event
        # - Push a commit using the built-in token

        # checkout action: https: //github.com/actions/checkout
        uses: actions/checkout@v2
        # with: action 提供的輸入參數
        with:
          # 指定 checkout 的分支、tag 或 SHA
          # 更多 checkout action 的配置可查看 https: //github.com/actions/checkout#usage
          ref: feat/ci
        # args: 用於 Docker 容器的 CMD 指令參數
        # entrypoint: Docker 容器 action(覆蓋 Dockerfile 的 ENTRYPOINT) 和 JavaScript action 均可以使用
      #
      # run: 使用當前的操做系統的默認的 non-login shell 執行命令行程序
      # 運行單個腳本
      # run: npm install
      # 運行多個腳本
      # run: |
      # npm ci
      # npm run build
      #
      # working-directory: 用於指定當前腳本運行的目錄
      # working-directory: ./temp
      #
      # shell: 能夠指定 shell 類型進行執行,例如 bash、pwsh、python、sh、cmd、powershell
      # shell: bash
      #
      # env: 除了能夠設置 workflow 以及 job 的 env,也能夠設置 step 的 env(能夠理解爲做用域不一樣,局部做用域的優先級更高)
      #
      # comtinue-on-error: 默認當前 step 失敗則會阻止當前 job 繼續執行,設置 true 時當前 step 失敗則能夠跳過當前 job 的執行

      - name: Cache
        # cache action: https://github.com/actions/cache
        # cache 在這裏主要用於緩存 npm,提高構建速率
        uses: actions/cache@v2
        # npm 緩存的路徑可查看 https://docs.npmjs.com/cli/cache#cache
        # 因爲這裏 runs-on 是 ubuntu-latest,所以配置 ~/.npm
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: | ${{ runner.os }}-node-       # github-script action: https://github.com/actions/github-script
      # 在 workflow 中使用 Script 語法調用 Github API 或引用 workflow context

      # setup-node action: https://github.com/actions/setup-node
      # 配置 Node 執行環境(當前構建的服務器默認沒有 Node 環境,能夠經過 Action 安裝 Node)
      # 須要注意安裝 Node 的同時會捆綁安裝 npm,若是想了解爲何會捆綁,能夠 Google 一下有趣的故事哦
      # 所以使用了該 action 後就可使用 npm 的腳本在服務器進行執行啦
      # 這裏也能夠嘗試 v2-beta 版本哦
      - name: Set Node
        uses: actions/setup-node@v1
        with:
          # 也能夠經過 strategy.matrix.node 進行靈活配置
          # 這裏本地使用 node 的 12 版本構建,所以這裏就進行版本固定啦
          node-version: "12"

      - run: npm install
      - run: npm run build
      - run: npm run docs:build

      - name: Deploy
        # 用於發佈靜態站點資源
        # actions-gh-pages action: https://github.com/peaceiris/actions-gh-pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          # GTIHUB_TOKEN:https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token
          # Github 會在 workflow 中自動生成 GIHUBT_TOKEN,用於認證 workflow 的運行
          github_token: ${{ secrets.GITHUB_TOKEN }}
          # 靜態資源目錄設置
          publish_dir: ./docs/.vuepress/dist
          # 默認發佈到 gh-pages 分支上,能夠指定特定的發佈分支
          publish_branch: gh-pages1 # default: gh-pages
          full_commit_message: ${{ github.event.head_commit.message }}
    #
    # timeout-minutes: 一個 job 執行的最大時間,默認是 6h,若是超過期間則取消執行
    #
    # strategy.matrix: 例如指定當前 job 的 node 版本列表、操做系統類型列表等
    # strategy.fail-fast
    # strategy.max-parallel
    # continue-on-error: 一旦當前 job 執行失敗,那麼 workflow 中止執行。設置爲 true 能夠跳過當前 job 執行
    # container: Docker 容器配置,包括 image、env、ports、volumes、options 等配置
    #
    # services: 使用 Docker 容器 Action 或者 服務 Action 必須使用 Linux 環境運行
複製代碼

舒適提示:這裏再也不敘述具體的配置過程,更多可查看配置文件中貼出的連接信息。

上傳 CI 的配置文件後,Github 就會進行自動構建,具體以下:

正在構建或者構建完成後可查看每一個構建的信息,若是初次構建失敗則能夠經過構建信息找出失敗緣由,並從新修改構建配置嘗試再次構建。除此以外,每次構建失敗 Github 都會經過郵件的形式進行通知:

若是構建成功,則每次你推送新的代碼後,Github 服務會進行一系列流程並自動更新靜態資源站點。

總結

但願你們看完這篇文檔以後若是想使用其中某些工具可以養成如下一些習慣:

  • 通篇閱讀工具的文檔,瞭解相同功能的不一樣工具的差別點

通篇閱讀工具對應的官方 Github README 文檔以及官方站點文檔,瞭解該工具設計的核心哲學、核心功能、解決什麼核心問題。前端的工具百花齊放,一樣的功能可能能夠採用多種不一樣的工具實現。若是想要在項目中使用適當的工具,就得知道這些工具的差別。完整的閱讀相應的官方文檔,有助於你理解各自的核心功能和差別。

  • 在調研了各個工具的差別以後,選擇認爲合適的工具進行實踐

在實踐的過程當中你會對該工具的使用愈來愈熟悉。此時若是遇到一些問題或者想要實現某些功能,在通篇閱讀文檔的基礎上會變得相對容易。固然若是遇到一些報錯信息沒法解決,此時第一時間應該是搜索當前工具所對應的 Github Issues。除此以外,你也能夠根據錯誤的堆棧信息追蹤工具的源碼,瞭解源碼以後可能會對錯誤信息產生的緣由更加清晰。

  • 在完成以上兩步以後,你應該總結工具的使用技巧啦,此時在此通讀工具文檔可能會產生不同的收穫

連接文檔

相關文章
相關標籤/搜索