[guide] Monorepo with React and TS
這個 template 的功能包含:
- 編譯 React 元件
- 支援 TypeScript 的編譯
- ESLint with TypeScript
- 可以撰寫測試
- 透過 lerna 進行版本控制與專案管理
- 透過 rollup 將專案打包
初始化 lerna
lerna init & lerna create @ pjchender/mono-react-ts-template
$ lerna init
create packages
$ lerna create @mono-react-component-template/core -y
$ lerna create @mono-react-component-template/components -y
Setup TypeScript
setup tsc and build with tsc @ pjchender/mono-react-ts-template
- 在根目錄建立
tsconfig.settings.json
,這支檔案是給packages/*
中的專案使用的 - 在
packages/*
中各自建立tsconfig.json
,並且extends
來自外層的tsconfig.settings.json
- 在根目錄建立
tsconfig.json
,透過在此檔案中設定references
來將packages/*
中的tsconfig.json
關聯起來 - 這時候的做法是透過
tsc
來打包專案,但後續會改成使用 babel 搭配@babel/preset-typescript
來編譯 TypeScript
Add cleanup script
add clean script to remove dist @ pjchender/mono-react-ts-template
每次專案打包後都會產生 dist
和 *.tsbuildinfo
的檔案,透過 rimraf
這個套件來快速移除這些檔案。
- 安裝
rimraf
- 在
packages/*
及根目錄的package.json
建立對應的clean
指令
Setup ESLint with TypeScript
-
安裝和 ESLint、TypeScript 及 React 有關的套件
npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
npm install eslint-config-airbnb-typescript \
eslint-plugin-import@^2.22.0 \
eslint-plugin-jsx-a11y@^6.3.1 \
eslint-plugin-react@^7.20.3 \
eslint-plugin-react-hooks@^4.0.8 \
@typescript-eslint/eslint-plugin@^4.4.1 \
eslint-config-prettier \
eslint-plugin-prettier \
eslint-plugin-simple-import-sort \
--save-dev
npm install --save-dev --save-exact prettier -
在根目錄建立
.eslintrc.js
,在packages/*
中的 eslint 會繼承這支檔案的設定 -
在
packages/*
中建立.eslintrc.js
,並透過extends
繼承根目錄的.eslintrc.js
-
建立
.prettierrc
-
建立
.eslintignore
-
在
packages/*
及根目錄的package.json
建立對應的lint
指令
Testing (Jest)
setup babel for testing(jest) @ pjchender/mono-react-ts-template
-
安裝所需的套件
npm install jest \
@types/jest \
eslint-plugin-jest \
@babel/preset-env \
@babel/preset-typescript \
--save-dev -
在根目錄建立
babel.config.js
,Jest 在執行時預設就會讀這支的設定 -
在
packages/*
中各自建立.babelrc
並且繼承根目錄的babel.config.js
檔 -
在
packages/*
及根目錄的package.json
建立對應的test
指令
rollup
setup rollup with babel to build ts files @ pjchender/mono-react-ts-template
安裝所需的套件
npm install rollup \
@rollup/plugin-node-resolve \
@rollup/plugin-commonjs \
@rollup/plugin-babel \
rollup-plugin-terser \
@babel/plugin-transform-runtime \
--save-dev
編譯 TypeScript
一般來說,最常使用的方式是使用 Babel 來編譯 TypeScript 檔案,搭配 tsc 來檢驗型別並產生 .d.ts
檔案。這裡我們也選擇這樣做。
-
建立
rollup.config.js
@rollup/plugin-node-resolve
:在沒有使用 node-resolve 時,rollup 不會去把 node_modules 的內容 resolve 出來並放到 bundle 中,但若使用了 resolve,這時就會把 node_modules 內的結果直接放到 bundle 中。@rollup/plugin-babel
:使用 babel@rollup/plugin-commonjs
:將 CommonJS 的 modules 轉成 ES6 modules,來讓 rollup 進行 bundlerollup-plugin-terser
:將 bundle 的檔案做 minify
-
由於要讓 Babel 能夠編譯
.ts
檔,需要先透過node-resolve
找到.ts
的位置(透過extensions
的設定) -
接著一樣透過
extensions
的設定讓 Babel 能夠處理 ts 檔 -
在
packages/*
及根目錄的package.json
建立對應的build
指令
要選擇使用 Babel 或 TSC 來編譯 TypeScript 的檔案可以參考:Setup TypeScript Template @ pjchender
透過 tsc 產生 type definition
use tsc to build .d.ts files @ pjchender/mono-react-ts-template
由於透過 Babel 編譯 TypeScript 時,並不會產生對應的 .d.ts
檔,此時其他開發者使用此套件時,並不會獲得任何的型別資訊(及限制),因此我們仍需要使用 tsc
來產生 .d.ts
檔。
-
若要使用 tsc 來做型別檢查並產生對應的
.d.ts
檔,記得在 tsconfig.json 中的設定要:// tsconfig.json
// https://www.typescriptlang.org/docs/handbook/babel-with-typescript.html
"compilerOptions": {
// Ensure that .d.ts files are created by tsc, but not .js files
"declaration": true,
"emitDeclarationOnly": true,
// Ensure that Babel can safely transpile files in the TypeScript project
"isolatedModules": true
} -
在
package.json
中要加上types
這個欄位,讓使用此套件的開發者可以正確載入到 Type Definition// package.json
{
"name": "@mono-react-component-template/components",
"version": "0.0.0",
+ "main": "dist/index.cjs.js",
+ "module": "dist/index.esm.js",
+ "types": "dist/index.d.ts",
"directories": {
"src": "src",
"test": "__tests__"
},
} -
在
packages/*
及根目錄的package.json
建立對應的build:ts
指令
設定進版和發佈的指令
- 透過
lerna version patch
的指令更新版號,預設的情況下,lerna 會和 git remote 的位址有連動,若不需要,可以加上--no-git-tag-version
- 這裡我們會發到由 verdaccio 所建立的本機的 npm registry,因此會把 publish 的 registry 設為
--registry 'http://localhost:4873
diff --git a/package.json b/package.json
index ac740dc..40aa653 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,9 @@
"build:ts": "lerna run build:ts",
"lint": "lerna run lint",
"clean": "lerna run clean",
- "test": "lerna run test"
+ "test": "lerna run test",
+ "version:patch": "lerna version patch --no-git-tag-version",
+ "publish:local": "lerna run build && lerna publish from-package --registry 'http://localhost:4873'"
},
"devDependencies": {
"@babel/plugin-transform-runtime": "^7.14.3",
編譯 React 元件
setup to build react components @ pjchender/mono-react-ts-template
安裝 React 套件
在 package/components
專案中安裝 react 及相關套件,並且一併放到 peerDependencies 中:
# 由於有在 npm 設定 workspace 所以可以透過 --workspace 進行安裝
npm install -D react @types/react styled-components @types/styled-components --workspace=packages/components
安裝 @babel/preset-react
在還沒有安裝對應的 babel plugin 就要編譯 react 元件時,因為 rollup 不認得 JSX,因此會發生錯誤:
npm install -D @babel/preset-react
並在 babel.config.js
中建立對應的設定檔:
diff --git a/babel.config.js b/babel.config.js
index 97ed664..406d237 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -8,6 +8,12 @@ module.exports = {
},
},
],
+ [
+ '@babel/preset-react',
+ {
+ runtime: 'automatic',
+ },
+ ],
'@babel/preset-typescript',
],
plugins: ['@babel/plugin-transform-runtime'],
修改 eslintrc 的設定
+ peerDependencies: true,
packageDir,
},
Testing for React Component
setup for testing react components @ pjchender/mono-react-ts-template
-
在
packages/components
中安裝對應的套件(這裡我們假設packages/core
不會用到 react,如果會的話,或許可以把@testing-library
裝在根目錄):npm install -D @testing-library/react \
@testing-library/jest-dom \
@testing-library/react-hooks \
@testing-library/user-event \
@types/styled-components \
react-test-renderer -
在根目錄建立
jest.config.js
,設定testEnvironment
為jsdom
,並且使用'@testing-library/jest-dom/extend-expect'
// jest.config.js
process.env.TZ = 'UTC';
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
};