前言
自己重新搭建了一套前端項(xiàng)目架構(gòu) 基于 lerna yarn 的 monrepo的倉(cāng)庫(kù), 主要是后面會(huì)學(xué)習(xí)輸出的一些東西, 整個(gè)架子先搭建起來(lái)。
- 2d 和 3d 公共 util 的封裝
- 個(gè)人 npm 包的發(fā)布 (rollup)
- 2d React 項(xiàng)目 搭建(vite)
- 3d react 項(xiàng)目 搭建 (webpack)
- 搭建一套基于webpack 5 的cli
每個(gè)項(xiàng)目都有一些特定的依賴, 但是也會(huì)有一些相同的依賴。比如eslint、 babel 的一些基礎(chǔ)配置,或者一些通用的腳本文件。讀完本篇文章你可以學(xué)到 從0 到 1 搭建 monorepo 前端工程化項(xiàng)目 如下圖所示:
項(xiàng)目架構(gòu)圖
為什么使用monorepo
monorepo 是一種將多個(gè)項(xiàng)目代碼存儲(chǔ)在一個(gè)倉(cāng)庫(kù)里的軟件開(kāi)發(fā)策略("mono" 來(lái)源于希臘語(yǔ) μ?νο? 意味單個(gè)的,而 "repo",顯而易見(jiàn)地,是 repository 的縮寫(xiě))。將不同的項(xiàng)目的代碼放在同一個(gè)代碼倉(cāng)庫(kù)中,這種「把雞蛋放在同一個(gè)籃子里」的做法可能乍看之下有些奇怪,但實(shí)際上,這種代碼管理方式有很多好處,無(wú)論是世界一流的互聯(lián)網(wǎng)企業(yè) Google,Facebook,還是社區(qū)知名的開(kāi)源項(xiàng)目團(tuán)隊(duì) Babe、都使用了 monorepo 策略管理他們的代碼。這是Taro 的官方源碼庫(kù):
taro
至于他的優(yōu)點(diǎn)如下:
- 代碼重用將變得非常容易:由于所有的項(xiàng)目代碼都集中于一個(gè)代碼倉(cāng)庫(kù),我們將很容易抽離出各個(gè)項(xiàng)目共用的業(yè)務(wù)組件或工具,并通過(guò) Typescript,Lerna 或其他工具進(jìn)行代碼內(nèi)引用;
- 賴管理將變得非常簡(jiǎn)單, 可以輕松的做到版本依賴管理 和版本號(hào)自動(dòng)升級(jí)
- 發(fā)布npm 包 也很特別簡(jiǎn)單, 提取公共方法 直接公共包,可以快速發(fā)布到npm 上
- 還有一個(gè) 最大的 優(yōu)點(diǎn) 就是 避免重復(fù)安裝包, 減少的磁盤(pán)空間, 降低了構(gòu)建時(shí)間
這兩項(xiàng)好處全部都可以由一個(gè)成熟的包管理工具來(lái)完成,對(duì)前端開(kāi)發(fā)而言,即是 yarn(1.0 以上)或 npm(7.0 以上)通過(guò)名為 workspaces 的特性實(shí)現(xiàn)的(?? 注意:支持 workspaces 特性的 npm 目前依舊不是 LTS 版本)。
yarn
這里的話 我們?nèi)职惭b yarn
npm install yarn -g
然后新建一個(gè)文件夾 進(jìn)入到目錄中執(zhí)行
yarn init
會(huì)在項(xiàng)目的根目錄生成 package.json
這時(shí)候我們?cè)陧?xiàng)目根目錄
新建packages 目錄
在package.json 新增下面字段 workspace
{ "name": "yarn-test", "version": "1.0.0", "private": true, "workspaces": [ "packages/*" ], "main": "index.js", "license": "MIT"}
表示工作區(qū)是packages 下的所有子目錄,
private: true 表示項(xiàng)目的根目錄 不會(huì)被發(fā)布出去
假設(shè)項(xiàng)目中有foo和bar兩個(gè)package:
mono-demo/|--package.json|--packages/| |--foo/| | |--package.json| |--bar/| | |--package.json
yarn workspace <workspace_name>
在指定的package中運(yùn)行指定的命令。
# 在foo中添加react,react-dom作為devDependenciesyarn workspace foo add react react-dom --dev# 移除bar中的lodash依賴yarn workspace bar remove lodash# 運(yùn)行bar中package.json的 scripts.test 命令yarn workspace bar run test
yarn workspaces run
在所有package中運(yùn)行指定的命令,若某個(gè)package中沒(méi)有對(duì)應(yīng)的命令則會(huì)報(bào)錯(cuò)。
# 運(yùn)行所有package(foo、bar)中package.json的 scripts.build 命令yarn workspaces run build
yarn workspaces info [–json]
查看項(xiàng)目中的workspace依賴樹(shù)。
例如我的bar依賴了foo,如下:
// bar/package.json{ "name": "bar", "version": "1.0.0", "dependencies": { "foo": "^1.0.0" }}
在項(xiàng)目中的依賴結(jié)構(gòu)是這樣的(假設(shè)foo/package.json的版本匹配bar的依賴版本,否則會(huì)另外安裝一個(gè)匹配的foo):
/package.json/yarn.lock/node_modules/node_modules/foo -> /packages/foo/packages/foo/package.json/packages/bar/package.json
那么運(yùn)行yarn workspaces info會(huì)得到如下輸出:
yarn workspaces { "bar": { "location": "packages/bar", "workspaceDependencies": [ "foo" ], "mismatchedWorkspaceDependencies": [] }, "foo": { "location": "packages/foo", "workspaceDependencies": [], "mismatchedWorkspaceDependencies": [] }}
比如我的一些依賴是所有package 通用的 比如 eslint、babel… 我們就使用下面的這個(gè)命令 加一個(gè) -W 就可以了
yarn <add|remove>-W
- -W: –ignore-workspace-root-check ,允許依賴被安裝在workspace的根目錄
管理根目錄的依賴。
# 安裝eslint作為根目錄的devDependenciesyarn add eslint -D -W
lerna
**Lerna**是社區(qū)主流的monorepo管理工具之一,集成了依賴管理、版本發(fā)布管理等功能。
使用Learn管理的項(xiàng)目的目錄結(jié)構(gòu)和yarn workspace類(lèi)似。
我們根目錄安裝
yarn add lerna -D -W
然后執(zhí)行
npx lerna init
然后項(xiàng)目中就會(huì)生成lerna.json
我們進(jìn)行下面配置
{ "packages": ["packages/*"], "command": { "run": { "npmClient": "yarn" }, "publish": { "ignoreChanges": ["ignored-file", "*.md"], "message": "chore(release): publish", "registry": "https://npm.pkg.github.com" } }, "version": "independent", "useWorkspaces": true, "npmClient": "yarn"}
這里 同樣使用 workspace, 指定項(xiàng)目 使用yarn 進(jìn)行包管理
這里有一個(gè)很重要的字段 "version": "independent",
這是表示使用 獨(dú)立模式 Lerna 項(xiàng)目允許維護(hù)人員彼此獨(dú)立地增加包版本。每次發(fā)布時(shí),您都會(huì)收到有關(guān)已更改的每個(gè)包的提示,以指定它是補(bǔ)丁、次要、主要還是自定義更改。獨(dú)立模式允許您更具體地更新每個(gè)包的版本,并且對(duì)一組組件有意義。這里搭配 semantic-release 這個(gè)npm包 感興趣的可以去了解下。
下面我介紹一些lerna 的一些命令: 大家可以去github lerna 看的更多
lerna bootstrap:等同于 lerna link yarn install,用于創(chuàng)建符合鏈接并安裝依賴包;
lerna run:會(huì)像執(zhí)行一個(gè) for 循環(huán)一樣,在所有子項(xiàng)目中執(zhí)行 npm script 腳本,并且,它會(huì)非常智能的識(shí)別依賴關(guān)系,并從根依賴開(kāi)始執(zhí)行命令;
lerna exec:像 lerna run 一樣,會(huì)按照依賴順序執(zhí)行命令,不同的是,它可以執(zhí)行任何命令,例如 shell 腳本;
lerna publish:發(fā)布代碼有變動(dòng)的 package,因此首先您需要在使用 Lerna 前使用 git commit 命令提交代碼,好讓 Lerna 有一個(gè) baseline;
lerna add:將本地或遠(yuǎn)程的包作為依賴添加至當(dāng)前的 monorepo 倉(cāng)庫(kù)中,該命令讓 Lerna 可以識(shí)別并追蹤包之間的依賴關(guān)系,因此非常重要
tsconfig
作為一個(gè)ts 項(xiàng)目, 在項(xiàng)目根目錄安裝 ts
yarn add typesript -D -W
首先在項(xiàng)目中生成 tsconfig.json
npx tsc --init
然后在項(xiàng)目根目錄生成tsconfig.json 這里 劃重點(diǎn) 我們把基礎(chǔ)的 tsconfig.json 放在這里 ,然后 新建一個(gè)項(xiàng)目 生成tsconfig.json 都是繼承根目錄的 tsconfig.json 類(lèi)似于這樣
{ "extends": "../../tsconfig.json", "compilerOptions": { "target": "es2018", "module": "ESNext", "outDir": "./dist" }, "include": ["./src/**/*.ts"] // * 匹配0或者多個(gè)字符 (不包括目錄分割符) **/遞歸匹配任意子目錄}
這是一個(gè)子項(xiàng)目的tsconfig.json
至于tsconfig.json 文件 詳細(xì)配置,你可以自己百度。
Babel
Babel 配置文件合并的方式與 TypeScript 如出一轍,甚至更加簡(jiǎn)單,我們只需在子項(xiàng)目中的 .babelrc 文件中這樣聲明即可:
{ "extends": "../.babelrc"}
scripts
我們?cè)谌中陆ㄒ粋€(gè)scripts 文件夾 可能 是 shell 文件 也有可能是ts 文件。我們都知道 ts 文件 是不能直接執(zhí)行, 都是先編譯成js 然后再執(zhí)行, 這也太麻煩了吧。好在社區(qū)已經(jīng)提供的 ts-node 可以允許你直接運(yùn)行ts 文件 這東西實(shí)現(xiàn)的原理 大概就是
我們可以使用 ts-node 某個(gè) ts 文件,來(lái)直接執(zhí)行這個(gè) ts 文件,它的原理就是修改了 require hook,也就是 Module._extensions['.ts'] 來(lái)實(shí)現(xiàn)的。
在 require hook 里面做 ts 的編譯,然后后面直接執(zhí)行編譯后的 js,這樣就能達(dá)到直接執(zhí)行 ts 文件的效果。
所以我們重寫(xiě) Module._extensions['.ts'] 方法,在里面讀取文件內(nèi)容,然后調(diào)用 ts.transpileModule 來(lái)把 ts 轉(zhuǎn)成 js,之后調(diào)用 Module._compile 來(lái)處理編譯后的 js。
yarn add ts-node -D -W
新建一個(gè) test.ts 文件
const foo = { baz: { a: 1, },}console.log(foo)
然后 在package.json
編寫(xiě)如下腳本:
"test": "ts-node ./scripts/test.ts "
然后執(zhí)行 yarn test
res
其實(shí)這個(gè)ts-node 有一個(gè)坑 就是 文件引用問(wèn)題 當(dāng)你的 ts 腳本文件 引用了當(dāng)前項(xiàng)目的其他包 可能就會(huì)出現(xiàn) 執(zhí)行報(bào)錯(cuò)
我們?cè)趐ackage 新建一個(gè)util 然后 新建了一個(gè) index.ts 文件
const add = (a: number, b: number) => a bexport default add
然后我在根目錄的 tsconfig.json 進(jìn)行別名配置
"baseUrl": "./packages", // 根路徑 路徑映射, "paths": { "@fly/util": ["./util/index.ts"] }
我們?cè)?腳本 引入 這個(gè)加法 函數(shù)
import add from '@fly/util'console.error(add(2, 3))
然后繼續(xù)執(zhí)行
會(huì)報(bào)下面這個(gè)錯(cuò)誤
error
大家注意看 我畫(huà)框的地方,大體就是 由于 我們 ts-node 在執(zhí)行的過(guò)程中, 由于tsconfig.json 的 "module": "CommonJS", 會(huì)將
import add from '@fly/util' 編譯成
const add = require("@fly/util")
由于我們這個(gè)是ts 別名配置 當(dāng)然找不到 這個(gè)模塊, 如果你是webpack 項(xiàng)目的話 ,可以 配置別名 解決, 會(huì)進(jìn)行路徑替換,
但是我們?cè)趯?xiě)腳手架的時(shí)候,不可能用到webpack 就是 node 環(huán)境, 這里我怎么去解決呢
社區(qū)也提供了解決方案
ts-config
大概意思就是:使用它來(lái)加載位置在 tsconfig.json 的路徑部分中指定的模塊。支持在運(yùn)行時(shí)加載和通過(guò) API 加載。
Typescript 默認(rèn)模仿模塊的 Node.js 運(yùn)行時(shí)解析策略。但它也允許使用路徑映射,允許指定任意模塊路徑(不以“/”或“.”開(kāi)頭)并將其映射到文件系統(tǒng)中的物理路徑。typescript 編譯器可以從 tsconfig 解析這些路徑,因此它可以編譯。但是,如果您嘗試使用 node(或 ts-node)執(zhí)行編譯后的文件,它只會(huì)在 node_modules 文件夾中一直查找到文件系統(tǒng)的根目錄,因此不會(huì)找到 tsconfig 中路徑指定的模塊 這句話 很重要, 所以我們剛才的報(bào)錯(cuò),就是這個(gè)原因 而這個(gè)庫(kù) 就是幫我們解決的。
yarn add tsconfig-paths -D -W
如何使用呢
ts-node --project customLocation/tsconfig.json -r tsconfig-paths/register "test/**/*.ts"
這里的話最好ts config.json 的 common js 因?yàn)槲覀兪窃趎ode 環(huán)境
所以我在項(xiàng)目新建一個(gè)tsconfigs 用來(lái) 存放不同的 ts配置 同樣繼承 根目錄
{ "extends": "../tsconfig", "compilerOptions": { "module": "CommonJS" }}
執(zhí)行命令
ts-node --project ./tsconfigs/cmj.json -r tsconfig-paths/register ./scripts/test.ts
res
執(zhí)行成功 很舒服哇??吹竭@里覺(jué)得有幫助的話 可以幫忙點(diǎn)個(gè)贊吧
但是這里還會(huì)有個(gè)問(wèn)題 如圖:
eslint
這其實(shí)是eslint import 的配置 ,如果你配置了的話 安裝下面這個(gè)npm
yarn add eslint-import-resolver-typescript -D -W
光從名字就可以看出和這個(gè)問(wèn)題極為相關(guān)。從項(xiàng)目 README 可以發(fā)現(xiàn),這個(gè) lib 可以在 TypeScript 項(xiàng)目使 eslint-plugin-import 找到正確的 .ts 和 .tsx 文件,也能識(shí)別 tsconfig.json 的 path 配置(路徑別名 2),甚至 monorepo 這類(lèi)一個(gè) git 倉(cāng)庫(kù)多個(gè)項(xiàng)目的工程也支持。
用法也很簡(jiǎn)單在 eslint 的"import/resolver":指向當(dāng)前配置了 path 的 tsconfig 的路徑即可,eslint 就會(huì)自動(dòng)識(shí)別就不會(huì)報(bào)錯(cuò)了。
{ "plugins": ["import"], "rules": { "import/no-unresolved": "error" }, "settings": { "import/parsers": { // 使用 TypeScript parser "@typescript-eslint/parser": [".ts", ".tsx"] }, "import/resolver": { // 默認(rèn)使用根目錄 tsconfig.json "typescript": { // 從 <roo/>@types 讀取類(lèi)型定義 "alwaysTryTypes": true, }, // 使用指定路徑 tsconfig.json, <root>/path/to/folder/tsconfig.json "typescript": { "directory": "./path/to/folder" }, // monorepos 這類(lèi)多 tsconfig.json // 可以用 glob 這類(lèi)匹配模式 "typescript": { "directory": "./packages/*/tsconfig.json" }, // 或者數(shù)組 "typescript": { "directory": [ "./packages/module-a/tsconfig.json", "./packages/module-b/tsconfig.json" ] }, // 也可以混合使用 "typescript": { "directory": [ "./packages/*/tsconfig.json", "./other-packages/*/tsconfig.json" ] } } }}
上面就是官方的用法, 下面我們就開(kāi)始 eslint 詳細(xì)用法吧
eslint
對(duì)于eslint 的配置其實(shí)我們可以如法炮制,我們項(xiàng)目的根目錄 新建 .eslintrc 然后我們每個(gè)子項(xiàng)目 同樣繼承外部的 .eslintrc
好的下面我們開(kāi)始安裝 eslint
yarn add eslint -D -W
然后我們生成eslint 的配置文件
npx eslint --init
由于我們的項(xiàng)目 是基于 React 和 ts 的 所以在選擇的按照下面進(jìn)行選擇
eslint-config
這時(shí)候在我們的根目錄 就會(huì)出現(xiàn)**.eslint.yml** 這個(gè)配置文件 這里你也可以選擇你喜歡的配置文件格式, 個(gè)人比較喜歡YAML 這種方式
env: browser: true node: trueextends: - plugin:react/recommended - eslint:recommended - airbnbparser: '@typescript-eslint/parser'parserOptions: ecmaFeatures: JSX: true ecmaVersion: 2020 sourceType: moduleplugins: - react - '@typescript-eslint' - react-hooksrules:
然后就會(huì)出現(xiàn)下面這個(gè)文件我來(lái)一一解讀下面每一條的配置文件
env
- 表示你在 eslint 想啟用的環(huán)境 我們是前端嘛 所以 就是 node 和 browser,官網(wǎng)支持的還是比較多的extends單從字面上去理解就是 繼承 其他的配置 可以是 文件路徑 形式的 或者是 下載的插件包的 這里的話 一般npm包的 格式是下面這樣子的eslint-config-packagename
我們?cè)谂渲玫臅r(shí)候 前面的 eslint-config 可以省略, 我這使用的是airbnb 的配置。或者安裝的包的名字 是這樣子eslint-plugin-packagename
然后就可以 eslint-plugin 可以省略,然后就可以像下面使用plugin:xxxx/recommended
或者 是子目錄下繼承根目錄的 eslint 例如如下:extends: ../../.eslintrc
當(dāng)一切準(zhǔn)備就緒后,我們的項(xiàng)目目錄應(yīng)該大致呈如下所示的結(jié)構(gòu):.
- ├── package.json
├── .eslintrc
└── packages/
│ ├── tsconfig.json
│ ├── .babelrc
├── project_1/
│ ├── index.js
│ ├── .eslintrc
│ ├── .babelrc
│ ├── tsconfig.json
│ └── package.json
└───project_2/
├── index.js
├── .eslintrc
├── .babelrc
├── tsconfig.json
└── package.json
parserESLint 默認(rèn)使用Espree作為其解析器, 但是由于我們項(xiàng)目是 ts 文件, 所以安裝yarn add @typescript-eslint/parser
作用 就是將 TypeScript 轉(zhuǎn)換成與 estree 兼容的形式,以便在ESLint中使用。eslint 也是對(duì)AST 進(jìn)行操作,但是對(duì)TS 是不支持的,所以做一層轉(zhuǎn)換成 js.parserOption有了解析器肯定就有解析參數(shù) ecmaFeatures:
jsx: true // 表示支持jsx 語(yǔ)法 但是React 對(duì) ESLint 無(wú)法識(shí)別的JSX語(yǔ)法應(yīng)用特定的語(yǔ)義。如果你正在使用 React 并且想要 React 語(yǔ)義支持,我們建議你用 eslint-plugin-react。
ecmaVersion: 2020 // 默認(rèn)的js 的版本
sourceType: module // esm 模式
plugins正如上面所說(shuō),在解析參數(shù)配置了支持jsx 語(yǔ)法, 但是 ESLint 無(wú)法識(shí)別的JSX語(yǔ)法應(yīng)用特定的語(yǔ)義。如果你正在使用 React 并且想要 React 語(yǔ)義支持,我們建議你用 eslint-plugin-react。這就是所謂的插件 ,這里安裝了 react 和 react-hooks 兩個(gè)插件yarn add eslint-plugin-react eslint-plugin-react-hooks
然后我們就可以 plugins 進(jìn)行配置了 同樣可以省略 eslint-plugin
rules
rules 的定義我們一般看到的就是這樣子, 具體的配置可以自己查官方列表
---rules: eqeqeq: off curly: error quotes: - error - double
然后你如果安裝了插件
就可以插件名/ 規(guī)則 可以對(duì)默認(rèn)的插件配置 進(jìn)行重寫(xiě), 比如下面這樣子
'react-hooks/rules-of-hooks': 2'react-hooks/exhaustive-deps': 2
與VScode 集成
"editor.codeActionsOnSave": { "source.fixAll.eslint": true }
prettier
prettier 的出現(xiàn)其實(shí)為了解決代碼格式的問(wèn)題?這是eslint 無(wú)法做到的
Prettier中文的意思是漂亮的、美麗的,是一個(gè)流行的代碼格式化的工具,我們來(lái)看如何結(jié)合ESLint來(lái)使用。首先我們需要安裝三個(gè)依賴:
安裝 npm 包
yarn add prettier eslint-config-prettier eslint-plugin-prettier -D -W
- prettier:prettier插件的核心代碼
- eslint-config-prettier:解決ESLint中的樣式規(guī)范和prettier中樣式規(guī)范的沖突,以prettier的樣式規(guī)范為準(zhǔn),使ESLint中的樣式規(guī)范自動(dòng)失效
- eslint-plugin-prettier:將prettier作為ESLint規(guī)范來(lái)使用
然后在項(xiàng)目的根目錄下創(chuàng)建.prettierrc文件:
{ "printWidth": 120, "semi": false, "trailingComma": "all", "singleQuote": true, "arrowParens": "always"}
接著修改.eslintrc.js文件,引入prettier:
extends: - plugin:react/recommended # - plugin:import/recommended - eslint:recommended - airbnb - prettier plugins: - react - '@typescript-eslint' - react-hooks # - import - prettier
分別在extends 和 plugins 加入 prettier
husky和lint-staged構(gòu)建代碼工作流
在這之前我先簡(jiǎn)單介紹 下Husky 和 lint-staged 這兩個(gè)東西 到底是干什么的??
husky
husky目前是前端工程化必備的一個(gè)工具了, husky 這個(gè) npm 包 說(shuō)白了就是在git 提交前 提供一些鉤子 hooks 方便你運(yùn)行一些腳本命令。下面跟著我可以實(shí)操一下
yarn add husky -D -W
第二步:在packgae.json中添加prepare腳本
{ "scripts": { "prepare": "husky install" }}
prepare腳本會(huì)在npm install(不帶參數(shù))之后自動(dòng)執(zhí)行。也就是說(shuō)當(dāng)我們執(zhí)行npm install安裝完項(xiàng)目依賴后會(huì)執(zhí)行 husky install命令,該命令會(huì)創(chuàng)建.husky/目錄并指定該目錄為git hooks所在的目錄。
第三步 添加 git hooks
npx husky add .husky/pre-commit "yarn lint-staged"
這時(shí)候在我們根目錄 就會(huì)出現(xiàn) .husky 的目錄
husky
然后寫(xiě)入 pre-commit 腳本
#!/bin/sh. "$(dirname "$0")/_/husky.sh"yarn lint-staged
由于我們還沒(méi)有裝 lint-staged , 直接運(yùn)行會(huì)報(bào)錯(cuò)
lint-staged
yarn add lint-staged -D -W
Lint-staged 用于對(duì) Git 暫存區(qū)中的文件執(zhí)行代碼檢測(cè), 然后我們同樣也可以做一些操作
我們?cè)趐ackage.json 增加如下配置
"lint-staged": { "*.@(js|ts|tsx)": [ "eslint --ext .ts,.tsx,.js --fix", "prettier --write", "git add" ], "*.@(yml|yaml)": [ "prettier --parser yaml --write" ], "*.md": [ "prettier --parser markdown --write" ], "*.json": [ "prettier --parser json --write" ] },
我們看下第一個(gè),當(dāng)匹配到 以 js 或者 ts 或者是tsx 結(jié)尾的文件時(shí)候, 這時(shí)候我們就可以 結(jié)合 之前 的eslint 和 prettirer 做一些操作
- eslint 對(duì)這些文件 檢測(cè) 并自動(dòng)修復(fù)
- 然后 使用 prettier — write 進(jìn)行自動(dòng)檢測(cè)
- 最后添加到 暫存區(qū)中
我們r(jià)un 一下 看下效果:
husky 錄屏
你會(huì)發(fā)現(xiàn)好像已經(jīng)成功了, 但是最后 還是失敗了,因?yàn)槲以趆usky 還加了一個(gè)hook 用于在提交命令前 規(guī)范 commit-msg
我們輸入下面命令
npx husky add .husky/commit-msg 'yarn commitlint --edit "$1"'
然后在.husky 的目錄 就會(huì)出現(xiàn)下面這張圖
commit
由于運(yùn)行了這個(gè)腳本 commitlint 這個(gè)腳本 但是我們 安裝 老樣子
yarn add commitlint @commitlint/config-conventional @commitlint/config-lerna-scopes -D -W
**@commitlint/config-conventional ** 這里會(huì)使用默認(rèn)angular 團(tuán)隊(duì)的提交規(guī)范
@commitlint/config-lerna-scopes 由于我們是lerna 多個(gè)packages 主要是用來(lái)限制在packages 里的包 不在的 就會(huì)報(bào)錯(cuò),
packages├── api├── app└── web? echo "build(api): change something in api's build" | commitlint? input: build(api): change something in api's build? found 0 problems, 0 warnings? echo "test(foo): this won't pass" | commitlint? input: test(foo): this won't pass? scope must be one of [api, app, web] [scope-enum]? found 1 problems, 0 warnings
foo 不屬于項(xiàng)目中的一個(gè)包, 所以 直接 會(huì)報(bào)錯(cuò)。
在項(xiàng)目的根目錄 新建:commitlint.config.js
module.exports = { extends: ['@commitlint/config-conventional', '@commitlint/config-lerna-scopes'],}
這樣我們提交的時(shí)候就會(huì)做到我們上面的限制, 項(xiàng)目代碼的提交規(guī)范 還是很重要的
生成changelog
首先,聊一下什么是 CHANGELOG ,為什么需要 CHANGELOG ?它記錄你項(xiàng)目所有的commit信息并歸類(lèi)版本,可以快速跳轉(zhuǎn)到該條commit記錄,甚至可以顯示修改人信息一眼發(fā)現(xiàn)bug的創(chuàng)建者。它能讓你方便知道項(xiàng)目里哪個(gè)版本做了哪些功能有哪些bug等信息。也方便排查bug,對(duì)于提交記錄一目了然,不用一個(gè)一個(gè)去翻去查。
這里我們安裝 這個(gè)包
yarn add standard-version -D -W
這里,就直接用 standard-version 來(lái)實(shí)現(xiàn)自動(dòng)生成 CHANGELOG 了。conventional-changelog 咱們就不聊了,畢竟是它推薦咱們用 standard-version (這都是同一個(gè)團(tuán)隊(duì)的東西,基于conventional-changelog實(shí)現(xiàn)的)。
semantic-release 還有這個(gè) 進(jìn)行生成
至于這兩個(gè)的區(qū)別??我們看下
semantic-release 自動(dòng)化整個(gè)包發(fā)布工作流程,包括:確定下一個(gè)版本號(hào)、生成發(fā)布說(shuō)明和發(fā)布包。
雖然兩者都基于結(jié)構(gòu)化提交消息的相同基礎(chǔ),但標(biāo)準(zhǔn)版本采用不同的方法,為您處理版本控制、更改日志生成和 git 標(biāo)記,而無(wú)需自動(dòng)推送(到 GitHub)或發(fā)布(到 npm 注冊(cè)表)。使用標(biāo)準(zhǔn)版本只會(huì)影響您的本地 git 存儲(chǔ)庫(kù) – 它根本不會(huì)影響遠(yuǎn)程資源。運(yùn)行標(biāo)準(zhǔn)版本后,您可以查看發(fā)布狀態(tài)、糾正錯(cuò)誤并遵循對(duì)您的代碼庫(kù)最有意義的發(fā)布策略。我們認(rèn)為它們都是很棒的工具,如果對(duì)他們的用例有意義,我們鼓勵(lì)人們使用語(yǔ)義發(fā)布而不是標(biāo)準(zhǔn)版本
然后我們?cè)趐ackage.json 新增這腳本
"release": "standard-version",
為了 讓我們的changeLog 看起來(lái)好看一點(diǎn)在項(xiàng)目根目錄 新增 .versionrc.js
module.exports = { types: [ { type: 'feat', section: '? Features | 新功能' }, { type: 'fix', section: ' Bug Fixes | Bug 修復(fù)' }, { type: 'init', section: ' Init | 初始化' }, { type: 'docs', section: '?? Documentation | 文檔' }, { type: 'style', section: ' Styles | 風(fēng)格' }, { type: 'refactor', section: '?? Code Refactoring | 代碼重構(gòu)' }, { type: 'perf', section: '? Performance Improvements | 性能優(yōu)化' }, { type: 'test', section: '? Tests | 測(cè)試' }, { type: 'revert', section: '? Revert | 回退' }, { type: 'build', section: '? Build System | 打包構(gòu)建' }, { type: 'chore', section: ' Chore | 構(gòu)建/工程依賴/工具' }, { type: 'ci', section: ' Continuous Integration | CI 配置' }, ],}
然后在husky 新增 pre-push 腳本
npx husky add .husky/pre-commit "yarn release"
這樣我們?cè)?git push 提交代碼的時(shí)候 就會(huì)自動(dòng)生成changelog
changeLog
參考
- https://www.zhihu.com/question/318476028/answer/1895685159
- https://juejin.cn/post/7036688014206042143
- https://juejin.cn/post/6868472838613893127
最后
很感謝你能夠看完,如果覺(jué)得Fly哥寫(xiě)的不錯(cuò)的話,可以點(diǎn)個(gè)贊鼓勵(lì)一下,項(xiàng)目源碼 目前在github
https://github.com/wzf1997/fly 已經(jīng)開(kāi)源, 感興趣的可以學(xué)習(xí)一下
版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。