Monorepo概念,小技巧和竅門圍繞NextJS
Howtos for Monorepo。 Monorepos的新手?檢查此常見問題解答。此示例由TurborePo和Yarn 4採用A /打字條路徑別名方法來管理。不是唯一的方法。
對
如果您在公司中喜歡我的一些OSS工作,我將非常感謝贊助,咖啡或丟下的星星。這給了我更多的時間將其提高到一個新的水平。
| 噴氣橋 | Embie.be | 動詞 |
corepack enable
yarn install .
├── apps
│ ├── nextjs-app (i18n, ssr, api, vitest)
│ └── vite-app
└── packages
├── common-i18n (locales...)
├── core-lib
├── db-main-prisma
├── eslint-config-bases (to shared eslint configs)
└── ui-lib (emotion, storybook)
應用不應取決於應用,它們可以依賴包裝
應用程序可以取決於軟件包,軟件包可以互相取決於彼此...
.
├── apps
│ ├── vite-app (Vite app as an example)
│ │ ├── src/
│ │ ├── package.json (define package workspace:package deps)
│ │ └── tsconfig.json (define path to packages)
│ │
│ └── nextjs-app (NextJS app with api-routes)
│ ├── e2e/ (E2E tests with playwright)
│ ├── public/
│ ├── src/
│ │ └── pages/api (api routes)
│ ├── CHANGELOG.md
│ ├── next.config.mjs
│ ├── package.json (define package workspace:package deps)
│ ├── tsconfig.json (define path to packages)
│ └── vitest.config.ts
│
├── packages
│ ├── core-lib (basic ts libs)
│ │ ├── src/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── db-main-prisma (basic db layer with prisma)
│ │ ├── e2e/ (E2E tests)
│ │ ├── prisma/
│ │ ├── src/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ ├── eslint-config-bases
│ │ ├── src/
│ │ ├── CHANGELOG.md
│ │ ├── package.json
│ │ └── tsconfig.json
│ │
│ └── ui-lib (basic design-system in react)
│ ├── src/
│ ├── CHANGELOG.md
│ ├── package.json
│ └── tsconfig.json
│
├── static (no code: images, json, locales,...)
│ ├── assets
│ └── locales
├── docker (docker...)
│ ├── .dockerignore
│ ├── docker-compose.yml (compose specific for nextjs-app)
│ ├── docker-compose.db.yml (general services like postgresql...)
│ └── Dockerfile (multistage build for nextjs-app)
├── .yarnrc.yml
├── package.json (the workspace config)
└── tsconfig.base.json (base typescript config)
{
"name" : "nextjs-monorepo-example" ,
// Set the directories where your apps, packages will be placed
"workspaces" : [ "apps/*" , "packages/*" ] ,
//...
}包裝管理器將掃描這些目錄,並尋找兒童package.json 。他們的內容用於定義工作空間拓撲(應用程序,libs,依賴關係...)。
用包裝名稱創建一個文件夾。
mkdir packages/magnificent-poney
mkdir packages/magnificent-poney/src
cd packages/magnificent-poney初始化一個包裝的包裹名稱。
而不是輸入
yarn init,而是選擇以./package/ui-lib/package.json為示例並編輯其值。
{
"name" : "@your-org/magnificent-poney" ,
"version" : "0.0.0" ,
"private" : true ,
"scripts" : {
"clean" : "rimraf ./tsconfig.tsbuildinfo" ,
"lint" : "eslint . --ext .ts,.tsx,.js,.jsx" ,
"typecheck" : "tsc --project ./tsconfig.json --noEmit" ,
"test" : "run-s 'test:*'" ,
"test:unit" : "echo "No tests yet"" ,
"fix:staged-files" : "lint-staged --allow-empty" ,
"fix:all-files" : "eslint . --ext .ts,.tsx,.js,.jsx --fix" ,
} ,
"devDependencies" : {
"@your-org/eslint-config-bases" : "workspace:^" ,
} ,
}首先將軟件包添加到app package.json。建議的方法是使用YARN和PNPM支持的工作空間協議。
cd apps/my-app
yarn add @your-org/magnificent-poney@ ' workspace:^ '靈感可以在應用程序/nextjs-app/package.json中找到。
{
"name" : "my-app" ,
"dependencies" : {
"@your-org/magnificient-poney" : "workspace:^" ,
} ,
} 然後在app tsconfig.json中添加打字稿路徑別名。這將使您直接導入它(無需構建)
靈感可以在應用程序/nextjs-app/tsconfig.json中找到。
{
"compilerOptions" : {
"baseUrl" : "./src" ,
"paths" : {
// regular app aliases
"@/components/*" : [ "./components/*" ] ,
// packages aliases, relative to app_directory/baseUrl
"@your-org/magnificent-poney/*" : [
"../../../packages/magnificent-poney/src/*" ,
] ,
"@your-org/magnificent-poney" : [
"../../../packages/magnificent-poney/src/index" ,
] ,
} ,
} ,
}PS:
- 不要試圖在全局tsonfig.base.json中設置別名,以嚴格與圖形依賴關係。
@your-org/magnificent-poney/*中的星星使您可以導入子文件夾。如果使用桶文件(index.ts),則可以刪除帶有星星的別名。
編輯您的next.config.mjs並啟用casteriention.externaldir選項。反饋在這裡。
const nextConfig = {
experimental : {
externalDir : true ,
} ,
} ;如果您使用的是較舊的NextJS版本,並且沒有實驗標誌,則只需覆蓋您的WebPack配置即可。
const nextConfig = {
webpack : ( config , { defaultLoaders } ) => {
// Will allow transpilation of shared packages through tsonfig paths
// @link https://github.com/vercel/next.js/pull/13542
const resolvedBaseUrl = path . resolve ( config . context , "../../" ) ;
config . module . rules = [
... config . module . rules ,
{
test : / .(tsx|ts|js|jsx|json)$ / ,
include : [ resolvedBaseUrl ] ,
use : defaultLoaders . babel ,
exclude : ( excludePath ) => {
return / node_modules / . test ( excludePath ) ;
} ,
} ,
] ;
return config ;
} ,
} ;PS:如果您的共享軟件包利用SCSS Bundler ...將需要自定義的WebPack配置或使用Next-Transpile-Modules,請參見下面的常見問題解答。
這些軟件包現在已鏈接到您的應用程序,只需像常規軟件包一樣導入它們: import { poney } from '@your-org/magnificent-poney' 。
選修的
如果您需要在MonorePo之外共享一些軟件包,則可以將它們發佈到NPM或私人存儲庫。每個軟件包中都有一個基於微型漏斗的示例。可以使用Atlassian/Changeet進行版本控制和發布,並且很簡單,就像打字一樣:
$ yarn g:changeset按照說明...提交更改文件文件。 CI檢查後,將出現“版本軟件包” P/R。合併時,github操作將發布包裝的SEMVER版本,並為您生成ChangElogs。
PS:
- 即使您不需要發布,更改集也可以維護應用程序的自動化轉換器。好的 !
- 要禁用某些軟件包的自動發布,只需在其package.json中設置
"private": "true"。- 想要調整行為,請參閱.changeset/config.json。
可以在此存儲庫的任何文件夾中運行一些便利腳本,並將其稱為包裝和應用程序定義的對應物。
| 姓名 | 描述 |
|---|---|
yarn g:changeset | 添加更改以聲明新版本 |
yarn g:codegen | 在所有工作區中運行代碼根 |
yarn g:typecheck | 在所有工作區中運行Typechecks |
yarn g:lint | 在所有工作區中顯示襯裡問題 |
yarn g:lint --fix | 嘗試在所有工作區中運行Linter Auto-Fix |
yarn g:lint-styles | 在所有工作區中顯示CSS樣式問題 |
yarn g:lint-styles --fix | 嘗試在所有工作空間中運行Stylelint自動固定問題 |
yarn g:test | 在所有工作區中運行單元和E2E測試 |
yarn g:test-unit | 在所有工作區內運行單元測試 |
yarn g:test-e2e | 在所有工作區中運行E2E測試 |
yarn g:build | 在所有工作區中運行構建 |
yarn g:clean | 清潔構建在所有工作區 |
yarn g:check-dist | 確保構建DIST文件通過ES2017(運行g:build )。 |
yarn g:check-size | 確保瀏覽器DIST文件在尺寸限制內(運行g:build )。 |
yarn clean:global-cache | 清潔工具卡車(Eslint,Jest ...) |
yarn deps:check --dep dev | 將打印全球可以升級的包裝(另請參見.ncurc.yml) |
yarn deps:update --dep dev | 應用可能的更新(運行yarn install && yarn dedupe之後) |
yarn install:playwright | 為E2E安裝劇作家 |
yarn dedupe | 鎖定文件的內置紗線重複數據刪除 |
為什麼使用
:前綴腳本名稱?它在紗線3+中很方便,我們可以從monorepo中的任何文件夾中調用這些腳本。g:是global:。請參閱root軟件包中的完整列表。
全局命令yarn deps:check和yarn deps:update將有助於維護整個MonorePo的相同版本。它們基於出色的NPM檢查日期(請參閱選項,即: yarn check:deps -t minor )。
運行
yarn deps:update後,需要yarn install。為了防止在Yarn.lock中重複,您可以運行yarn dedupe --check和yarn dedupe應用刪除。示例GitHub動作中強制執行重複檢查。
請參見一個示例。
檢查.husky文件夾內容以查看啟用了哪些掛鉤。絨毛階段用於確保棉絨和漂亮的棉布自動應用於提交和/或推動。
測試取決於TS-Jest或vitest,具體取決於應用程序。所有設置都支持打字條路徑別名。每當涉及反應時,就會啟用反應測試庫。
配置生存在每個應用程序/軟件包的根文件夾中。例如,請參見
您會在.github/Workflows中找到一些用於github操作的示例工作流程。默認情況下,他們將確保
每個步驟都可以選擇。
為了確保表現不錯,這些功能在示例動作中存在:
包裝的緩存(Node_modules ...) - 安裝大約25s
Nextjs先前構建的緩存- 大約20年代建造
使用操作路徑更改時觸發,即:
paths: - "apps/nextjs-app/**" - "packages/**" - "package.json" - "tsconfig.base.json" - "yarn.lock" - ".yarnrc.yml" - ".github/workflows/**" - ".eslintrc.base.json" - ".eslintignore"
ESLINT插件要求設置eslint.workingDirectories設置:
"eslint.workingDirectories": [
{
"pattern": "./apps/*/"
},
{
"pattern": "./packages/*/"
}
],
更多信息在這裡
VERCEL支持本地單星,請參見Vercel-Monorepo-Deploy文檔。
有一個用於構建Docker映像的基本示例,請閱讀Docker Doc。
將來可能會添加NetLify,AWS-amplify,K8s-Docker,無液Nextjs食譜。公關也歡迎。
應用程序依賴性和Dev依賴性被固定在精確版本中。軟件包DEP將使用SEMVER兼容。有關此更改的更多信息,請參見此處的推理和我們的RenoVabot.json5配置文件。
為了幫助保持DEP的最新狀態,請參閱yarn deps:check && yarn deps:update腳本和 /或使用RenovateBot。
當通過紗線CLI添加DEP(即:YARN添加一些內容)時,可以通過設置
defaultSemverRangePrefix: ""yarnrc.yml來自動設置保存外觀行為。但這也將使軟件包的默認值/*。最好處理yarn add something --exact在每盤基礎上實現。