发布库

使用合适的工具,从 monorepo 将包发布到 npm 仓库可以非常流畅。

¥Publishing a package to the npm registry from a monorepo can be a smooth experience, with the right tools.

虽然本指南无法解决构建健壮软件包所需的所有编译、打包和发布配置问题,但它将解释一些基础知识。

¥While this guide cannot solve for every possible compiling, bundling, and publishing configuration needed for robust packages, it will explain some of the basics.

如果你想将部分 monorepo 软件包发布到 npm,则应遵循此设置。如果你不需要发布到 npm,则应该使用 内部包。它们的设置和使用更加简单。

¥You should follow this setup if you want to publish some of your monorepo's packages to npm. If you don't need to publish to npm, you should use an Internal Package instead. They're much easier to set up and use.

打包

¥Bundling

内部软件包 不同,外部包可以部署到 npm 并在本地使用。在本指南中,我们将把一个包打包到 ECMAScript 模块 (esm) 和 CommonJS 模块 (cjs),这是 npm 上最常用的格式。

¥Unlike Internal Packages, external packages can be deployed to npm and used locally. In this guide, we'll bundle a package to both ECMAScript modules (esm) and CommonJS modules (cjs), the most commonly used formats on npm.

设置构建脚本

¥Setting up a build script

让我们从使用 内部软件包 教程创建的包开始。

¥Let's start with a package created using the Internal Packages tutorial.

在那里,我们创建了一个 @repo/math 包,其中包含一些用于加减数字的辅助函数。我们认为这个包对于 npm 来说已经足够好了,所以我们要把它打包起来。

¥There, we created a @repo/math package which contained a few helper functions for adding and subtracting numbers. We've decided that this package is good enough for npm, so we're going to bundle it.

我们将使用打包器将 build 脚本添加到 @repo/math。如果你不确定选择哪一个,我们推荐 tsup

¥We're going to add a build script to @repo/math, using a bundler. If you're unsure which one to choose, we recommend tsup.

使用包管理器将 tsup 安装到 ./packages/math 包中,然后为其创建构建脚本:

¥Install tsup inside the ./packages/math package using your package manager and then create a build script for it:

./packages/math/package.json
{
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts"
  }
}

tsup 默认将文件输出到 dist 目录,因此你应该:

¥tsup outputs files to the dist directory by default, so you should:

  1. dist 添加到你的 .gitignore 文件中,以确保它们未提交到源代码管理中。

    ¥Add dist to your .gitignore files to make sure they aren't committed to source control.

  2. dist 添加到 turbo.jsonbuild 的输出部分。

    ¥Add dist to the outputs of build in your turbo.json.

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "outputs": ["dist/**"]
    }
  }
}

这样,当 tsup 运行时,Turborepo 的输出就可以是 cached

¥That way, when tsup is run the outputs can be cached by Turborepo.

最后,我们应该更新包的入口点。在 package.json 文件中,将 main 更改为指向使用 CommonJS 模块的客户端的 ./dist/index.jscjs),将 module 更改为指向使用 ECMAScript 模块的客户端的 ./dist/index.mjsesm),并将 types 更改为指向类型定义文件。 - ./dist/index.d.ts

¥Finally, we should update our package entrypoints. Inside package.json, change main to point at ./dist/index.js for clients using CommonJS modules (cjs), module to point at ./dist/index.mjs for clients using ECMAScript modules (esm), and types to the type definition file - ./dist/index.d.ts:

./packages/math/package.json
{
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts"
}

无需同时打包到 cjsesm。但是,我们建议这样做,因为它可以让你的包在更广泛的环境中使用。

¥It is not required to bundle to both cjs and esm. However, it is recommended, as it allows your package to be used in a wider variety of environments.

如果你在使用 mainmoduletypes 时遇到错误,请查看 tsup 文档

¥If you run into errors by using main, module and types, take a look at the tsup docs.

打包是一个复杂的话题,我们这里篇幅有限,无法一一详述!

¥Bundling is a complicated topic, and we don't have space here to cover everything!

在构建之前构建软件包应用

¥Building our package before our app

在运行 turbo run build 之前,我们需要考虑一件事。我们刚刚在 monorepo 中添加了一个 任务依赖 任务。packages/mathbuild 需要在 apps/webbuild 之前运行。

¥Before we can run turbo run build, there's one thing we need to consider. We've just added a task dependency into our monorepo. The build of packages/math needs to run before the build of apps/web.

幸运的是,我们可以使用 dependsOn 轻松配置这一点。

¥Fortunately, we can use dependsOn to easily configure this.

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"]
    }
  }
}

现在,我们可以运行 turbo run build,它会在构建我们的应用之前自动构建我们的包。

