使用 @nx/rollup 在 Nx 中构建与发布 JavaScript 库:执行器、推断插件与迁移实战
【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx
本篇技术指南围绕 Nx 仓库中的@nx/rollup插件包展开,介绍如何在 Nx 工作区中借助 Rollup 将库构建为 ESM / CommonJS 产物:从readme-template.md所定义的包定位出发,覆盖快速开始、@nx/rollup:rollup执行器的全部配置项、自定义rollup.config与withNx编程式 API、样式与依赖处理原理,以及从执行器迁移到@nx/rollup/plugin推断插件的完整路径。读完本文,你将掌握在 Nx 中为库项目配置 Rollup 构建、按需定制产物格式与外置依赖、并平滑迁移到新式推断目标的全套方案。
一、包定位:@nx/rollup是什么
在 packages/rollup/readme-template.md 中,这个包被一句话定义清楚:
This package is a Rollup plugin for Nx.
即@nx/rollup是 Nx 的 Rollup 插件包,使命是在 Nx 工作区中"Packages a library for different web usages (ESM, CommonJS)"——把一个库项目打包成面向不同 Web 使用场景的 ESM 与 CommonJS 产物。包内同时提供执行器(executor)与生成器(generator),以及新式的推断插件(inferred plugin),具体能力可以从包的清单文件确认:
- packages/rollup/package.json 中描述为 "The Nx Plugin for Rollup contains executors and generators that support building applications using Rollup.",其
peerDependencies声明支持rollup: "^3.0.0 || ^4.0.0"(且为 optional,rollup 由工作区自行安装); - packages/rollup/executors.json 注册了唯一执行器
@nx/rollup:rollup("Bundle a package using Rollup"); - packages/rollup/generators.json 注册了
init、configuration(别名rollup-project)与convert-to-inferred三个生成器; - 包还通过 packages/rollup/plugin.ts 暴露
createNodes/createNodesV2/RollupPluginOptions,通过 packages/rollup/with-nx.ts 暴露withNx编程式配置函数。
值得注意的是,readme-template.md本身是一个发布模板:其中{{links}}与{{content}}是占位符。scripts/copy-readme.js 会在打包发布时用 scripts/readme-fragments/links.md 与 scripts/readme-fragments/content.md 替换它们,最终生成dist/packages/rollup/README.md。这意味着模板中的"Getting Started"章节是所有 Nx 包通用的入门指引,而本文下面将结合仓库源码,把模板中一句话带过的"Rollup plugin"展开成可落地的完整方案。
二、快速开始:在 Nx 中启用 Rollup 构建
模板的 Getting Started 部分(即 scripts/readme-fragments/content.md)给出了两种进入路径,它们是使用@nx/rollup的前提:
1. 创建全新 Nx 工作区
# 方式一:npx npx create-nx-workspace # 方式二:npm init npm init nx-workspace # 方式三:yarn create yarn create nx-workspace2. 为已有仓库接入 Nx
npx nx@latest init进入工作区后,先安装插件包与 rollup:
npm install -D @nx/rollup rollup随后通过init生成器完成插件初始化(该生成器在 packages/rollup/src/generators/init/init.ts 中实现,支持skipFormat、skipPackageJson、keepExistingVersions、updatePackageScripts等选项),再为具体库项目生成构建配置:
nx g @nx/rollup:configuration my-libconfiguration生成器(别名rollup-project)的参数定义见 packages/rollup/src/generators/configuration/schema.json,常用参数包括:
| 参数 | 说明 | 默认值 |
|---|---|---|
project | 要配置的库项目名 | 必填 |
compiler | 编译源码使用的编译器 | babel(可选swc、tsc) |
main | 入口文件(相对工作区根) | <projectRoot>/src/index.ts |
tsConfig | 构建用的 tsconfig(相对工作区根) | <projectRoot>/tsconfig.lib.json |
format | 输出模块格式 | ["esm"](可选cjs) |
external | 不打进产物、保持外置的模块列表 | [] |
rollupConfig | 自定义 rollup 配置文件路径(相对工作区根) | 无 |
buildTarget | 生成的构建目标名 | build |
importPath | 库的导入名,如@myorg/my-lib | 无 |
生成后,project.json中会得到一个使用@nx/rollup:rollup执行器的build目标,随后即可运行:
nx build my-lib三、@nx/rollup:rollup执行器全参数详解
执行器的完整 schema 定义在 packages/rollup/src/executors/rollup/schema.json,实现位于 packages/rollup/src/executors/rollup/rollup.impl.ts。核心参数整理如下(带默认值):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
main | string | 必填 | 入口文件路径(相对项目),别名entryFile |
outputPath | string | 必填 | 产物输出目录 |
outputFileName | string | 与main同名 | 主输出文件名 |
tsConfig | string | 必填 | tsconfig 路径 |
deleteOutputPath | boolean | true | 构建前清空输出目录 |
format | ("esm"\|"cjs")[] | 与 tsconfig 匹配 | 输出模块格式列表,别名f |
external | string[]|"all"|"none" | [] | 外置模块列表;all表示全部外置、none表示全部打进产物 |
watch | boolean | false | 文件变更时增量重建 |
rollupConfig | string | string[] | 无 | 一个或多个接收 rollup config 并返回新 config 的模块路径 |
extractCss | boolean | string | true | 提取 CSS 到输出目录,也可传自定义文件名(如styles.css) |
assets | object[] | string[] | [] | 静态资源列表(glob+input+output) |
compiler | "babel" \| "swc" \| "tsc" | "babel" | 使用的编译器 |
babelUpwardRootMode | boolean | false | BabelrootMode: "upward",用于 monorepo 中逐包应用.babelrc |
javascriptEnabled | boolean | false | 为 less loader 开启javascriptEnabled |
generateExportsField | boolean | false | 在输出package.json中生成exports字段,别名exports |
additionalEntryPoints | string[] | [] | 追加到exports字段的额外入口 |
buildLibsFromSource | boolean | true | 直接以源码方式读取可构建库,而非预先单独构建它们 |
skipTypeCheck | boolean | false | 跳过 TypeScript 类型检查 |
skipTypeField | boolean | false | 不在输出package.json写入type字段 |
sourceMap | boolean | 无 | 输出 sourcemap |
project | string | 无 | package.json文件路径(已废弃,自动探测项目根package.json) |
一个典型的project.json配置示例:
{ "my-lib": { "targets": { "build": { "executor": "@nx/rollup:rollup", "outputs": ["{workspaceRoot}/dist/my-lib"], "options": { "main": "packages/my-lib/src/index.ts", "outputPath": "dist/my-lib", "tsConfig": "packages/my-lib/tsconfig.lib.json", "compiler": "swc", "format": ["esm", "cjs"], "external": ["react", "react-dom"], "assets": [{ "glob": "*.md", "input": ".", "output": "." }], "generateExportsField": true } } } } }3.1 底层执行流程
从 rollup.impl.ts 可以看清执行器的工作方式:
- 先执行
warnRollupExecutorDeprecation()(见 packages/rollup/src/utils/deprecation.ts),提示该执行器已废弃、将在 Nx v24 移除; - 通过
require('rollup')懒加载 rollup(因为 rollup 是 optional peer dependency,图构建阶段可能尚未安装); - 默认把
NODE_ENV置为production; - 非
watch模式下:rollup.rollup(opts)创建 bundle,再对每个 output 执行bundle.write(o),计时并输出⚡ Done in ${duration};watch模式下则切换到rollup.watch,监听START/END/ERROR事件,并在SIGTERM/SIGINT/SIGQUIT时关闭 watcher; - 支持同时产出 ESM 与 CJS:当
format包含cjs时,resolveOutfile会把 CJS 主文件解析为<outputPath>/<name>.cjs.js。
3.2 用户自定义 rollupConfig 的合并规则
createRollupOptions(rollup.impl.ts)展示了自定义配置的两类合并语义:
- 导出为函数:
finalConfig = config(finalConfig, options),把默认配置与标准化后的 options 交给你做任意改写; - 导出为对象:做浅合并,且
plugins采用"默认插件 + 用户插件"拼接的方式追加,而不是覆盖。
无论哪种方式,generatePackageJson插件都会被确保保留在最终插件列表中,以维持输出package.json的生成能力。
四、用withNx编写自定义 rollup.config
除了在project.json中声明式配置,@nx/rollup还提供了编程式配置入口withNx(导出自 packages/rollup/with-nx.ts,实现位于 packages/rollup/src/plugins/with-nx/with-nx.ts)。它的调用形态为withNx(options, overrideConfig, dependencies):第一参传入与执行器一致的标准化选项,第二参传入需要覆盖/追加的 rollup 配置,第三参为可构建依赖节点列表(执行器内部调用时即为withNx(options, {}, dependencies))。
典型用法(新建rollup.config.ts并把rollupConfig指向它):
import { withNx } from '@nx/rollup/with-nx'; export default withNx( { main: './src/index.ts', outputPath: './dist', tsConfig: './tsconfig.lib.json', compiler: 'swc', format: ['esm', 'cjs'], external: ['react', 'react-dom'], generateExportsField: true, }, { // 此处可叠加任意原生 rollup 配置或自定义插件 plugins: [myCustomPlugin()], } );可用的RollupWithNxPluginOptions完整字段定义见 packages/rollup/src/plugins/with-nx/with-nx-options.ts,与执行器选项一一对应,并额外支持:
generatePackageJson?: boolean:是否在输出目录生成package.json(TypeScript Project References + 包管理器 Workspaces 场景下不支持,其余场景默认true)。
选项在 packages/rollup/src/plugins/with-nx/normalize-options.ts 中被归一化:字符串形式的assets必须位于项目 source root 内,目录会展开为**/*的 glob;对象形式的 asset 输出路径不允许以..开头(不能写到输出目录之外);format会去重并保持esm/cjs顺序。
4.1 内置插件管线
从with-nx.ts的导入(packages/rollup/src/plugins/with-nx/with-nx.ts#L20-L42)可以看到默认装配的完整工具链:
@rollup/plugin-babel、@rollup/plugin-commonjs、@rollup/plugin-node-resolve、@rollup/plugin-image、@rollup/plugin-json、@rollup/plugin-typescript;- 内联的 postcss 插件(不依赖外部
rollup-plugin-postcss),实现在 packages/rollup/src/plugins/postcss/postcss-plugin.ts,并附带 sass/less/stylus 三套 loader(packages/rollup/src/plugins/postcss/loaders),配合autoprefixer处理前缀; nxCopyAssetsPlugin(packages/rollup/src/plugins/nx-copy-assets.plugin.ts)负责把assets拷贝到输出目录;generatePackageJson(packages/rollup/src/plugins/package-json/generate-package-json.ts)负责生成输出package.json;swc(packages/rollup/src/plugins/swc.ts)在compiler: "swc"时替代 babel 编译。
五、依赖包含与babelUpwardRootMode实战细节
packages/rollup/docs/rollup-examples.md 是该执行器 schema 的examplesFile(在 schema.json 中被引用),包含两个高频实战要点:
5.1 把依赖写进输出 package.json
要让某个依赖出现在输出产物的package.json的dependencies中,它必须安装在仓库根package.json的dependencies区(而不是devDependencies):
{ "dependencies": { "some-dependency": "^1.0.0" } }这是generatePackageJson插件生成输出package.json时的依据:只有根dependencies中的包才会被视为运行时依赖写入产物清单。
5.2babelUpwardRootMode的正确打开方式
babelUpwardRootMode: true会把 Babel 的rootMode设为upward,令 Babel 从工作目录向上查找babel.config.json并将其位置作为 "root"。这在 monorepo 中适用于"每个项目必须应用各自.babelrc"的场景。配置示例:
{ "my-app": { "targets": { "build": { "executor": "@nx/rollup:rollup", "options": { "babelUpwardRootMode": true } } } } }开启后,工作区根需要一份包含所有包范围的babel.config.json:
{ "babelrcRoots": ["*"] }每个包再提供自己的.babelrc,例如:
{ "presets": ["@babel/preset-env", "@babel/preset-typescript"] }目录形态如下:
├── packages │ ├── a │ │ └── .babelrc │ └── b │ └── .babelrc └── babel.config.json注意其语义细节:若a导入了b,则b会应用packages/b/.babelrc,而不会应用a自己的配置;babel.config.json中的内容对所有包生效。由于各包需各自维护正确的 presets/plugins,这种模式容易造成包间构建差异,官方文档明确建议默认不要设置babelUpwardRootMode(保持默认false),仅在确实需要逐包.babelrc时才启用。
六、迁移到推断插件@nx/rollup/plugin
@nx/rollup:rollup执行器已在 schema 中标记废弃,packages/rollup/src/utils/deprecation.ts 明确说明:
The
@nx/rollup:rollupexecutor is deprecated and will be removed in Nx v24.
Nx v24 中执行器将被移除,而推断插件(@nx/rollup/plugin)与convert-to-inferred生成器会继续得到支持。因此"executor → plugin"的迁移是当前仓库指向的标准演进路径。
6.1 一条命令完成迁移
# 迁移所有使用 @nx/rollup:rollup 的项目 nx g @nx/rollup:convert-to-inferred # 只迁移指定项目 nx g @nx/rollup:convert-to-inferred --project=my-lib生成器参数见 packages/rollup/src/generators/convert-to-inferred/schema.json,实现见 packages/rollup/src/generators/convert-to-inferred/convert-to-inferred.ts。其工作步骤包括:
assertSupportedRollupVersion(tree)校验工作区的 rollup 版本;forEachExecutorOptions遍历所有使用@nx/rollup:rollup的目标(--project指定时只处理该项目),跳过命名 configuration;- 把
nx.json中targetDefaults里针对@nx/rollup:rollup的默认选项拷贝到目标上,弥补移除 executor 后 defaults 不再生效的问题; - 通过 extract-rollup-config-from-executor-options.ts 把 executor 选项转写为
rollup.config.ts(内部走withNx形态),并删除project.json中的旧 target; - 通过 add-plugin-registrations.ts 在
nx.json的plugins中注册@nx/rollup/plugin。
6.2 推断插件的工作机制
推断插件的实现位于 packages/rollup/src/plugins/plugin.ts:
- 以 glob
**/rollup.config.{js,cjs,mjs,ts,cts,mts}扫描工作区(plugin.ts#L44),只要项目根(含package.json或project.json)存在 rollup 配置文件,就自动为其生成build目标,无需在project.json手工声明; - 通过
calculateHashesForCreateNodes对项目根与选项做哈希,并把生成结果缓存到 Nx 的workspace-data目录(rollup-<optionsHash>.hash),未变更时直接复用缓存中的目标配置; - 加载配置时优先解析工作区自身安装的 rollup的
loadConfigFile,以保证与 rollup 大版本兼容(例如 rollup@2 允许 config 中使用require,rollup@4 则不行);TypeScript 写的 config 会附加--configPlugin typescript={tsconfig:'tsconfig.lib.json'},并以 watch 模式加载配置以规避缓存; - 生成的
build目标为command: "rollup -c <config>",cwd指向项目根,cache: true,dependsOn: ["^build"](先构建依赖库),inputs使用production/default命名输入并声明对rollup的外部依赖,outputs从 config 的output.dir/output.file推导(缺失时默认dist); - 插件选项通过
nx.json中插件配置传入:buildTargetName(默认build)、buildDepsTargetName、watchDepsTargetName。
插件还通过addBuildAndWatchDepsTargets自动补充构建/监听依赖库的目标;在 TypeScript Project References 场景(isUsingTsSolutionSetup())下,会额外挂上@nx/js:typescript-sync同步生成器。
6.3 迁移后的形态与配套迁移
迁移完成后,项目不再依赖 executor,project.json中的build目标消失,构建行为完全由rollup.config.ts驱动,nx build my-lib依然可用,同时nx graph中会展示基于 Rollup 的目标关系。此外,仓库还在 packages/rollup/src/migrations/update-23-0-0 提供了配套升级迁移:createNodesV2迁移、移除已废弃的useLegacyTypescriptPlugin选项、内部子路径导入重写,确保旧配置在升级后平滑衔接新式插件体系。
七、总结
@nx/rollup是 Nx 生态中专用于 Rollup 构建的插件包,其能力图谱如下:
- 声明式配置:
@nx/rollup:rollup执行器(schema.json)覆盖入口、输出、格式、外置依赖、资源、样式提取、编译器选择等 20 余项参数; - 编程式配置:
withNx(packages/rollup/with-nx.ts)在原生rollup.config中复用 Nx 的库构建管线; - 自包含工具链:内联 postcss(sass/less/stylus)、assets 拷贝、输出
package.json生成、exports字段与额外入口点支持; - 面向未来:执行器已废弃(Nx v24 移除),推荐通过
nx g @nx/rollup:convert-to-inferred迁移到@nx/rollup/plugin推断目标,实现配置即代码、缓存即收益的现代构建方式。
无论你是要快速为现有库添加构建目标,还是希望把 Rollup 构建完全收敛到配置文件、享受 Nx 的缓存与依赖图编排,@nx/rollup都提供了对应层级的接入方式。相关源码与示例可继续在仓库中查阅:packages/rollup/docs/rollup-examples.md、packages/rollup/src/plugins/plugin.ts、packages/rollup/src/plugins/with-nx/with-nx.ts。
【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考