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在每盘基础上实现。