跳到主要内容

Cursor 中的 Monorepo 管理:Turborepo、Nx 和 pnpm Workspaces

Monorepo Management in Cursor

Monorepo 允许你将多个包或应用程序保存在单个仓库中,共享代码、配置和工具。Cursor 是一款 AI 驱动的 IDE 编辑器,通过理解跨包关系、生成管道配置和安全地重构共享 API,使 monorepo 管理变得极其简单。本指南涵盖 Turborepo、Nx 和 pnpm workspaces,以及 AI 辅助依赖管理和跨包重构的实用技术。

前提条件​

在开始之前,请确保你具备以下条件:

  • Cursor(建议使用最新版本)作为你的 IDE 编辑器
  • Node.js 18 或更高版本
  • 全局安装 pnpm(npm install -g pnpm)
  • 对包管理器和工作区有基本了解
提示

Cursor 的内置终端和多根工作区支持使其非常适合 monorepo。在 Cursor 中打开仓库根目录,以便 AI 可以同时看到每个包。这为编辑器提供了完整的上下文,用于跨包重构和依赖分析。

选择 Monorepo 工具​

三种工具主导了 JavaScript 和 TypeScript monorepo 领域。每种工具都有不同的优势:

工具最适合关键优势
pnpm workspaces中小型 monorepo快速、磁盘高效的安装
Turborepo以应用为中心的 monorepo简单的任务缓存和并行运行
Nx大型、插件密集的 monorepo强大的代码生成和依赖图

让 Cursor 的 AI 为你的情况推荐工具:

I have a monorepo with 2 Next.js apps, a shared React component library,
and 3 utility packages. Should I use Turborepo or Nx? Compare them.

Cursor 解释了权衡取舍,并为你选择的工具生成初始配置。

在 Cursor 中设置 pnpm Workspaces​

pnpm workspaces 是大多数现代 monorepo 的基础,因为它们的速度和硬链接磁盘效率。Cursor 帮助你定义工作区并引导初始包。

创建工作区根目录​

在 Cursor 中打开一个新文件夹,让 AI 搭建 pnpm 工作区:

Create a pnpm workspace monorepo with:
- A root package.json with pnpm workspace config
- A pnpm-workspace.yaml listing apps/* and packages/*
- A shared TypeScript config package
- An .npmrc with shared-cache settings

Cursor 生成根文件:

# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
// package.json
{
"name": "cursor-monorepo",
"private": true,
"scripts": {
"dev": "pnpm -r --parallel run dev",
"build": "pnpm -r run build",
"lint": "pnpm -r run lint",
"test": "pnpm -r run test"
},
"devDependencies": {
"typescript": "^5.4.0"
}
}
# .npmrc
shared-cache-max-age=86400
auto-install-peers=true
strict-peer-dependencies=false

创建初始包​

让 Cursor 生成一个共享 UI 包和一个使用它的 Web 应用:

Create a packages/ui React component library and an apps/web Next.js app.
The web app should depend on the ui package using workspace:* protocol.

Cursor 生成包结构:

monorepo/
apps/
web/
package.json
src/
app/page.tsx
packages/
ui/
package.json
src/
index.ts
Button.tsx
pnpm-workspace.yaml
package.json

packages/ui/package.json:

{
"name": "@cursor-monorepo/ui",
"version": "0.1.0",
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"lint": "eslint .",
"build": "tsc"
},
"peerDependencies": {
"react": "^18.0.0"
}
}

apps/web/package.json 使用工作区协议引用共享包:

{
"name": "@cursor-monorepo/web",
"version": "0.1.0",
"dependencies": {
"@cursor-monorepo/ui": "workspace:*",
"next": "^14.0.0",
"react": "^18.0.0"
}
}

从根目录使用 Cursor 的终端安装所有内容:

pnpm install

pnpm 硬链接依赖,因此安装速度快且磁盘效率高。

注意

引用内部包时,始终使用 workspace:* 协议(或 workspace:^)。如果你固定版本号如 1.0.0,pnpm 会尝试从注册表获取包而不是解析本地包,导致安装时出现令人困惑的"找不到包"错误。

在 Cursor 中集成 Turborepo​

Turborepo 在 pnpm workspaces 之上添加了缓存和并行任务执行。Cursor 生成管道配置并帮助你调优。

将 Turborepo 添加到现有工作区​

让 Cursor 将 Turborepo 添加到你的 monorepo:

Add Turborepo to my pnpm workspace. Create a turbo.json with build,
dev, lint, and test pipelines. Configure build dependencies and caching.

Cursor 安装依赖并生成 turbo.json:

pnpm add -Dw turbo
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"],
"inputs": [
"src/**",
"package.json",
"tsconfig.json"
]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {
"dependsOn": ["^build"],
"outputs": []
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"inputs": ["src/**", "test/**", "package.json"]
}
}
}

dependsOn: ["^build"] 指令告诉 Turborepo 在构建包本身之前先构建包的依赖项,这对于应用程序依赖共享库的 monorepo 至关重要。

使用 Turbo 运行任务​

从 Cursor 的终端在整个 monorepo 中运行任务:

# Build all packages in topological order
pnpm turbo run build

# Run dev servers in parallel
pnpm turbo run dev --parallel

# Filter to a single package and its dependents
pnpm turbo run build --filter=@cursor-monorepo/web...

... 后缀表示"此包及依赖它的所有内容",这在更改共享库时进行影响分析非常有用。

提示

使用 --filter 标志和 ^ 前缀来仅运行一个包及其依赖的任务。例如,pnpm turbo run build --filter=^@cursor-monorepo/web 仅构建 Web 应用所需的包,跳过不相关的工作。这对于快速本地反馈循环非常有价值。

配置远程缓存​

远程缓存让你的团队共享构建结果。让 Cursor 设置 Vercel 远程缓存:

Configure Turborepo remote caching for my monorepo. Generate the
.nenv example and explain how to link the cache.

Cursor 解释步骤:

npx turbo login
npx turbo link

添加 turbo.json 环境提示,以便缓存键包含正确的变量:

{
"globalEnv": ["NODE_ENV", "CI"]
}

在 Cursor 中集成 Nx​

Nx 是一个更强大的 monorepo 工具,具有代码生成器、依赖图和对许多框架的插件支持。Cursor 帮助你引导和扩展 Nx 项目。

创建 Nx 工作区​

让 Cursor 创建一个 Nx 工作区:

Create an Nx integrated monorepo with:
- A React app named storefront
- A Node API app named api
- A shared types library
- pnpm as the package manager

Cursor 运行脚手架并解释结果:

npx create-nx-workspace@latest cursor-nx --preset=apps --packageManager=pnpm

生成的结构:

cursor-nx/
apps/
storefront/
api/
libs/
types/
nx.json
project.json

使用 Nx 插件生成代码​

Nx 插件提供生成器以实现一致的脚手架。让 Cursor 生成一个 React 组件库:

Generate a React library named ui with buildable true and
Storybook configuration using the @nx/react plugin.
npx nx g @nx/react:library ui --buildable --storybook --directory=libs/ui

可视化依赖图​

Nx 附带一个图可视化器。从 Cursor 的终端运行它:

npx nx graph

这会在浏览器中打开一个交互式图,显示包之间的依赖关系。如果你询问,Cursor 的 AI 也可以用文本描述图:

List all packages that depend on libs/types and would break if I
renamed its default export.

Cursor 读取工作区配置并返回影响分析,这在重构共享代码之前至关重要。

注意

Nx 集成工作区在 tsconfig.base.json 中使用路径映射进行导入。如果你添加新库,必须更新 paths 映射,否则 TypeScript 无法解析导入。当你看到"Cannot find module"错误时,Cursor 的 AI 可以检测缺失的路径映射并建议修复。

AI 辅助的依赖管理​

在 monorepo 中保持依赖一致性是最困难的维护任务之一。Cursor 的 AI 在这方面表现出色。

审计版本不匹配​

让 Cursor 查找依赖不匹配:

Scan all package.json files in my monorepo and report any
dependencies that have inconsistent versions across packages.
Suggest a single pinned version for each.

Cursor 读取每个 package.json,列出不匹配项,并可以生成对齐脚本:

# Align react to 18.2.0 everywhere

检测未使用的依赖​

Cursor 可以检测在 package.json 中声明但从未导入的包。询问:

Find unused dependencies in the apps/web package by checking
imports across all source files.

Cursor 报告未使用的条目并建议删除命令:

pnpm --filter @cursor-monorepo/web remove unused-package-name

管理共享开发依赖​

将共享开发工具(ESLint、Prettier、TypeScript)提升到工作区根目录,以避免版本漂移。Cursor 生成一个共享配置包:

Create a packages/config package that exports shared ESLint,
TypeScript, and Prettier configs so other packages can extend them.
// packages/config/package.json
{
"name": "@cursor-monorepo/config",
"version": "0.1.0",
"files": ["eslint", "tsconfig", "prettier"],
"devDependencies": {
"eslint": "^8.57.0",
"prettier": "^3.2.0"
}
}
// packages/config/eslint/base.js
module.exports = {
extends: ['next', 'prettier'],
rules: {
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
'no-console': ['warn', { allow: ['warn', 'error'] }],
},
};

其他包继承共享配置:

{
"eslintConfig": { "extends": "@cursor-monorepo/config/eslint" }
}
提示

使用 pnpm 的 catalog 功能(或 Renovate)在一个地方集中版本号。询问 Cursor:"为所有共享依赖版本设置 pnpm catalog,"它将创建 pnpm-workspace.yaml catalog 块,使单一版本更新自动传播到所有地方。

使用 Cursor 进行跨包重构​

重构共享 API 会影响每个使用者。Cursor 的代码库索引让 AI 可以跟踪整个 monorepo 中的使用情况,使大规模重构安全。

重命名共享导出​

假设你想将 packages/ui 中的 Button 组件重命名为 ActionButton。让 Cursor 的 Agent 执行:

Rename the Button component to ActionButton across the entire
monorepo. Update the export, the type, all imports, and the
Storybook stories. Run the build to verify nothing is broken.

Cursor 一次性执行多文件编辑:

// packages/ui/src/ActionButton.tsx
import React from 'react';

export interface ActionButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'secondary';
}

export const ActionButton = ({ label, onClick, variant = 'primary' }: ActionButtonProps) => (
<button className={`btn btn-${variant}`} onClick={onClick}>
{label}
</button>
);
// packages/ui/src/index.ts
export { ActionButton } from './ActionButton';
export type { ActionButtonProps } from './ActionButton';
// apps/web/src/app/page.tsx
import { ActionButton } from '@cursor-monorepo/ui';

export default function Home() {
return <ActionButton label="Get Started" onClick={() => alert('hi')} />;
}

提取共享工具​

当你发现跨包重复的逻辑时,让 Cursor 提取它:

Extract the date formatting logic duplicated in apps/web and apps/api
into a new shared package called @cursor-monorepo/format. Update all
call sites to import from the new package.

Cursor 创建包、移动代码、更新导入,并运行受影响的构建以确认成功。

注意

跨包重构后,始终运行完整的测试套件和整个工作区的类型检查。单个遗漏的导入可以单独编译,但在组合包时失败。从根目录运行 pnpm -r run build && pnpm -r run test 来及早发现这些问题。

工作区配置和工具​

跨包一致的工具保持 monorepo 健康。Cursor 可以为 TypeScript、ESLint 和 CI 生成共享配置。

共享 TypeScript 配置​

Create a shared tsconfig base at packages/config/tsconfig/base.json
with strict mode, path aliases, and modern lib settings.
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"strict": true,
"noUncheckedIndexedAccess": true,
"moduleResolution": "bundler",
"module": "ESNext",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
}
}

每个包继承它:

{
"extends": "@cursor-monorepo/config/tsconfig/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}

使用 GitHub Actions 的 CI 管道​

让 Cursor 生成一个利用 Turborepo 缓存的 CI 管道:

Create a GitHub Actions workflow that:
- Installs pnpm and Node
- Restores the pnpm store cache
- Runs turbo run lint build test with caching
- Only runs affected tasks on pull requests
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v3
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- uses: actions/cache@v4
with:
path: .turbo
key: turbo-${{ runner.os }}-${{ github.sha }}
restore-keys: turbo-${{ runner.os }}-
- run: pnpm turbo run lint build test

最佳实践总结​

在 Cursor 中管理 monorepo 时,请牢记以下原则:

  • 打开工作区根目录,以便 Cursor 看到每个包以获得跨包上下文。
  • 使用工作区协议(workspace:*)进行内部包引用。
  • 将共享开发工具提升到配置包以避免版本漂移。
  • 利用任务缓存(Turborepo 或 Nx)保持 CI 快速。
  • 在重构共享 API 之前运行影响分析。
  • 使用 pnpm catalogs 或 Renovate 集中版本。

通过将稳健的 monorepo 工具与 Cursor 的 AI 驱动代码库理解相结合,你可以自信地重构共享代码、保持依赖对齐,并在许多包中交付一致的工具。清晰地描述你的意图,让 Cursor 处理样板代码和跨文件编辑,并在提交前审查生成的差异。