¥Now, we can run turbo run build, and it'll automatically build our packages before it builds our app.

设置开发脚本

¥Setting up a dev script

我们的设置存在一个小问题。我们的软件包构建得很好,但在开发环境中运行不佳。我们对 @repo/math 包所做的更改未反映在我们的应用中。

¥There's a small issue with our setup. We are building our package just fine, but it's not working great in dev. Changes that we make to our @repo/math package aren't being reflected in our app.

这是因为我们没有 dev 脚本来在工作时重建包。我们可以轻松添加一个:

¥That's because we don't have a dev script to rebuild our packages while we're working. We can add one easily:

./packages/math/package.json
{
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
  }
}

这会将 --watch 标志传递给 tsup,这意味着它将监视文件更改。

¥This passes the --watch flag to tsup, meaning it will watch for file changes.

如果我们已经在 turbo.json 中设置了 开发脚本,则运行 turbo run dev 将同时运行 packages/math 开发任务和 apps/web 开发任务。

¥If we've already set up dev scripts in our turbo.json, running turbo run dev will run our packages/math dev task in parallel with our apps/web dev task.

我们的包现在可以考虑部署到 npm 了。在我们的 版本控制和发布 部分,我们将执行此操作。

¥Our package is now in a spot where we can consider deploying to npm. In our versioning and publishing section, we'll do just that.

版本控制和发布

¥Versioning and publishing

在 monorepo 中手动版本控制和发布包可能很繁琐。幸运的是,有一个工具可以让事情变得简单。 - 变更集 CLI。

¥Manually versioning and publishing packages in a monorepo can be tiresome. Luckily, there's a tool that makes things easy - the Changesets CLI.

我们推荐使用变更集,因为它使用起来直观易用,并且 - 就像 Turborepo 一样 - 适用于你已习惯的 monorepo 工具。

¥We recommend Changesets because it's intuitive to use, and - just like Turborepo - fits with the monorepo tools you're already used to.

一些替代方案如下:

¥Some alternatives are:

发布

¥Publishing

软件包打包后,你可以将其发布到 npm 仓库。

¥Once your package has been bundled, you can then publish it to the npm registry.

我们建议你查看变更集文档。以下是我们推荐的阅读顺序:

¥We recommend taking a look at the Changesets docs. Here's our recommended reading order:

  1. 为什么使用变更集? - 一个介绍基础知识的简介。

    ¥Why use changesets? - an intro that takes you through the fundamentals.

  2. 安装说明

    ¥Installation instructions

  3. 如果你使用的是 GitHub,请考虑使用 变更集 GitHub 机器人 - 一个机器人,它会提醒你将变更集添加到 PR。

    ¥If you're using GitHub, consider using the Changeset GitHub bot - a bot to nudge you to add changesets to PR's.

  4. 你还应该考虑添加 变更集 GitHub 操作。 - 一个使发布变得极其简单的工具。

    ¥You should also consider adding the Changesets GitHub action - a tool which makes publishing extremely easy.

将变更集与 Turborepo 结合使用

¥Using Changesets with Turborepo

开始使用变更集后,你将可以使用三个有用的命令:

¥Once you've started using Changesets, you'll gain access to three useful commands:

Terminal
# Add a new changeset
changeset
 
# Create new versions of packages
changeset version
 
# Publish all changed packages to npm
changeset publish

将你的发布流程链接到 Turborepo 可以使你的部署组织更加简单快捷。

¥Linking your publishing flow into Turborepo can make organizing your deploy a lot simpler and faster.

我们建议将变更集配置为自动提交 changeset version 的变更。

¥Our recommendation is to configure Changesets to automatically commit changeset version's changes

./.changeset/config.json
{
  // …
  "commit": true
  // …
}

并将 publish-packages 脚本添加到你的根 package.json 中:

¥and add a publish-packages script into your root package.json:

./package.json
{
  "scripts": {
    // Include build, lint, test - all the things you need to run
    // before publishing
    "publish-packages": "turbo run build lint test && changeset version && changeset publish"
  }
}

如果你的包是公共的,请将变更集的 access 设置为 public

¥If your packages are public, set Changeset's access to public:

./.changeset/config.json
{
  // …
  "access": "public"
  // …
}

我们推荐使用 publish-packages,这样它就不会与 npm 内置的 publish 脚本冲突。

¥We recommend publish-packages so that it doesn't conflict with npm's built-in publish script.

这意味着当你运行 publish-packages 时,你的 monorepo 会被构建、linted、测试和发布。 - 你将受益于 Turborepo 的所有加速功能。

¥This means that when you run publish-packages, your monorepo gets built, linted, tested and published - and you benefit from all of Turborepo's speedups.