从 Nx 迁移

本指南将帮助你将现有的 Nx 仓库迁移到 Turborepo。

为什么要切换?

你可能有很多原因选择从 Nx 迁移到 Turborepo。以下是开发者提到的最常见的迁移动机。

使用生态系统标准

Turborepo 的目标是保持轻量级,以你的仓库作为真实来源。一个例子是 Turborepo 在 JavaScript/TypeScript 支持方面构建在 JavaScript 包管理器工作空间之上

相比之下,Nx 使用插件层、依赖项和其他 Nx 特定代码来推断你的仓库信息。虽然这些插件可以提供功能层并且是可选的,但想要迁移的 Nx 用户经常提到从代码库中移除 Nx 特定代码是他们改变的一个关键动机。

对源代码的更大控制

Nx 的理念涉及用插件层、依赖项和 Nx 特定代码包装你的代码。虽然这些代码层是可选的,但它们提供了 Nx 的大部分价值,并且是 Nx 推荐的,所以大多数 Nx 仓库都有它们。在迁移到 Turborepo 时,许多开发者解释说这些层往往会创建一个抽象层,使他们的仓库脱离他们的控制,从而导致问题。

Turborepo 选择让你按照自己的条件处理工具,随意配置(或不配置)任何工具。

仓库管理器的配置更少

迁移到 Turborepo 可能需要删除你之前为 Nx 设置的配置,并用更少的 Turborepo 配置替换它,因为 Turborepo 会自动推断你的仓库需求。例如,以下是 Turborepo 和 Nx 在下面使用的等效启动器中的工具特定配置。

