使用 Nx 构建 Bitwarden Monorepo:命令速查、项目配置与缓存机制实战指南
【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clients
本指南以 Bitwarden 客户端仓库中的 using-nx-to-build-projects.md 为骨架,系统讲解如何借助 Nx 在包含 web、浏览器扩展、桌面端与 CLI 的巨型 monorepo 中高效完成构建、测试、lint 与增量构建。读完本文,你将掌握 Nx 命令的完整用法、project.json中两类库的集成模式(Legacy Facade 与现代原生 Executor)、构建配置(Configuration)的选择逻辑,以及 Nx 缓存与依赖图的底层工作方式,能够独立在本地与 CI 中正确驱动 Bitwarden 全量构建。
认识 Nx 在 Bitwarden 仓库中的角色
Bitwarden 客户端代码库(README.md 中定义为 web、browser extension、desktop、cli 四大客户端应用)是一个庞大的 monorepo,包含apps/下的多个应用、libs/下的数十个共享库,以及bitwarden_license/下的商业授权代码。仓库引入 Nx 的核心目的,是让从 monorepo 中构建单个项目变得更加容易:统一命令入口、按依赖图精准调度、并通过缓存跳过未变更项目的重复构建。
使用 Nx 的基本模式是:先查阅项目目录下的project.json文件,了解该项目可用的命令(target)及其名称,再以npx nx [your_command] [your_project] [your_options]的形式执行。运行npx nx --help可查看大量可用选项。
需要特别注意的是,当前仓库的 Nx 实现仍在演进中(work in progress):CI 仍使用旧的 npm 构建流程,且存在许多通过兼容技巧接入 Nx 项目图的"legacy"库。这一点在阅读下文两类库的差异时会反复体现。
快速上手:常用命令速查
基本命令
以下命令完整覆盖了日常构建、测试、lint、serve 与批量操作:
# 构建一个项目 npx nx build cli npx nx build-native desktop # 部分应用有特殊的构建命令(如桌面端的原生模块) npx nx build state # 现代库与应用使用简单的小写 target 名称 npx nx build @bitwarden/common # 旧版库采用特殊命名约定,需携带 @bitwarden 前缀 # 测试一个项目 npx nx test cli # Lint 一个项目 npx nx lint cli # 监听模式运行/开发一个项目(仅对配置了 serve target 的项目生效) npx nx serve cli # 只构建所有相对 origin/main 有变更的项目(affected) nx affected --target=build --base=origin/main # 一次性对所有项目执行 build、test、lint npx nx run-many --target=build,test,lint --all # 大多数项目默认使用 "oss-dev" 配置,如需商业授权构建请追加 --configuration npx nx build cli --configuration=commercial-dev # 需要生产构建时,去掉 "dev" 后缀 npx nx build cli --configuration=oss # 或 "commercial" # 配置同样可以传递给 run-many # 例如:运行所有 Bitwarden 商业授权构建 npx nx run-many --target=build,test,lint --all --configuration=commercial # 产物统一输出到根级 /dist/ 目录 # 运行本地构建出的 CLI node dist/apps/cli/oss-dev/bw.js结合仓库源码,可以对上述命令做如下深化理解:
npx nx build cli:apps/cli/project.json中buildtarget 使用@nx/webpack:webpackexecutor,并通过defaultConfiguration: "oss-dev"(apps/cli/project.json)声明默认配置,因此不带--configuration时默认走 oss-dev 开发构建。npx nx build-native desktop:桌面端应用在 apps/desktop/project.json 中定义了build-nativetarget,通过nx:run-commands在apps/desktop/desktop_native目录执行node build.js,用于编译 Rust 编写的原生模块,然后再由buildtarget 通过dependsOn: ["build-native"]并行编排build-main、build-preload、build-renderer三个子构建(apps/desktop/project.json)。--configuration=commercial-dev:以 CLI 为例,commercial系列配置会把webpackConfig、main、tsConfig整体切换到商业授权代码库 bitwarden_license/bit-cli/webpack.config.js 对应的入口(apps/cli/project.json)。
全局命令
# 查看所有项目 npx nx show projects # 仅运行受影响的项目(非常适合本地开发与 CI) npx nx affected:build npx nx affected:test npx nx affected:lint # 展示依赖图 npx nx dep-graphaffected系列命令是 Nx 增量能力的核心体现:它会基于 git 历史(默认基线main,见 nx.json)计算自基线以来变更的项目集合,只对受影响的子集执行对应 target,从而显著缩短本地与 CI 的构建时间。
项目配置入口:project.json 与两类库集成模式
仓库中的库(library)依据 Nx 迁移进度分为两种集成模式,理解二者的差异是正确构建的前提。
Legacy Libraries(旧版库,Facade 门面模式)
绝大多数现有库仍采用门面(facade)模式:其project.json将 target 委托给既有的 npm scripts,从而保持引入 Nx 之前构建方式的向后兼容。这些库被视为技术债务(tech debt),Platform 团队正着力于将其升级为现代模式。典型示例见 libs/common/project.json。
这类库使用nx:run-scriptexecutor 调用既有的 npm scripts:
{ "targets": { "build": { "executor": "nx:run-script", "options": { "script": "build" } } } }例如 libs/common/package.json 中定义的真实脚本为:clean(rimraf dist)、build(npm run clean && tsc)、build:watch(npm run clean && tsc -watch)、test(jest)。也就是说,npx nx build @bitwarden/common最终等价于在libs/common下执行npm run build,其产物默认输出到libs/common/dist/。
旧版库的标准命令集合:
nx build <library>—— 构建库nx build:watch <library>—— 构建并监听文件变更nx clean <library>—— 清理构建产物nx test <library>—— 运行测试nx lint <library>—— 运行 lint
注意旧版库的命名约定:项目名携带@bitwarden前缀(如@bitwarden/common),与tsconfig.base.json中路径映射(如"@bitwarden/state": ["./libs/state/src/index.ts"],见 tsconfig.base.json)保持一致。
Modern Libraries(现代库,原生 Nx Executor)
较新的库(如libs/state)直接使用 Nx 原生 executor,以获得更好的性能与缓存能力:
{ "targets": { "build": { "executor": "@nx/js:tsc", "outputs": ["{options.outputPath}"], "options": { "outputPath": "dist/libs/state" } } } }以 libs/state/project.json 为例,其buildtarget 使用@nx/js:tsc,通过tsConfig: "libs/state/tsconfig.lib.json"指定编译选项,outputs声明产物路径dist/libs/state,从而使 Nx 能够将该输出纳入缓存管理;test与lint则分别使用@nx/jest:jest与@nx/eslint:lint原生 executor。现代库使用简单的小写 target 名(如build、test、lint),且项目名不带@bitwarden前缀。
应用级构建配置:Configuration 与特殊 Target
除了库之外,应用(application)的project.json往往更复杂,本节以三个典型应用说明。
CLI:webpack + 四种配置
apps/cli/project.json 的build使用@nx/webpack:webpack,定义了四种 configuration:
| 配置 | mode | 输出路径 | 入口与配置来源 |
|---|---|---|---|
oss-dev(默认) | development | dist/apps/cli/oss-dev | apps/cli/src/bw.ts |
oss | production | dist/apps/cli/oss | 同上 |
commercial-dev | development | dist/apps/cli/commercial-dev | bitwarden_license/bit-cli/src/bw.ts |
commercial | production | dist/apps/cli/commercial | 同上 |
由此可印证原文档的规则:去掉 "dev" 后缀即得到生产构建;而商业授权构建需要额外--configuration=commercial[-dev]。
Browser 扩展:多浏览器 × 多 Manifest 版本
apps/browser/project.json 是配置最丰富的应用,其build通过env环境变量(BROWSER、MANIFEST_VERSION、NODE_ENV)区分 chrome、edge、firefox(含 MV2/MV3)、opera、safari(含 MV2/MV3)等 12 个开源配置,外加commercial-*系列商业授权变体;servetarget 则通过nx:run-commands直接调用webpack --watch(apps/browser/project.json),并设置NODE_OPTIONS="--max-old-space-size=8192"以支撑大体积打包。
Desktop:特殊 Target 编排
apps/desktop/project.json 展示了"部分应用有特殊构建命令"的实例:除标准build外,还定义了build-native(编译 Rust 原生模块)、build-main、build-preload、build-renderer等独立 target,build通过dependsOn与并行commands数组统一编排它们(apps/desktop/project.json)。这类应用不能简单地用npx nx build desktop理解全部流程,需要先查看project.json确认命令名称。
当你运行一条 Nx 命令时发生了什么
原文档用一张 Mermaid 流程图完整刻画了命令执行链路,本文完整保留并逐段解读:
从仓库源码可以进一步印证图中的"读取 workspace 配置"环节:
- nx.json 声明了缓存目录
cacheDirectory: ".nx/cache"、默认基线defaultBase: "main"、namedInputs(区分default、production、sharedGlobals三组输入集合)、最大并行度parallel: 4,以及四条插件配置:@nx/js(@nx/js:tsc,configName: tsconfig.lib.json)、@nx/jest/plugin、@nx/eslint/plugin,以及 Bitwarden 自研的@bitwarden/nx-plugin(用于提供自定义生成器与 executor,见 libs/nx-plugin/package.json)。 - 图中提到 ESLint 读取
.eslintrc.json,但仓库根级实际采用扁平化配置 eslint.config.mjs(现代库如libs/state的lintFilePatterns同样由@nx/eslint:lint驱动),具体以仓库当前版本为准。 - 图中 Legacy 路径输出到
libs/LIB/dist/、现代库输出到dist/libs/LIB/、webpack 应用输出到dist/apps/<app>/,这与前文libs/common/package.json与libs/state/project.json的实际输出路径完全一致。
缓存与性能
Nx 自动缓存
Nx 会自动缓存构建输出,并且只重建真正发生变更的部分:
# 首次运行:构建所有内容 npx nx build cli # 第二次运行:命中缓存(明显更快) npx nx build cli缓存机制的实现细节体现在 nx.json 的targetDefaults.build中:inputs: ["production", "^production"]定义了构建的输入集合(production输入会排除*.spec.ts与tsconfig.spec.json,见 nx.json),outputs: ["{options.outputPath}"]让 Nx 明确知道产物位置,cache: true开启缓存。只有当输入哈希一致时才能命中缓存并跳过执行;任何输入变更都会导致缓存失效并重新构建。
清空缓存
# 清空全部缓存 npx nx reset当需要验证干净构建、或缓存出现异常时使用npx nx reset,它等价于清理.nx/cache缓存目录并重置 Nx 状态。
深入阅读指引
- Nx 官方入门文档与命令参考(
npx nx --help可查看本机安装版本的全部选项); - 仓库级构建配置:nx.json;
- 应用级配置示例:apps/cli/project.json、apps/browser/project.json、apps/desktop/project.json;
- 两类库配置对比:libs/common/project.json(Legacy 门面模式)与 libs/state/project.json(现代原生 executor);
- 旧版库实际 npm 脚本:libs/common/package.json;
- 路径映射与依赖解析:tsconfig.base.json;
- 自研 Nx 插件:libs/nx-plugin/package.json;
- 依赖图可视化:
npx nx dep-graph。
【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clients
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考