Convert repository to monorepo layout (apps/web + packages) with Turbo#211
Convert repository to monorepo layout (apps/web + packages) with Turbo#211EvanTechDev wants to merge 27 commits intodevfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
审阅者指南将现有的单体 Next.js 应用仓库转换为基于 Turborepo 的 monorepo,分别为 Web 应用以及共享的 config、i18n 和 UI 包创建独立的 workspace,并相应配置 Turbo 任务、路径别名和共享配置。 跨 workspace 的 generate:locales 任务时序图sequenceDiagram
actor Dev
participant RootPkg as root_package_json
participant Turbo as turbo
participant I18nPkg as @repo/i18n
participant GenLocales as gen-locales_mjs
participant FS as file_system
Dev->>RootPkg: bun run generate:locales
RootPkg->>Turbo: turbo generate:locales --filter=@repo/i18n
Turbo->>I18nPkg: run script generate:locales
I18nPkg->>GenLocales: bun scripts/gen-locales.mjs
GenLocales->>FS: read src/locales/*.json
FS-->>GenLocales: locale json contents
GenLocales->>FS: write src/locales.ts
GenLocales-->>I18nPkg: log generated locales_ts
I18nPkg-->>Turbo: task success
Turbo-->>RootPkg: pipeline success
RootPkg-->>Dev: generate:locales completed
文件级变更
使用提示与命令与 Sourcery 交互
自定义你的使用体验访问你的 控制面板 以:
获取帮助Original review guide in EnglishReviewer's GuideConvert the existing single Next.js app repository into a Turborepo-based monorepo with separate workspaces for the web app and shared config, i18n, and UI packages, wiring Turbo tasks, path aliases, and shared configs accordingly. Sequence diagram for generate:locales task across workspacessequenceDiagram
actor Dev
participant RootPkg as root_package_json
participant Turbo as turbo
participant I18nPkg as @repo/i18n
participant GenLocales as gen-locales_mjs
participant FS as file_system
Dev->>RootPkg: bun run generate:locales
RootPkg->>Turbo: turbo generate:locales --filter=@repo/i18n
Turbo->>I18nPkg: run script generate:locales
I18nPkg->>GenLocales: bun scripts/gen-locales.mjs
GenLocales->>FS: read src/locales/*.json
FS-->>GenLocales: locale json contents
GenLocales->>FS: write src/locales.ts
GenLocales-->>I18nPkg: log generated locales_ts
I18nPkg-->>Turbo: task success
Turbo-->>RootPkg: pipeline success
RootPkg-->>Dev: generate:locales completed
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - 我发现了 3 个问题,并给出了一些整体性的反馈:
- 新增的共享 Tailwind 配置文件
packages/config/tailwind.config.ts目前是一个空对象,这会丢失之前所有的 Tailwind 设置;建议将原来的tailwind.config.ts内容迁移到这里,以保持 Web 应用的样式一致性。 - Locale 生成目前通过两种不同方式接线(根目录脚本使用带
@repo/i18n的 Turbo,而apps/web里的脚本则手动cd到packages/i18n);建议统一成一种方式(例如始终通过 Turbo 调用 workspace 脚本),这样更清晰也更不容易出错。
给 AI Agent 的提示词
Please address the comments from this code review:
## Overall Comments
- 新增的共享 Tailwind 配置文件 `packages/config/tailwind.config.ts` 目前是一个空对象,这会丢失之前所有的 Tailwind 设置;建议将原来的 `tailwind.config.ts` 内容迁移到这里,以保持 Web 应用的样式一致性。
- Locale 生成目前通过两种不同方式接线(根目录脚本使用带 `@repo/i18n` 的 Turbo,而 `apps/web` 里的脚本则手动 `cd` 到 `packages/i18n`);建议统一成一种方式(例如始终通过 Turbo 调用 workspace 脚本),这样更清晰也更不容易出错。
## Individual Comments
### Comment 1
<location path="package.json" line_range="13-14" />
<code_context>
+ "dev": "turbo dev --filter=web",
+ "build": "turbo build",
+ "start": "turbo start --filter=web",
+ "generate:locales": "turbo generate:locales --filter=@repo/i18n",
+ "generate:oauth-metadata": "turbo generate:oauth-metadata --filter=web"
},
"devDependencies": {
</code_context>
<issue_to_address>
**issue (bug_risk):** These turbo commands are missing the `run` subcommand and likely won't execute the intended tasks.
The turbo CLI requires `turbo run <task>` for task execution. As written, these scripts will fail because `turbo generate:locales` and `turbo generate:oauth-metadata` won’t match any command. Please update to:
```jsonc
"generate:locales": "turbo run generate:locales --filter=@repo/i18n",
"generate:oauth-metadata": "turbo run generate:oauth-metadata --filter=web"
```
And follow this pattern for any similar scripts you add.
</issue_to_address>
### Comment 2
<location path="apps/web/package.json" line_range="6-12" />
<code_context>
+ "private": true,
+ "packageManager": "bun@1.3.8",
+ "scripts": {
+ "dev": "(cd ../../packages/i18n && bun run generate:locales) && next dev",
+ "build": "(cd ../../packages/i18n && bun run generate:locales) && next build",
+ "start": "next start",
+ "generate:locales": "(cd ../../packages/i18n && bun run generate:locales)",
</code_context>
<issue_to_address>
**suggestion:** The subshell `cd` approach for pre-generating locales is fragile and bypasses the monorepo task graph.
This pattern hardcodes repo layout and shell behavior and sidesteps turbo’s dependency graph and caching. Instead, either:
1. Add a `generate:locales` script in `apps/web` that depends on `@repo/i18n`’s `generate:locales` via turbo’s `pipeline`/`dependsOn`, or
2. Run `turbo run generate:locales --filter=@repo/i18n` from the root and make `dev`/`build` depend on that.
This avoids path/shell brittleness and lets turbo cache and schedule the work correctly.
```suggestion
"scripts": {
"dev": "bun run generate:locales && next dev",
"build": "bun run generate:locales && next build",
"start": "next start",
"generate:locales": "turbo run generate:locales --filter=@repo/i18n",
"generate:oauth-metadata": "bun lib/gen-oauth-metadata.mjs"
},
```
</issue_to_address>
### Comment 3
<location path="apps/web/tsconfig.json" line_range="13" />
<code_context>
+ "@/*": ["./*"],
+ "@/components/ui/*": ["../../packages/ui/src/*"],
+ "@/lib/i18n": ["../../packages/i18n/src/i18n.ts"],
+ "@/lib/locales": ["../../packages/i18n/src/locales.ts"]
+ }
+ },
</code_context>
<issue_to_address>
**suggestion:** Pointing a path alias directly at the generated locales file can cause editor/typecheck issues before generation runs.
Because `../../packages/i18n/src/locales.ts` is generated, it won’t exist (and TS/IDE will error) until `generate:locales` has run at least once. To avoid that, you could either:
- Point this alias at the i18n package entry (e.g. `@repo/i18n`) instead of the generated file, or
- Point it at a stable barrel file in the i18n package that re-exports from `./locales`, so the barrel is always present.
That way you keep `@/lib/locales` ergonomics without depending directly on a generated artifact.
Suggested implementation:
```
"@/components/ui/*": ["../../packages/ui/src/*"],
"@/lib/i18n": ["../../packages/i18n/src/i18n.ts"],
"@/lib/locales": ["@repo/i18n"]
```
For this to work cleanly, ensure that the `@repo/i18n` package's main entry exports the same `locales` surface that consumers expect from `@/lib/locales`. If it currently does not, add the appropriate re-exports in the i18n package (e.g., export `locales` or equivalent from its entry file).
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进后续的 Review。
Original comment in English
Hey - I've found 3 issues, and left some high level feedback:
- The new shared Tailwind config in
packages/config/tailwind.config.tsis an empty object, which drops all of the previous Tailwind settings; consider porting the originaltailwind.config.tscontents here so the web app’s styling remains consistent. - Locale generation is wired up in two different ways (root scripts using Turbo with
@repo/i18nandapps/webscripts manuallycd-ing intopackages/i18n); it would be clearer and less error-prone to standardize on a single approach (e.g., always invoking the workspace script via Turbo).
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new shared Tailwind config in `packages/config/tailwind.config.ts` is an empty object, which drops all of the previous Tailwind settings; consider porting the original `tailwind.config.ts` contents here so the web app’s styling remains consistent.
- Locale generation is wired up in two different ways (root scripts using Turbo with `@repo/i18n` and `apps/web` scripts manually `cd`-ing into `packages/i18n`); it would be clearer and less error-prone to standardize on a single approach (e.g., always invoking the workspace script via Turbo).
## Individual Comments
### Comment 1
<location path="package.json" line_range="13-14" />
<code_context>
+ "dev": "turbo dev --filter=web",
+ "build": "turbo build",
+ "start": "turbo start --filter=web",
+ "generate:locales": "turbo generate:locales --filter=@repo/i18n",
+ "generate:oauth-metadata": "turbo generate:oauth-metadata --filter=web"
},
"devDependencies": {
</code_context>
<issue_to_address>
**issue (bug_risk):** These turbo commands are missing the `run` subcommand and likely won't execute the intended tasks.
The turbo CLI requires `turbo run <task>` for task execution. As written, these scripts will fail because `turbo generate:locales` and `turbo generate:oauth-metadata` won’t match any command. Please update to:
```jsonc
"generate:locales": "turbo run generate:locales --filter=@repo/i18n",
"generate:oauth-metadata": "turbo run generate:oauth-metadata --filter=web"
```
And follow this pattern for any similar scripts you add.
</issue_to_address>
### Comment 2
<location path="apps/web/package.json" line_range="6-12" />
<code_context>
+ "private": true,
+ "packageManager": "bun@1.3.8",
+ "scripts": {
+ "dev": "(cd ../../packages/i18n && bun run generate:locales) && next dev",
+ "build": "(cd ../../packages/i18n && bun run generate:locales) && next build",
+ "start": "next start",
+ "generate:locales": "(cd ../../packages/i18n && bun run generate:locales)",
</code_context>
<issue_to_address>
**suggestion:** The subshell `cd` approach for pre-generating locales is fragile and bypasses the monorepo task graph.
This pattern hardcodes repo layout and shell behavior and sidesteps turbo’s dependency graph and caching. Instead, either:
1. Add a `generate:locales` script in `apps/web` that depends on `@repo/i18n`’s `generate:locales` via turbo’s `pipeline`/`dependsOn`, or
2. Run `turbo run generate:locales --filter=@repo/i18n` from the root and make `dev`/`build` depend on that.
This avoids path/shell brittleness and lets turbo cache and schedule the work correctly.
```suggestion
"scripts": {
"dev": "bun run generate:locales && next dev",
"build": "bun run generate:locales && next build",
"start": "next start",
"generate:locales": "turbo run generate:locales --filter=@repo/i18n",
"generate:oauth-metadata": "bun lib/gen-oauth-metadata.mjs"
},
```
</issue_to_address>
### Comment 3
<location path="apps/web/tsconfig.json" line_range="13" />
<code_context>
+ "@/*": ["./*"],
+ "@/components/ui/*": ["../../packages/ui/src/*"],
+ "@/lib/i18n": ["../../packages/i18n/src/i18n.ts"],
+ "@/lib/locales": ["../../packages/i18n/src/locales.ts"]
+ }
+ },
</code_context>
<issue_to_address>
**suggestion:** Pointing a path alias directly at the generated locales file can cause editor/typecheck issues before generation runs.
Because `../../packages/i18n/src/locales.ts` is generated, it won’t exist (and TS/IDE will error) until `generate:locales` has run at least once. To avoid that, you could either:
- Point this alias at the i18n package entry (e.g. `@repo/i18n`) instead of the generated file, or
- Point it at a stable barrel file in the i18n package that re-exports from `./locales`, so the barrel is always present.
That way you keep `@/lib/locales` ergonomics without depending directly on a generated artifact.
Suggested implementation:
```
"@/components/ui/*": ["../../packages/ui/src/*"],
"@/lib/i18n": ["../../packages/i18n/src/i18n.ts"],
"@/lib/locales": ["@repo/i18n"]
```
For this to work cleanly, ensure that the `@repo/i18n` package's main entry exports the same `locales` surface that consumers expect from `@/lib/locales`. If it currently does not, add the appropriate re-exports in the i18n package (e.g., export `locales` or equivalent from its entry file).
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
package.json
Outdated
| "generate:locales": "turbo generate:locales --filter=@repo/i18n", | ||
| "generate:oauth-metadata": "turbo generate:oauth-metadata --filter=web" |
There was a problem hiding this comment.
issue (bug_risk): 这些 turbo 命令缺少 run 子命令,很可能无法执行预期的任务。
Turbo CLI 在执行任务时需要使用 turbo run <task>。按当前写法,这些脚本会失败,因为 turbo generate:locales 和 turbo generate:oauth-metadata 不会匹配到任何命令。请更新为:
"generate:locales": "turbo run generate:locales --filter=@repo/i18n",
"generate:oauth-metadata": "turbo run generate:oauth-metadata --filter=web"并在你新增的其他类似脚本中也遵循这一写法。
Original comment in English
issue (bug_risk): These turbo commands are missing the run subcommand and likely won't execute the intended tasks.
The turbo CLI requires turbo run <task> for task execution. As written, these scripts will fail because turbo generate:locales and turbo generate:oauth-metadata won’t match any command. Please update to:
"generate:locales": "turbo run generate:locales --filter=@repo/i18n",
"generate:oauth-metadata": "turbo run generate:oauth-metadata --filter=web"And follow this pattern for any similar scripts you add.
| "scripts": { | ||
| "dev": "(cd ../../packages/i18n && bun run generate:locales) && next dev", | ||
| "build": "(cd ../../packages/i18n && bun run generate:locales) && next build", | ||
| "start": "next start", | ||
| "generate:locales": "(cd ../../packages/i18n && bun run generate:locales)", | ||
| "generate:oauth-metadata": "bun lib/gen-oauth-metadata.mjs" | ||
| }, |
There was a problem hiding this comment.
suggestion: 使用子 Shell cd 的方式在运行前生成 locales 比较脆弱,而且绕过了 monorepo 的任务图。
这种模式对仓库目录结构和 Shell 行为进行了硬编码,并且绕开了 turbo 的依赖图和缓存机制。更好的做法是:
- 在
apps/web中添加一个generate:locales脚本,通过 turbo 的pipeline/dependsOn依赖@repo/i18n的generate:locales,或者 - 从根目录运行
turbo run generate:locales --filter=@repo/i18n,并让dev/build依赖该任务。
这样可以避免路径/ Shell 的脆弱性,并让 turbo 正确地进行缓存和调度。
| "scripts": { | |
| "dev": "(cd ../../packages/i18n && bun run generate:locales) && next dev", | |
| "build": "(cd ../../packages/i18n && bun run generate:locales) && next build", | |
| "start": "next start", | |
| "generate:locales": "(cd ../../packages/i18n && bun run generate:locales)", | |
| "generate:oauth-metadata": "bun lib/gen-oauth-metadata.mjs" | |
| }, | |
| "scripts": { | |
| "dev": "bun run generate:locales && next dev", | |
| "build": "bun run generate:locales && next build", | |
| "start": "next start", | |
| "generate:locales": "turbo run generate:locales --filter=@repo/i18n", | |
| "generate:oauth-metadata": "bun lib/gen-oauth-metadata.mjs" | |
| }, |
Original comment in English
suggestion: The subshell cd approach for pre-generating locales is fragile and bypasses the monorepo task graph.
This pattern hardcodes repo layout and shell behavior and sidesteps turbo’s dependency graph and caching. Instead, either:
- Add a
generate:localesscript inapps/webthat depends on@repo/i18n’sgenerate:localesvia turbo’spipeline/dependsOn, or - Run
turbo run generate:locales --filter=@repo/i18nfrom the root and makedev/builddepend on that.
This avoids path/shell brittleness and lets turbo cache and schedule the work correctly.
| "scripts": { | |
| "dev": "(cd ../../packages/i18n && bun run generate:locales) && next dev", | |
| "build": "(cd ../../packages/i18n && bun run generate:locales) && next build", | |
| "start": "next start", | |
| "generate:locales": "(cd ../../packages/i18n && bun run generate:locales)", | |
| "generate:oauth-metadata": "bun lib/gen-oauth-metadata.mjs" | |
| }, | |
| "scripts": { | |
| "dev": "bun run generate:locales && next dev", | |
| "build": "bun run generate:locales && next build", | |
| "start": "next start", | |
| "generate:locales": "turbo run generate:locales --filter=@repo/i18n", | |
| "generate:oauth-metadata": "bun lib/gen-oauth-metadata.mjs" | |
| }, |
| "@/*": ["./*"], | ||
| "@/components/ui/*": ["../../packages/ui/src/*"], | ||
| "@/lib/i18n": ["../../packages/i18n/src/i18n.ts"], | ||
| "@/lib/locales": ["../../packages/i18n/src/locales.ts"] |
There was a problem hiding this comment.
suggestion: 将路径别名直接指向生成的 locales 文件,可能会在生成步骤执行之前引发编辑器/类型检查错误。
由于 ../../packages/i18n/src/locales.ts 是生成文件,在至少运行过一次 generate:locales 之前它是不存在的,因此 TS/IDE 会报错。为了避免这个问题,你可以:
- 将该别名指向 i18n 包的入口(例如
@repo/i18n)而不是生成文件,或者 - 将其指向 i18n 包中一个稳定存在的 barrel 文件,该文件从
./locales中重新导出,这样 barrel 始终存在。
这样既能保留 @/lib/locales 的易用性,又不会直接依赖生成产物。
建议实现方式:
"@/components/ui/*": ["../../packages/ui/src/*"],
"@/lib/i18n": ["../../packages/i18n/src/i18n.ts"],
"@/lib/locales": ["@repo/i18n"]
为了让这一方案工作顺畅,需要确保 @repo/i18n 包的主入口导出与使用方期望从 @/lib/locales 获取的相同 locales 接口。如果当前还没有,请在 i18n 包的入口文件中添加相应的二次导出(例如导出 locales 或等效的对象/函数)。
Original comment in English
suggestion: Pointing a path alias directly at the generated locales file can cause editor/typecheck issues before generation runs.
Because ../../packages/i18n/src/locales.ts is generated, it won’t exist (and TS/IDE will error) until generate:locales has run at least once. To avoid that, you could either:
- Point this alias at the i18n package entry (e.g.
@repo/i18n) instead of the generated file, or - Point it at a stable barrel file in the i18n package that re-exports from
./locales, so the barrel is always present.
That way you keep @/lib/locales ergonomics without depending directly on a generated artifact.
Suggested implementation:
"@/components/ui/*": ["../../packages/ui/src/*"],
"@/lib/i18n": ["../../packages/i18n/src/i18n.ts"],
"@/lib/locales": ["@repo/i18n"]
For this to work cleanly, ensure that the @repo/i18n package's main entry exports the same locales surface that consumers expect from @/lib/locales. If it currently does not, add the appropriate re-exports in the i18n package (e.g., export locales or equivalent from its entry file).
Motivation
Description
turbo.json, convert the rootpackage.jsonto a workspace-aware monorepo config, and add workspace scripts usingturbo.apps/web/and addapps/web/package.json,tsconfig.json,postcss.config.mjs, andtailwind.config.tsthat re-export shared configs frompackages/config.packages/config,packages/i18n, andpackages/uipackages and move config files, locale JSON files, i18n runtime, UI components, and thegen-localesscript into these packages; update imports and paths accordingly (notablypackages/i18n/scripts/gen-locales.mjsandpackages/i18n/src/i18n.ts).tailwind.config.tsand.env.example, adjust.gitignoreto includeapps/web/.next/and the new generated locales path, and updateREADME.mdto document the monorepo structure and newbun/turbocommands.Testing
Codex Task
由 Sourcery 总结
将当前仓库转换为基于 Turbo 的 monorepo,并将应用和共享包拆分为各自的 workspace。
Build(构建):
package.json文件,其中包含共享的 config、UI 和 i18n 包,并对外导出配置和脚本。Documentation(文档):
Chores(日常维护):
apps/web,并相应调整路径、导入,以及生成的 locales/i18n 运行时代码位置。Original summary in English
Summary by Sourcery
Convert the repository into a Turbo-powered monorepo with separated app and shared package workspaces.
Build:
Documentation:
Chores: