Turborepo 示例中的 Next.js 应用实战:基于examples/basic的apps/web开发、构建与部署指南
【免费下载链接】turboBuild system optimized for JavaScript and TypeScript, written in Rust项目地址: https://gitcode.com/gh_mirrors/tu/turbo
本指南以 Turborepo 官方 basic 示例中的apps/web应用为对象,讲解在一个由 Rust 编写、专为 JavaScript/TypeScript 优化的构建系统 Turborepo 管理的 monorepo 中,如何启动 Next.js 开发服务器、利用热更新迭代页面、集成共享 UI 包,并完成构建与部署。读完本文,你将掌握在examples/basic这一双 Next.js 应用 + 多个共享包的仓库结构中,独立运行与交付web应用的完整实操路径。
一、示例背景:web应用在 monorepo 中的位置
examples/basic是 Turborepo 官方维护的入门 starter,其整体结构定义在根目录的 examples/basic/README.md 中:它包含docs与web两个 Next.js 应用,以及@repo/ui(共享 React 组件库)、@repo/eslint-config(ESLint 配置,内置@next/eslint-plugin-next与eslint-config-prettier)、@repo/typescript-config(全仓库统一的tsconfig.json基座)等包,所有应用与包均为 100% TypeScript。
本文的主角 examples/basic/apps/web/README.md 是web应用自身的引导文档。它本质上是一个由create-next-app生成的 Next.js 项目骨架说明,但在 Turborepo 语境下,它代表了 monorepo 中单个叶子应用的标准开发入口。web应用的关键依赖与脚本定义在 examples/basic/apps/web/package.json:
next: 16.3.4、react / react-dom: 19.2.8;- 工作区内部依赖
@repo/ui: workspace:*; - 开发脚本:
dev(next dev --port 3000)、build(next build)、start(next start)、lint(eslint --max-warnings 0)、check-types(next typegen && tsc --noEmit)。
二、环境准备:包管理器与依赖安装
整个示例使用 pnpm 作为包管理器(根 examples/basic/package.json 中packageManager指定为pnpm@11.25.0,engines.node要求>=24),并通过 examples/basic/pnpm-workspace.yaml 声明工作区:
packages: - "apps/*" - "packages/*"这意味着apps/web与apps/docs自动成为工作区成员。安装全部依赖时,在示例根目录执行:
pnpm install由于web通过workspace:*协议引用@repo/ui,pnpm 会建立软链接,使web可以像使用普通 npm 包一样import { Button } from "@repo/ui/button"(对应 examples/basic/packages/ui/package.json 中的"./*": "./src/*.tsx"导出映射),而无需手工配置路径别名。
三、启动开发服务器:npm run dev与 Turborepo 的两种姿势
原文档给出的启动方式是进入应用目录直接运行包管理器脚本:
npm run dev # or yarn dev # or pnpm dev # or bun dev四种方式等价,最终都执行next dev --port 3000(端口由 examples/basic/apps/web/package.json 的dev脚本显式指定为 3000)。随后在浏览器打开 http://localhost:3000 即可看到页面。
不过,在 Turborepo 的 monorepo 中更常见的做法是从仓库根目录用turbo统一调度。在 examples/basic/README.md 中给出了两种写法:
# 全局安装 turbo(推荐) turbo dev # 或通过包管理器按需调用 npx turbo dev pnpm exec turbo dev如果只想启动web这一个应用,可以使用 filter 缩小任务范围:
turbo dev --filter=web这里dev任务的特殊之处体现在根 examples/basic/turbo.json 的配置中:
{ "dev": { "cache": false, "persistent": true } }persistent: true表示该任务是一个不会自行结束的长驻进程(开发服务器),Turborepo 会据此调整调度与退出逻辑;cache: false则表明开发模式不参与缓存——这也解释了为什么在根目录turbo dev时,docs与web两个开发服务器可以并行常驻运行。
四、热更新迭代:编辑app/page.tsx即可即时生效
原文档强调:"You can start editing the page by modifyingapp/page.tsx. The page auto-updates as you edit the file." 这正是 Next.js App Router 的热更新(Fast Refresh)机制。在 examples/basic/apps/web/app/page.tsx 中可以看到该示例页面的实际实现:
- 自定义
ThemeImage组件:通过srcLight/srcDark两个属性分别传入明暗主题下的 Logo 图(turborepo-dark.svg与turborepo-light.svg),利用next/image渲染,由 examples/basic/apps/web/app/page.module.css 中的imgLight/imgDark类配合暗色模式控制显隐; - 通过
import { Button } from "@repo/ui/button"使用共享组件库中的按钮,这是 monorepo 内部依赖的直观演示——Button的实现位于 examples/basic/packages/ui/src/button.tsx,它是一个标注了"use client"的客户端组件,点击后弹出Hello from your ${appName} app!提示。
这意味着你在 monorepo 中编辑任何一层代码都能获得即时反馈:既包括web自己的页面与样式,也包括@repo/ui中的共享组件——只要 Turborepo 与 Next.js 的文件监听正常运行,保存即可热更新。
五、字体优化:从next/font到本地字体加载
原文档提到项目使用next/font自动优化并加载自定义 Google 字体 Inter。这一句来自create-next-app模板。在 Turborepo 的 basic 示例中,实际实现有所演进:根布局 examples/basic/apps/web/app/layout.tsx 改用next/font/local加载仓库本地字体文件:
import localFont from "next/font/local"; const geistSans = localFont({ src: "./fonts/GeistVF.woff", variable: "--font-geist-sans", }); const geistMono = localFont({ src: "./fonts/GeistMonoVF.woff", variable: "--font-geist-mono", });字体文件位于 examples/basic/apps/web/app/fonts(GeistVF.woff 与 GeistMonoVF.woff)。通过variable选项将字体挂载为 CSS 变量,再在<body>上拼接geistSans.variable与geistMono.variable,供 examples/basic/apps/web/app/globals.css 中的全局样式引用。无论采用 Inter 还是本地 Geist,核心收益一致:字体随页面自托管加载,避免布局偏移(CLS),符合 Next.js 内置的最佳实践。
六、构建、类型检查与产物缓存
除了开发模式,web应用还内置了生产构建与质量检查脚本:
npm run build # next build npm run start # next start(生产模式运行) npm run lint # eslint --max-warnings 0,任何 warning 都视为失败 npm run check-types # next typegen && tsc --noEmit在根目录通过 Turborepo 执行时:
turbo build --filter=web turbo lint --filter=web turbo check-types --filter=webbuild任务在 examples/basic/turbo.json 中的定义值得关注:
"build": { "dependsOn": ["^build"], "inputs": ["$TURBO_DEFAULT$", ".env*"], "outputs": [".next/**", "!.next/cache/**", "!.next/dev/**"] }dependsOn: ["^build"]:声明web的构建依赖其上游依赖(@repo/ui)先完成构建,Turborepo 会据此自动建立任务依赖图;inputs:参与哈希计算的输入,$TURBO_DEFAULT$代表默认的文件集合(源码等),.env*将环境变量文件纳入缓存指纹;outputs:声明可缓存的产物目录.next/**,同时排除!.next/cache/**与!.next/dev/**,避免开发缓存污染构建缓存。
这是 Turborepo 增量构建与缓存命中的核心机制:当web的源码或依赖未变化时,再次运行turbo build会直接复用上次的构建产物,从而显著加速本地与 CI 的构建。
七、部署:将web应用发布到生产环境
原文档建议使用 Vercel 平台部署 Next.js 应用,并提示查阅 Next.js 官方部署文档。在 Turborepo 场景下,部署web应用时通常需要告诉托管平台"根目录"是apps/web(Vercel 支持在项目设置中指定 Root Directory 为apps/web),同时保留根目录的 lockfile 与turbo.json以便安装与构建。示例首页 examples/basic/apps/web/app/page.tsx 中的 "Deploy now" 按钮即指向 Vercel 的模板化部署入口,整个 basic 示例也可直接从根 examples/basic/README.md 中描述的npx create-turbo@latest一键生成后进行部署。
八、继续深入:仓库内的参考资源
围绕web应用及其运行环境,你可以在当前仓库中继续挖掘以下资源:
- 应用本体:examples/basic/apps/web/app/page.tsx、examples/basic/apps/web/app/layout.tsx、examples/basic/apps/web/package.json;
- 共享依赖:examples/basic/packages/ui/src/button.tsx、examples/basic/packages/ui/package.json;
- 任务编排:examples/basic/turbo.json;
- 工作区与示例说明:examples/basic/pnpm-workspace.yaml、examples/basic/README.md;
- 应用级工程配置:examples/basic/apps/web/next.config.js、examples/basic/apps/web/tsconfig.json。
此外,apps/docs(见 examples/basic/apps/docs/README.md)与web结构完全对称,可作为对照,理解同一套 Turborepo 任务管线如何被多个 Next.js 应用共享。更完整的 Turborepo 任务、缓存与过滤机制,可进一步查阅仓库根目录的 README.md 与示例目录中的其他示例。
【免费下载链接】turboBuild system optimized for JavaScript and TypeScript, written in Rust项目地址: https://gitcode.com/gh_mirrors/tu/turbo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考