Turborepo logo

从 Nx 迁移

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

为什么要切换?

你可能有许多理由选择从 Nx 迁移到 Turborepo。下面,我们列出了开发者在迁移时最常提及的动机。

使用生态系统标准

Turborepo 的目标是轻量级,依赖于你的仓库作为真理的来源。Turborepo 构建于 JavaScript 包管理器工作区之上,以支持 JavaScript/TypeScript,就是一个例子。

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

更好地控制源代码

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

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

更少的仓库管理器配置

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

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 以来,即使是自托管,类似的功能也是付费功能。当自托管或使用 Vercel 远程缓存时,Turborepo 的远程缓存是免费的。

迁移步骤

我们这次迁移的目标是尽可能快地获得可用的 Turborepo 任务,以便你可以逐步采用 Turborepo 功能。我们将首先使用 Nx scaffolder 创建一个带有 Next.js 应用程序的仓库。

终端
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 创建一个 package.json,其中包含 devbuild 脚本。

./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 可以根据你的 lockfile 优化你的包图。

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

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

通过运行你的安装命令来更新你的 lockfile。

终端
npm install

完成此操作后,你应该会看到 lockfile diff,表明该包已添加到包管理器的工作区。

步骤 7:安装 Turborepo

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

终端
npm install turbo --save-dev

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

终端
npm install turbo --global

步骤 8:添加 turbo.json

在根目录创建 turbo.json 以注册你的任务并描述其任务依赖项。

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

步骤 9:运行 turbo build

使用 Turborepo 构建应用程序。如果使用全局 turbo,则命令为 turbo build。你也可以通过你的包管理器运行该命令

终端
npx turbo run build

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

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

终端
turbo login
turbo link

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

高级迁移注意事项

虽然上面的迁移指南是一个很好的起点,但 monorepo 的可能性和功能范围意味着很难为所有情况创建通用的说明。下面,我们列出了一些你可能会考虑的常见后续步骤。

逐步迁移复杂的 monorepo

我们鼓励增量迁移,这意味着你的仓库中将同时存在 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 中的任务依赖项,以确保你的依赖项图满足你的要求。

多语言 monorepo

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

配置等效项

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

用于捕获文件的大部分 glob 在 Nx 和 Turborepo 之间是相同的。有关详细信息和边缘情况,请参阅我们的文件 glob 规范

全局配置

NxTurborepo
sharedGlobalsglobalDependencies
sharedGlobals.envglobalEnv
sharedGlobals.namedInputglobalDependencies
cacheDirectorycacheDir

任务配置

NxTurborepo
inputs 文件tasks[task].inputs
inputs.envtasks[task].env
outputs 文件tasks[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