- 构建工具
- 开发工具
- CLI
【免费下载链接】turbo
Build system optimized for JavaScript and TypeScript, written in Rust
这篇技术指南围绕 Turborepo 官方示例仓库中的with-vue-nuxt模板展开,完整讲解如何用 Turborepo 编排一个同时包含 Nuxt 应用、Vite + Vue 3 应用以及共享 Vue 组件库的 pnpm monorepo。读完本文,你将掌握该模板的目录结构、turbo.json任务编排语义、跨应用共享ui包的方式,以及构建、开发与远程缓存的实际用法,可直接照搬到自己的 Vue 技术栈 monorepo 项目中。
示例定位:社区维护的 Vue/Nuxt Monorepo 模板
with-vue-nuxt是 Turborepo 仓库中的一个示例工程,其元信息(见 examples/with-vue-nuxt/meta.json)将其定位为 "Monorepo with Vue and Nuxt, sharing a UI Library",并由社区维护(maintainedByCoreTeam: false)。这意味着它演示的是一种真实、可复制的组织方式,而不是演示性的玩具工程:
- 两个独立应用:一个基于 Vite 的 Vue 3 单页应用(
web)与一个基于 Nuxt 的服务端渲染应用(docs); - 一个共享 UI 库:
ui包同时被两个应用以workspace:*协议依赖; - 完整的工程化配套:共享 TypeScript 配置、共享 ESLint 扁平配置、pnpm workspace 与 Turborepo 任务编排。
整仓采用 pnpm 作为包管理器(packageManager: pnpm@11.24.0,见 examples/with-vue-nuxt/package.json),workspace 声明在 examples/with-vue-nuxt/pnpm-workspace.yaml:
packages: - "apps/*" - "packages/*" allowBuilds: esbuild: true unrs-resolver: true即apps与packages目录下的所有子目录都是独立的 workspace 包,这是 Turbo 生态中最标准的 monorepo 布局约定。
快速启动:一条命令生成完整工程
模板的官方使用方式是借助create-turbo脚手架,从示例直接生成项目:
npx create-turbo@latest -e with-vue-nuxt执行后,脚手架会把整个示例(两个应用、三个包、根级turbo.json与 workspace 配置)复制到当前目录并安装依赖。安装完成后即可继续下文的任务操作。
仓库结构:Apps 与 Packages 全景
按 README 与源码,该模板的顶层结构如下:
| 目录/包 | 说明 |
|---|---|
apps/docs | Nuxt 应用(当前使用 Nuxt 4),默认运行在 3001 端口 |
apps/web | Vue 3 + Vite 应用,默认运行在 3000 端口 |
packages/ui | 被web与docs共享的 Vue 组件库 |
packages/eslint-config-custom | 面向 Vue 包的共享扁平 ESLint 配置 |
packages/tsconfig | 共享的tsconfig.json(含base.json、vue.json、nuxt.json) |
各包/应用均为 100% TypeScript。工程化工具链由 TypeScript 负责静态类型检查、ESLint 负责代码规范、Prettier 负责格式化——根级package.json中的format脚本即为 Prettier 全局格式化:
"scripts": { "build": "turbo run build", "dev": "turbo run dev", "lint": "turbo run lint", "format": "prettier --write \"**/*.{ts,tsx,md}\"" }任务编排核心:turbo.json 逐项拆解
模板的 Turborepo 配置集中在 examples/with-vue-nuxt/turbo.json,是理解整个示例行为的关键:
{ "$schema": "https://turborepo.com/schema.json", "tasks": { "build": { "dependsOn": ["^build"], "inputs": ["$TURBO_DEFAULT$", ".env*"], "outputs": [".nuxt/**", ".output/**", "dist/**"] }, "lint": {}, "dev": { "cache": false, "persistent": true } } }各配置项的实际语义如下:
build.dependsOn: ["^build"]:声明build任务依赖其拓扑依赖的build任务(^前缀表示“上游依赖”)。这保证ui包先于web、docs构建完成,Turborepo 会据此自动计算并行的构建调度顺序;build.inputs: ["$TURBO_DEFAULT$", ".env*"]:定义参与缓存哈希的文件集合。$TURBO_DEFAULT$是内置占位符(默认覆盖package.json、turbo.json等全局关键文件),.env*将环境变量文件纳入哈希,任何.env变化都会使缓存失效,避免“改了环境变量却命中旧缓存”的经典问题;build.outputs: [".nuxt/**", ".output/**", "dist/**"]:声明构建产物目录。.nuxt与.output对应 Nuxt 构建中间产物与最终产物,dist对应 Vite 构建产物。Turborepo 只缓存这些目录,命中缓存时直接恢复产物并跳过实际构建;lint: {}:空配置即采用默认行为——每个包的lint脚本独立执行,输入变化才重跑,正常参与缓存;dev: { cache: false, persistent: true }:开发服务器既不缓存也不退出。persistent: true告诉 Turborepo 该任务会长时间占用进程,从而避免调度器在它“未结束”时误判失败或重复拉起,同时turbo run dev会把web(3000)与docs(3001)两个开发服务器并行拉起。
应用层细节:Nuxt 与 Vite 的差异化脚本设计
Nuxt 应用apps/docs
其脚本定义在 examples/with-vue-nuxt/apps/docs/package.json:
"scripts": { "build": "nuxt build", "dev": "nuxt dev --port 3001", "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare", "lint": "eslint ." }要点:dev显式固定--port 3001,与web的 3000 错开端口,保证turbo run dev并行启动时互不冲突;postinstall中的nuxt prepare会在依赖安装后自动生成 Nuxt 的类型声明与虚拟文件,是 Nuxt 3/4 工程在 monorepo 中的常见实践。Nuxt 配置 examples/with-vue-nuxt/apps/docs/nuxt.config.ts 启用了@nuxt/eslint模块与 devtools:
export default defineNuxtConfig({ modules: ["@nuxt/eslint"], devtools: { enabled: true }, });应用入口 examples/with-vue-nuxt/apps/docs/app.vue 直接演示了跨包引用的写法——从ui导入Page组件并注入当前包名:
<script setup lang="ts"> import { Page } from "ui"; import { name } from "./package.json"; useHead({ title: "Create Turborepo (vue-nuxt:docs)", meta: [{ name: "description", content: "Generated by create turbo" }], }); </script> <template> <Page :app-name="name" /> </template>注意这里的import { Page } from "ui":依赖名ui直接指向 workspace 包,无需相对路径穿越,这正是 monorepo 包引用模式的直观体现。
Vue 3 应用apps/web
脚本定义在 examples/with-vue-nuxt/apps/web/package.json:
"scripts": { "dev": "vite --port 3000", "build": "run-p check-types \"build-only {@}\" --", "preview": "vite preview", "build-only": "vite build", "check-types": "vue-tsc --noEmit -p tsconfig.app.json --composite false", "lint": "eslint ." }构建链路值得注意:build使用npm-run-all2的run-p并行执行check-types(vue-tsc类型检查,--composite false用于规避 project references 下的增量编译约束)与build-only(vite build),把“类型检查 + 打包”组合成一次 Turbo 可缓存的原子任务。Vite 配置 examples/with-vue-nuxt/apps/web/vite.config.ts 注册了@vitejs/plugin-vue并配置了@指向src的路径别名:
import { fileURLToPath, URL } from "node:url"; import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; export default defineConfig({ plugins: [vue()], resolve: { alias: { "@": fileURLToPath(new URL("./src", import.meta.url)), }, }, });共享 UI 库packages/ui
ui包的公共入口是 examples/with-vue-nuxt/packages/ui/index.ts,以命名导出暴露三个组件:
import Card from "./src/card.vue"; import Gradient from "./src/gradient.vue"; import Page from "./src/page.vue"; export { Card, Gradient, Page };其中 page.vue 是一个包含品牌展示区、链接卡片网格与响应式样式(含prefers-reduced-motion无障碍适配与移动端断点)的完整页面组件,通过defineProps<{ appName: string }>()接收应用名。web与docs两个应用都通过"ui": "workspace:*"依赖它,做到“一套组件、两端复用”。这正是 Turborepobuild.dependsOn: ["^build"]发挥作用的最小闭环:ui作为上游先构建,两个应用再消费其产物。
日常开发工作流
在仓库根目录执行(以下命令均基于根级 examples/with-vue-nuxt/package.json 的脚本):
开发模式(并行启动两个 dev server):
pnpm dev内部执行turbo run dev,依据turbo.json中dev的persistent: true与cache: false语义并行常驻运行:web在 http://localhost:3000,docs在 http://localhost:3001。
构建全部应用与包:
pnpm build内部执行turbo run build,Turborepo 会按dependsOn: ["^build"]先构建ui、tsconfig等依赖,再并行构建两个应用,并将产物按outputs声明缓存(.nuxt/**、.output/**、dist/**)。二次构建若输入未变化将直接命中本地缓存,秒级完成。
代码检查与格式化:
pnpm lint # 等价于 turbo run lint,逐个包执行 eslint pnpm format # prettier --write "**/*.{ts,tsx,md}" 全仓格式化远程缓存:让构建产物跨机器共享
模板默认使用 Turborepo 的本地缓存;若需在团队成员与 CI/CD 之间共享缓存产物,可按 README 中的指引启用 Remote Caching(以 Vercel Remote Cache 为例):
登录并认证 Turborepo CLI 与 Vercel 账号:
pnpm turbo login在仓库根目录将当前仓库链接到远程缓存:
pnpm turbo link
启用后,任意机器上以相同输入执行turbo run build,都可直接拉取远程缓存的构建产物,跳过重复计算——在 CI 上体现为构建时间的大幅缩短。不配置远程缓存时,Turborepo 仍会在本地(node_modules/.cache/turbo或系统缓存目录)正常缓存,功能不受影响。
进阶:基于模板扩展自己的 Vue monorepo
从源码结构可以推断出几条清晰的扩展路径:
- 新增一个 Vue 应用:在
apps/下复制web的结构,保持pnpm-workspace.yaml的apps/*通配即可被自动识别,无需改动根级turbo.json——build、dev、lint任务会自动覆盖新包; - 新增一个共享包:在
packages/下仿照ui建立新包,并在消费方package.json中声明"your-pkg": "workspace:*"; - 细化任务:例如为
test、typecheck增加任务配置,或按需调整inputs(如把src/**加入哈希集合)以提升缓存命中精度。
需要说明的是,本模板属于社区维护示例,其依赖版本(Nuxt 4、Vite 8、pnpm 11 等)以仓库当前实际内容为准,若迁移到自己的工程请按需对齐版本。
- 构建工具
- 开发工具
- CLI
【免费下载链接】turbo
Build system optimized for JavaScript and TypeScript, written in Rust
相关推荐
Turborepo with-vite 示例详解:用 Vite 构建共享 UI 库的多应用 TypeScript 单仓
Turborepo with vite 示例详解:用 Vite 构建共享 UI 库的多应用 TypeScript 单仓 本篇指南围绕 Turborepo 官方的
构建工具开发工具CLITurborepo 实战:在 Monorepo 中共享 Tailwind CSS 主题与 React 组件库(with-tailwind 示例解析)
Turborepo 实战:在 Monorepo 中共享 Tailwind CSS 主题与 React 组件库 with tailwind 示例解析 本篇以 Tu
构建工具开发工具CLIshadcn/ui Astro Monorepo 模板实战:用 pnpm Workspaces + Turborepo 搭建共享 React 组件库
shadcn/ui Astro Monorepo 模板实战:用 pnpm Workspaces + Turborepo 搭建共享 React 组件库 本篇基于仓
前端UI组件设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考