[architecture] Frontend monorepo with Nx
基本概念
在 JavaScript 中,精確來說 monorepo 的定義是該 repo 中有多個 package.json
,也就是不同的 package 有獨立的 package.json。
在 Nx 中有些專案有 project.json
但沒有 package.json
,因此這並不算是 monorepo;雖然如此,透過 package.json
還是能獲得 Nx 帶來的好處。
在 Nx 中:
- 即使不是 monorepo,也可以透過多個
project.json
來做到多個 modules 的管理和加速開發
廣義的 monorepo
廣義的 monorepo 來說,也可以是該 repo 中的多個 "projects" 會共用 root 的 npm modules、ESLint、TypeScript configuration。
使用 nx 的好處:
- 針對 component、library(modules) 已經有既定的資料夾結構和命名慣例
- 透過 nx graph 可以很清楚看出各個套件間的關聯,如何被引用
名詞定義
- Target:定義在
project.json
動作的名稱,例如build
- Task: 針對一個 project 執行特定的 target,例如
header:build
nx CLI
# --watch
# --skip-nx-cache:不要使用 nx 的 cache
# npm r-t 指的是 --target=xxx
Running Tasks
# nx <target-name> <project-name> <option overrides>
# 針對 products 這個 project 執行 serve 這個 task
$ nx serve products --watch
# 針對 common-ui 這個 project 執行 test 這個 task
$ nx test common-ui
target-name
會被定義在project.json
中
run-many:同時執行多個 target
# 對所有 project,同時執行多個 target (build, lint, test)
$ nx run-many -t build lint test
# 對所有 project 執行 lint,並且戴上 ESLint 的 quiet option
$ npx nx run-many -t lint --quiet
# 對所有 project 執行 build,且不要使用 cache
$ nx run-many -t build --skip-nx-cache
# 針對 header 和 footer 這兩個 project 同時執行多個 targets
$ nx run-may -t build lint test -p header footer
graph:Visualizing your Project Structure
$ nx graph --watch
affected:檢視目前變更會影響到哪些 package
# 畫出有被影響到的套件
$ nx affected:graph
# 只針對有被影響到的套件執行 task
# -t 指的是 --target=xxx
$ nx affected -t test
$ nx affected -t build
Create a Workspace
Installation
# Create a new Nx workspace
$ npx create-nx-workspace@latest [project-name]
$ npx nx list # 檢視可以整合的 nx 套件
# npx nx list [plugin] # 檢視該 nx 套件的資訊
$ npx nx list @nx/react
Project Configuration
- 專案中的
project.json
,可以視為強化版的package.json
。 - 只有要
project.json
檔案的資料夾,都是 "project",不管它是 App、component、或是 library。
project.json
{
"name": "store",
"$schema": "node_modules/nx/schemas/project-schema.json",
"sourceRoot": "./src",
"projectType": "application",
"tags": []
}
Target
nx.json
{
// ...
"targets": {
"serve": {
"executor": "@nx/vite:dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "store:build"
},
"configurations": {
"development": {
"buildTarget": "store:build:development",
"hmr": true
},
"production": {
"buildTarget": "store:build:production",
"hmr": false
}
}
},
"build": {
"executor": "@nx/vite:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"outputPath": "dist/modules/shared/ui"
},
"configurations": {
"development": {
"mode": "development"
},
"production": {
"mode": "production"
}
}
}
}
}
- executor:
<plugin>:<executor-name>
,例如@nx/vite:dev-server
,表示執行@nx/vite
這個 plugin 裡的dev-server
方法 - outputs:告訴 Nx 有什麼檔案會被建立,如此 Nx 可以把這些檔案加到 cache 中