Turborepo 示例中的 Next.js 应用实战:基于 `examples/basic` 的 `apps/web` 开发、构建与部署指南
2026/9/19 1:49:10 网站建设 项目流程

Turborepo 示例中的 Next.js 应用实战:基于examples/basicapps/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 中:它包含docsweb两个 Next.js 应用,以及@repo/ui(共享 React 组件库)、@repo/eslint-config(ESLint 配置,内置@next/eslint-plugin-nexteslint-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.4react / react-dom: 19.2.8
  • 工作区内部依赖@repo/ui: workspace:*
  • 开发脚本:devnext dev --port 3000)、buildnext build)、startnext start)、linteslint --max-warnings 0)、check-typesnext typegen && tsc --noEmit)。

二、环境准备:包管理器与依赖安装

整个示例使用 pnpm 作为包管理器(根 examples/basic/package.json 中packageManager指定为pnpm@11.25.0engines.node要求>=24),并通过 examples/basic/pnpm-workspace.yaml 声明工作区:

packages: - "apps/*" - "packages/*"

这意味着apps/webapps/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时,docsweb两个开发服务器可以并行常驻运行。

四、热更新迭代:编辑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.svgturborepo-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.variablegeistMono.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=web

build任务在 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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询