Turborepo 实战:用 with-vue-nuxt 示例构建 Vue 3 + Nuxt 共享 UI 库的 Monorepo
2026/9/19 21:50:09 网站建设 项目流程
  • 构建工具
  • 开发工具
  • CLI

【免费下载链接】turbo

Build system optimized for JavaScript and TypeScript, written in Rust

项目地址:https://gitcode.com/gh_mirrors/tu/turbo
点击查看免费下载

这篇技术指南围绕 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

appspackages目录下的所有子目录都是独立的 workspace 包,这是 Turbo 生态中最标准的 monorepo 布局约定。

快速启动:一条命令生成完整工程

模板的官方使用方式是借助create-turbo脚手架,从示例直接生成项目:

npx create-turbo@latest -e with-vue-nuxt

执行后,脚手架会把整个示例(两个应用、三个包、根级turbo.json与 workspace 配置)复制到当前目录并安装依赖。安装完成后即可继续下文的任务操作。

仓库结构:Apps 与 Packages 全景

按 README 与源码,该模板的顶层结构如下:

目录/包说明
apps/docsNuxt 应用(当前使用 Nuxt 4),默认运行在 3001 端口
apps/webVue 3 + Vite 应用,默认运行在 3000 端口
packages/uiwebdocs共享的 Vue 组件库
packages/eslint-config-custom面向 Vue 包的共享扁平 ESLint 配置
packages/tsconfig共享的tsconfig.json(含base.jsonvue.jsonnuxt.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包先于webdocs构建完成,Turborepo 会据此自动计算并行的构建调度顺序;
  • build.inputs: ["$TURBO_DEFAULT$", ".env*"]:定义参与缓存哈希的文件集合。$TURBO_DEFAULT$是内置占位符(默认覆盖package.jsonturbo.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-all2run-p并行执行check-typesvue-tsc类型检查,--composite false用于规避 project references 下的增量编译约束)与build-onlyvite 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 }>()接收应用名。webdocs两个应用都通过"ui": "workspace:*"依赖它,做到“一套组件、两端复用”。这正是 Turborepobuild.dependsOn: ["^build"]发挥作用的最小闭环:ui作为上游先构建,两个应用再消费其产物。

日常开发工作流

在仓库根目录执行(以下命令均基于根级 examples/with-vue-nuxt/package.json 的脚本):

开发模式(并行启动两个 dev server):

pnpm dev

内部执行turbo run dev,依据turbo.jsondevpersistent: truecache: false语义并行常驻运行:web在 http://localhost:3000,docs在 http://localhost:3001。

构建全部应用与包:

pnpm build

内部执行turbo run build,Turborepo 会按dependsOn: ["^build"]先构建uitsconfig等依赖,再并行构建两个应用,并将产物按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 为例):

  1. 登录并认证 Turborepo CLI 与 Vercel 账号:

    pnpm turbo login
  2. 在仓库根目录将当前仓库链接到远程缓存:

    pnpm turbo link

启用后,任意机器上以相同输入执行turbo run build,都可直接拉取远程缓存的构建产物,跳过重复计算——在 CI 上体现为构建时间的大幅缩短。不配置远程缓存时,Turborepo 仍会在本地(node_modules/.cache/turbo或系统缓存目录)正常缓存,功能不受影响。

进阶:基于模板扩展自己的 Vue monorepo

从源码结构可以推断出几条清晰的扩展路径:

  • 新增一个 Vue 应用:在apps/下复制web的结构,保持pnpm-workspace.yamlapps/*通配即可被自动识别,无需改动根级turbo.json——builddevlint任务会自动覆盖新包;
  • 新增一个共享包:在packages/下仿照ui建立新包,并在消费方package.json中声明"your-pkg": "workspace:*"
  • 细化任务:例如为testtypecheck增加任务配置,或按需调整inputs(如把src/**加入哈希集合)以提升缓存命中精度。

需要说明的是,本模板属于社区维护示例,其依赖版本(Nuxt 4、Vite 8、pnpm 11 等)以仓库当前实际内容为准,若迁移到自己的工程请按需对齐版本。

  • 构建工具
  • 开发工具
  • CLI

【免费下载链接】turbo

Build system optimized for JavaScript and TypeScript, written in Rust

项目地址:https://gitcode.com/gh_mirrors/tu/turbo
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询