公司內部的 kintone 應用程式如果流程比較複雜,通常不會只有開發一個應用程式,五個以上的應用程式都有客製化開發也是稀鬆平常,但要管理這些開發內容就比較麻煩了,像是資料夾的架構該如何設計?每個應用程式都是一個 Repository
嗎?函式要共用的話要怎麼辦...等等問題,因此我們在這裡來建構一個 Monorepo 架構的 kintone 應用程式環境,過程我們會用到 pnpm Workspace 和 Nx 來輔助,之後在部屬會更加方便。
使用之前要安裝 pnpm:
npm install pnpm -g
接著開一個新的資料夾,終端機打上 pnpm init
建立出 package.json
,再新增資料夾 apps
和 packages
,然後同時在根目錄新增檔案 pnpm-workspace.yaml
,用來指定 packages,然後填入以下內容:
// pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
到這個步驟後,專案目錄應該會像這樣:
📂 monorepo-nx
┣ 📂 packages/
┣ 📂 apps/
┣ 📜 package.json
┗ 📜 pnpm-workspace.yaml
apps
資料夾中會放我們在 kintone 上的應用程式,現在假設有 公司資料
、顧客資料
兩個應用程式,我們就可以在 apps
建立兩個開發專案,你可以使用之前的建置環境,或是用自己喜歡的工具都可以,這裡我一樣用 rsbuild
,框架用 React。
pnpm create rsbuild@latest
建立完成後:
📂 monorepo-nx
┗ 📂 apps/
┣ 📂 customer/
┗ 📂 company/
接著來試試看在 packages
建立 utils
並在應用程式中引用,
📂 monorepo-nx
┗ 📂 packages/
┗ 📂 utils/
┣ 📜 index.js # 入口
┣ 📜 sum.js # 加總的函式
┗ 📜 package.json # name 是 @packages/utils
sum.js
只寫了以下,並在 index.js 中統一 export 出去:
// sum.js
export const sum = (num1, num2) => {
return num1 + num2
}
// index.js
export { sum } from 'sum.js'
然後在 apps/customer 的 package.json
加上:
"devDependencies": {
"@packages/utils": "workspace:*"
}
接著就可以在 apps 中引入並使用這個函式了:
import { sum } from '@packages/utils'
pnpm add nx -D -w
或是
pnpx nx@latest init
如果使用 pnpx nx@latest init
他會問你一系列的問題,並且在根目錄建立 nx.json
。
這邊第三個問題是是否要使用 nx cloud
,我們先不要用這個。回答完後就可以使用 nx 的指令了,例如啟動 顧客管理
的專案:
pnpx nx run customer:dev
啟動多個 app:
pnpx nx run-many --target=dev --projects=customer,company
啟動全部的 app:
pnpx nx dev:all
如果一次啟動多個 app,有可能會出現警告,是因為 port 被佔用了,可以到 app 中專案的各 config 調整:
export default defineConfig({
plugins: [pluginReact()],
server: {
port: 5100 // 調整 port
}
})
也可以打 pnpm exec nx graph
用圖形化的介面查看 app 之間的依賴狀況。
再來嘗試將專案打包出來:
pnpx nx run-many --target=build --all
可以看到專案內多了 dist
資料夾,代表成功了。
不過會發生一個情況:如果我其中一個 app 根本沒有動過,那這個 app 仍然會一起被打包,有沒有方法可以只打包更動過的專案,而且有被 packages
依賴的 app 也要重新被打包?
有的,我們可以使用 git 加上指令 affected
,可以用來重新構建受影響的專案,它會根據程式碼的變更來智能的確定哪些項目需要重新構建,從而節省時間和資源。
所以我們先來建立版本控制:
git init
git add .
git commit -m "init"
來後嘗試打上編譯的指令:
pnpx nx affected -t build --base=main --head=HEAD
會得到沒專案打包的狀況,因為我們沒改任何程式碼。
再來我們修改 packages/utils/sum.js
這隻檔案,隨便加個 log 進去:
export const sum = (num1, num2) => {
console.log('test')
return num1 + num2
}
記得我們的 app/customer 有引用到 utils 的功能嗎?這時候重新打包過後,這個 app 應該會被重新構建一次,打上指令 pnpx nx affected -t build
:
也可以透過 --base=master~1
指定比較上一個 commit,這樣他就有了重新建構的比較基準。
npx nx affected -t build --base=master~1
NX 可以幫我們自動偵測哪個 app 有需要被重新建構,再也不需要自己指定打包哪個 app 了,不過這時候如果去修改任一個 app 內的所有內容例如:gitignore
、readme
等檔案的時候,會發現依舊會被重新打包,這樣的結果不是我們想要的,所以來修改一下根目錄的 nx.json
:
// nx.json
// 略 ...
"targetDefaults": {
"dev": {
// 執行 dev 之前要依賴的指令
"dependsOn": [
"^build"
]
},
"build": {
// build 時忽略 .md 的檔案
"inputs": [
"!{projectRoot}/**/*.md"
],
// 執行 build 之前要依賴的指令
"dependsOn": [
"^build"
]
}
},
// 略 ...
其中的 "!{projectRoot}/**/*.md"
就會幫我們忽略專案內附檔名是 .md
的檔案。
這樣就建構完基礎的 Monorepo 專案架構,下一篇文章中會結合 kintone 的環境進行開發。