Turborepo logo
turbo.json
{
  "$schema": "/schema.json",
  "ui": "tui",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "check-types": {
      "dependsOn": ["^check-types"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

免费的远程缓存

Turborepo 的远程缓存将你的任务结果存储在云服务器上。这通过防止整个组织重复工作节省了大量时间。Vercel 远程缓存已经为团队节省了超过 500 年的计算时间。

从 Nx 19.7 开始,类似的功能即使在自托管时也是付费功能。使用 Turborepo 的远程缓存在自托管或使用 Vercel 远程缓存时是免费的。

迁移步骤

我们这次迁移的目标是尽快获得一个可工作的 Turborepo 任务,这样你就可以逐步采用 Turborepo 功能。我们将从使用 Nx 脚手架创建一个带有 Next.js 应用的仓库开始。

Terminal
npx create-nx-workspace --preset=next --ci=skip --e2eTestRunner=none --style=tailwind --nextAppDir=true --nextSrcDir=false --packageManager=pnpm --appName=starter

步骤 1:更新 .gitignore

Turborepo 使用 .turbo 目录来保存本地缓存和关于你的仓库的其他信息。因此,应该将其添加到你的 .gitignore

.gitignore
.turbo

步骤 2:添加工作空间定义

Turborepo 构建在包管理器工作空间之上,这是 JavaScript 生态系统标准。将包含包的目录路径添加到工作空间。

package.json
{
  "workspaces": ["apps/*"]
}

步骤 3:向应用程序添加 package.json

Turborepo 使用标准的 package.json 文件,而不是添加额外的配置文件,如 project.json

starter 应用程序中添加一个 package.json。在 ./apps/starter/package.json 创建一个包含 devbuild 脚本的 package.json

./apps/starter/package.json
{
  "name": "starter",
  "scripts": {
    "dev": "next dev",
    "build": "next build"
  }
}

步骤 4:移除 Nx 插件

从 ./apps/starter/next.config.js 中移除 Nx 插件。下面的示例文件没有配置,尽管你现有的 Next.js 应用可能需要一些配置。

./apps/starter/next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {};
 
module.exports = nextConfig;

步骤 5:添加 packageManager 字段

根 package.json 需要有 packageManager 字段。这确保仓库中的开发者使用正确的包管理器,并且 Turborepo 可以根据你的锁文件优化你的包图。

./package.json
{
  "packageManager": "npm@10.0.0"
}

步骤 6:运行包管理器的安装命令

通过运行安装命令更新你的锁文件。

Terminal
npm install

完成这个步骤后,你应该看到锁文件的差异,表明包已被添加到包管理器的工作空间。

步骤 7:安装 Turborepo

将 Turborepo 添加到工作空间的根 package.json

Terminal
npm install turbo --save-dev

你也可以选择全局安装 turbo 以便在使用 Turborepo 时更方便。

Terminal
npm install turbo --global

步骤 8:添加 turbo.json

在根目录创建一个 turbo.json 来注册你的任务并描述它们的任务依赖关系。

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

步骤 9:运行 turbo build

使用 Turborepo 构建应用程序。使用全局 turbo,这将是 turbo build。你也可以通过包管理器运行命令:

Terminal
npx turbo run build

步骤 10:启用远程缓存(可选)

默认情况下,当你运行以下命令时,Turborepo 将连接到免费使用的 Vercel 远程缓存:

Terminal
turbo login
turbo link

你也可以配置自托管的远程缓存,这不需要许可证或任何其他费用。

高级迁移注意事项

虽然上面的迁移指南是一个很好的起点,但 monorepos 的可能性和功能的广度意味着很难为所有情况创建通用的说明。以下是你可能正在考虑的一些常见后续步骤。

逐步迁移复杂的 monorepos

我们鼓励增量迁移,这意味着你的仓库中同时会有 Nx 和 Turborepo。确保花时间理解你的 Nx 任务图是如何构建的。拆分任务图可能包括以下策略:

  • 一次迁移一个任务:将 nx run lint 改为 turbo run lint
  • 一次迁移一个包/项目:将 nx run-many lint test --projects=web 改为 turbo run lint test --filter=web
  • 双重运行某些任务:为了确保稳定性,在你仍在适应并在迁移早期阶段建立确定性时,你可能选择同时运行 turbo run lint nx run lint

在使用依赖项的地方安装它们

Turborepo 建议在使用的地方安装包,以提高缓存命中率,帮助依赖项修剪能力,并为开发者明确哪些依赖项是用于哪些包的。这与 Nx 的策略不同,在 Nx 中,所有依赖项都安装在仓库的根目录,使所有依赖项对工作空间中的所有包都可用。

历史上,Nx 建议在仓库的根目录安装所有依赖项,使所有依赖项对工作空间中的所有包都可用。如果你遵循了这个指导,我们强烈建议你将依赖项移动到需要它们的包和应用程序的 package.json 中。访问我们关于管理依赖项的文档了解更多信息。

创建共享包

你将大致遵循与上面相同的步骤来将包添加到包管理器的工作空间。

  1. 确保包的目录包含在工作空间定义中(如 ./packages/*)。
  2. 在包中添加一个带有需要运行的脚本的 package.json
  3. 检查 turbo.json 中的任务依赖关系,确保你的依赖图满足你的要求。

多语言 monorepos

Turborepo 原生支持 JavaScript 和 TypeScript,并对你想要使用的任何其他语言提供次要支持。访问多语言支持文档了解更多信息。

配置等效项

nx.json 中的配置可以使用下面的表格映射到 turbo.json

Nx 和 Turborepo 之间捕获文件的大多数 glob 是相同的。有关详细信息和边缘情况,请参见 我们的文件 glob 规范

全局配置

NxTurborepo
sharedGlobalsglobalDependencies
sharedGlobals.envglobalEnv
sharedGlobals.namedInputglobalDependencies
cacheDirectorycacheDir

任务配置

NxTurborepo
inputs filestasks[task].inputs
inputs.envtasks[task].env
outputs filestasks[task].outputs
cachetasks[task].cache

CLI 等效项

NxTurborepo
nx generateturbo generate
nx runturbo run
nx run-manyturbo run
nx reset--force
--parallel--concurrency
--nxBail--continue
--projects--filter
--graph--graph
--output-style--log-order
--no-cloud--cache
--verbose--verbosity