十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Bitwarden 客户端项目中的 Nx 自定义插件:`@bitwarden/nx-plugin` 生成器实战指南

Bitwarden 客户端项目中的 Nx 自定义插件:`@bitwarden/nx-plugin` 生成器实战指南 Bitwarden 客户端项目中的 Nx 自定义插件bitwarden/nx-plugin生成器实战指南【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clientsbitwarden/nx-plugin是 Bitwarden clients 仓库涵盖 web、浏览器扩展、桌面端与 CLI 四类客户端中内置的自定义 Nx 插件它为项目提供了一组符合 Bitwarden 架构与编码规范的Nx generators生成器用于在团队内统一新库、新组件的创建流程。本篇指南以插件官方文档libs/nx-plugin/README.md与basic-lib生成器使用说明libs/nx-plugin/docs/using-the-basic-lib-generator.md为骨架结合仓库内生成器源码与测试用例系统讲解 Nx 生成器的工作原理、basic-lib的完整参数体系、生成产物、库设计取舍以及自定义生成器的开发入口。读完本文你将能够在 Bitwarden 客户端仓库中一键创建符合项目标准的新库并理解其底层实现机制。插件概览为什么 Bitwarden 需要一个专属 Nx 插件Bitwarden clients 是一个以 Nx 管理的大型 monorepolibs/下按功能拆分了几十个库同时存在 web、浏览器扩展、桌面端、CLI 等可分发应用。要让几十个团队的代码结构保持一致仅靠口头约定远远不够这正是bitwarden/nx-plugin存在的理由。按 libs/nx-plugin/README.md 的说明该插件被设计用来强制执行 Bitwarden 的架构决策与代码组织方式简化新库、新组件的创建流程保证项目内配置的一致性自动更新项目的元数据与配置文件降低新贡献者的上手成本。插件的包定义位于 libs/nx-plugin/package.json其generators字段指向同目录下的 generators.json后者是 Nx 发现生成器的入口清单。插件本身由 Platform 团队维护但任何团队都可以为其贡献新的生成器。什么是 Nx GeneratorsNx generators 是遵循模板的代码生成工具可以在项目中创建或修改文件。按 libs/nx-plugin/README.md 的归纳它们能够依据模板创建新文件修改已有文件更新配置文件确保一致的项目结构自动化重复性任务。如果你熟悉 Angular CLI 的代码生成工具可以把 Nx generators 理解为更大规模的同类工具。生成器通过 Nx CLI 运行命令为nx generate简写nx g。从源码看这个描述非常具体basic-lib生成器通过nx/devkit的generateFiles将 files/ 目录下的__tmpl__模板渲染到目标库目录再通过updateJson、tree.write等 API 修改根级配置文件见 basic-lib.ts。也就是说修改配置文件并不是顺带一提而是生成器的核心职责之一。何时应该使用生成器官方文档给出的使用场景libs/nx-plugin/README.md包括创建遵循标准模式的新库、组件或特性希望在应用的相似部分之间保持一致性需要自动化重复性的搭建任务希望在项目搭建阶段降低人为出错概率。在 Bitwarden clients 中最常见的触发场景就是新增一个libs/下的功能库——这正是basic-lib生成器覆盖的用例。安装与运行环境bitwarden/nx-plugin以开发依赖的形式包含在仓库中。克隆仓库后执行npm install即可完成安装无需额外配置即可使用其生成器见 libs/nx-plugin/README.md。插件的运行依赖nx/devkit、nx/js、nx/eslint、nx/jest等均由 Nx 工作区统一提供。其自身的构建、lint、test 三个 target 定义在 project.json 中build使用nx/js:tsc输出到dist/libs/nx-plugin并把generators.json、*.md与非 TS 资源一并拷贝进产物test使用nx/jest:jest通过 jest.config.ts 以 node 环境运行。可用生成器一览截至当前仓库版本插件内置的生成器清单定义在 generators.json{ generators: { basic-lib: { factory: ./src/generators/basic-lib, schema: ./src/generators/schema.json, description: basic-lib generator } } }当前只包含一个生成器basic-lib创建一个具备标准配置与结构的全新库。完整的使用文档位于 libs/nx-plugin/docs/using-the-basic-lib-generator.md。官方文档同时说明未来可能会加入更多生成器以支持 Bitwarden 代码库中的其他常见模式。basic-lib生成器命令语法与参数详解命令语法在仓库根目录执行npx nx g bitwarden/nx-plugin:basic-lib如果直接在项目内使用已配置的 Nx CLI也可以省略npxnx g bitwarden/nx-plugin:basic-lib参数表basic-lib的全部参数定义在 schema.json对应 TypeScript 接口见 schema.d.ts。官方文档using-the-basic-lib-generator.md给出的参数表如下选项说明是否必填默认值--name库的名称是---description库的一句话简介是none--team负责维护该库的团队是none--directory库的创建目录是libs所有字段虽然都是必填项但并非都要以 CLI 标志提供未通过命令行提供的参数生成器会交互式地向用户提问。从 schema.json 可以进一步看到这些参数的底层约束name通过$default默认取 argv 的第 0 个位置参数即命令中的第一个位置参数并强制匹配^[a-z0-9](-[a-z0-9])*$也就是只能使用小写字母、数字与连字符构成的 kebab-case例如password-insulter、state-internaldescription一句话描述将写入生成的package.json与README.mddirectory默认libsteam一个带枚举约束的交互式列表可选项与 basic-lib.ts 中的团队映射一一对应包括admin-console、auth、autofill、billing、data-insights-and-reporting、key-management、platform、tools、ui-foundation、vault十个团队。完整命令行示例官方文档给出的示例是创建一个名为password-insulter的工具库using-the-basic-lib-generator.mdnx g bitwarden/nx-plugin:basic-lib --namepassword-insulter --descriptionLike the password strength meter, but more judgemental --teamtools执行步骤为打开终端并进入 Bitwarden clients 仓库根目录运行上述生成命令生成器创建库结构并更新必要的配置文件新库即可直接使用。生成器实际做了什么源码级的执行链路把官方文档的创建结构 更新配置落到源码上basic-lib的执行逻辑非常清晰basic-lib.tsconst projectRoot ${options.directory}/${options.name}; const srcRoot ${projectRoot}/src; generateFiles(tree, path.join(__dirname, files), projectRoot, { ...options, tmpl: , name: options.name, root: projectRoot, offsetFromRoot: offsetFromRoot(projectRoot), }); // 更新 tsconfig.base.json 的路径映射 updateTsConfigPath(tree, options.name, srcRoot); // 更新 .github/CODEOWNERS updateCodeowners(tree, options.directory, options.name, options.team); // 更新根 jest.config.js updateJestConfig(tree, options.directory, options.name); await formatFiles(tree); const tasks: GeneratorCallback[] []; tasks.push(() { execSync(npm install, { stdio: inherit }); return Promise.resolve(); }); return runTasksInSerial(...tasks);其核心工作分为四步渲染模板文件用generateFiles把 files/ 下的__tmpl__模板渲染到libs/name/模板中可以插值name、description、team、offsetFromRoot等变量注册路径别名updateTsConfigPath向根级 tsconfig.base.json 的compilerOptions.paths写入bitwarden/name - ./srcRoot/index.ts从而让全仓库都能通过bitwarden/name导入该库登记代码归属updateCodeowners向 .github/CODEOWNERS 追加libs/name bitwarden/team-team-dev行将新库归属到指定团队接入测试聚合updateJestConfig把rootDir/libs/name/jest.config.js按字母序插入根级 jest.config.js 的projects列表保证新库的测试进入 CI 流水线。最后生成器还会运行prettier格式化所有新文件并在结束后执行npm install。实现细节上仓库刻意没有使用nx/devkit自带的installPackagesTask而是用execSync(npm install)手动安装因为前者在当时的场景下会让package-lock处于损坏状态见 basic-lib.ts 的注释。三个更新函数都做了容错处理若.github/CODEOWNERS不存在会打印CODEOWNERS file not found at .github/CODEOWNERS警告并跳过basic-lib.ts若根jest.config.js不存在会打印警告并跳过basic-lib.ts团队名到 GitHub handle 的映射表basic-lib.ts支持admin-console、auth、autofill、billing、data-insights-and-reporting、key-management、platform、tools、ui-foundation、vault十种已知团队未知团队则回退为bitwarden/team-team-dev的通用格式。这些行为全部由 basic-lib.spec.ts 中的测试用例逐一验证例如断言tsconfig.base.json中会生成bitwarden/test - ./libs/test/src/index.ts路径映射断言 CODEOWNERS 中会追加libs/test bitwarden/team-platform-dev断言根jest.config.js中新库条目按字母序位于auth与vault之间断言缺失 CODEOWNERS / jest.config.js 时会优雅降级并输出警告。生成产物库结构与配置文件更新库内部结构按官方文档using-the-basic-lib-generator.md生成后的目录结构为libs/password-insulter/ ├── src/ │ ├── index.ts # 主入口 │ └── name.spec.ts # 同名测试文件 ├── README.md # 包含提供的 description ├── package.json # 极简的包描述 ├── project.json # Nx 项目配置build/lint/test ├── eslint.config.mjs # ESLint 扁平配置 ├── jest.config.js # Jest 测试配置 ├── tsconfig.json ├── tsconfig.lib.json # 库专用 TS 配置 └── tsconfig.spec.json # 测试专用 TS 配置注意官方文档写的是.eslintrc.json而当前仓库实际生成的是 eslint.config.mjs__tmpl__这是 ESLint 9 扁平配置时代的新命名测试用例basic-lib.spec.ts也断言生成eslint.config.mjs而非.eslintrc.json读者应以仓库实际行为为准。各模板的具体内容可以进一步查看index.ts__tmpl__库的主入口对外导出公共 APIREADME.md__tmpl__渲染为「标题 所属团队 描述」三段式project.json__tmpl__预置buildnx/js:tsc、lintnx/eslint:lint、testnx/jest:jest三个标准 target并自动代入库名与相对根目录的偏移量jest.config.js__tmpl__ 等其余配置模板。配置文件的联动更新除库自身文件外生成器还会自动修改三个根级文件tsconfig.base.json注册bitwarden/name路径别名全仓库即可直接按包名导入.github/CODEOWNERS新增libs/name bitwarden/team-team-dev把代码评审与维护责任交给对应团队jest.config.js把新库的 jest 配置按字母序加入聚合的projects数组纳入统一测试执行。npm install会作为生成任务的收尾自动执行把新库的依赖关系链接到位。生成后的下一步官方文档建议的后续步骤using-the-basic-lib-generator.md检查生成的README.md按需补充更详细的说明在src/目录中实现库代码可以按你的偏好使用任意子目录结构通过src/index.ts导出公共 API为库编写测试构建npx nx build password-insulter检查npx nx lint password-insulter测试npx nx test password-insulter。这三个命令正是 project.json__tmpl__ 中预置的build/lint/testtarget生成器已经把可运行的执行链搭好。常见问题排查官方文档给出了两个高频问题的处理办法using-the-basic-lib-generator.md问题生成器报路径错误解决方案确认命令是在仓库根目录执行的。问题TypeScript 路径映射不生效解决方案运行npx nx reset清空 Nx 缓存再重新从新库导入。结合源码还可以补充一条如果看到CODEOWNERS file not found或jest.config.js file not found警告说明对应根文件缺失生成器已按容错逻辑跳过该步骤需要人工补齐参见 basic-lib.spec.ts 与 basic-lib.spec.ts 的容错测试。扩展生成的代码生成的库是一个可以自由扩展的基础骨架using-the-basic-lib-generator.md为特定功能增加更多目录在src/下创建子目录以优化组织针对专门的测试需求修改 Jest 配置。库设计策略四种方案与 Platform 团队的建议官方文档用一个专门章节讨论了 monorepo 中的库切分策略using-the-basic-lib-generator.md这部分对决定把什么放进一个库至关重要也与仓库中libs/的既有格局直接相关。方案一按功能Feature切分功能库的导入形式为bitwarden/[feature]例如bitwarden/global-state。如果某个功能既有 UI 组件又需要被 CLI 使用通常会再拆出一个bitwarden/[feature]-ui或bitwarden/[feature]-angular库。[!NOTE] 官方文档提示随着越来越多的能力被加入 SDK、CLI 最终会用 Rust 直接编写同时存在带 Angular 依赖的包与不带 Angular 依赖的包的需求会越来越少。优点库更小、依赖更少其他团队引用时不容易产生循环依赖功能换团队时通常只需更新 GitHub 的CODEOWNERS文件依赖图更清晰模块体积更小。缺点需要花时间思考和定义什么是功能创建库的频率较高可能仍需要胶水库仅从库名看不出谁拥有哪个功能。[!NOTE]胶水库Glue library一种仅为跨团队协作而存在的库例如存放团队 B 需要实现、团队 A 负责消费的接口。它把两个功能粘合在一起同时让团队 A 仍能消费团队 B 库中的其他内容并避免循环依赖。方案二按团队Team切分把团队绝大部分代码放进一个包中。但官方文档明确指出如果所有团队都走这条路最终不可能只有这些团队库——因为团队分组极大概率导致循环依赖。例如团队 A 依赖团队 B 的库后团队 B 就无法再依赖团队 A 库中的任何内容若确有需要必须请求团队 A 把代码下移move downstream随之而来的是重命名、全量更新导入路径、代码与相似代码分离等一系列成本。优点需要维护的库更少团队代码集中在一处。缺点为了做胶水库需要频繁临时搬移代码且每次都要重新设计包抽象团队一旦拆分就要搬动大量代码模块更大。方案三按类型Type切分按文件的主要类型切分库例如一个库放所有type、一个放abstractions、再一个放services。由于所有 type 放一个库意味着多团队共管这并不被鼓励因此实际上通常会按团队再拆分形成类似bitwarden/platform-types的包——从本质上说这是团队方案的子集。优点团队代码内部不太容易出现循环依赖因为通常Types Abstractions Services表示层级更低与项目长期以来的组织方式最接近。缺点无法保证某团队的所有类型都比它要依赖的另一团队的类型层级更低团队间的循环依赖仍可能发生类型也可能需要依赖抽象官方目前总体上不鼓励团队随意创建抽象层。方案四功能/类型混合在功能库内部再按条目类型拆分。优点未来出现循环依赖的概率最低所有权移交非常容易。缺点需要维护的库数量最多使用者为了用上某个功能往往要引入多个模块。Platform 团队的建议综合以上取舍Platform 团队计划采用按功能切分并推荐其他团队同样如此using-the-basic-lib-generator.md同时承认在存储storage这类只在具体 app 中才有实现价值的领域也会出现只含抽象与极简类型的库形态接近类型方案。官方文档给出的 Platform 功能库示例均可通过bitwarden/[feature]导入storage-coreuser-stateglobal-statestate自带代码同时作为元包再导出user-state与global-stateclipboardmessagingipcconfighttpi18nenvironmentsserver-notificationssync这些例子与仓库中 libs/ 的实际布局高度吻合——例如libs/state、libs/messaging、libs/storage-core等均在仓库中存在可以对照查看其内部结构来理解功能库的落地形态。创建你自己的 Nx 生成器如果你为某个通用模式提炼出了新的生成器官方给出了标准的开发入口libs/nx-plugin/README.mdnpx nx generate nx/plugin:generator libs/nx-plugin/src/generators/your-generator-name-here该命令会基于nx/plugin插件脚手架生成一个基本的生成器结构。之后你需要在 libs/nx-plugin/src/generators 下实现生成器逻辑factory 函数 schema.json/schema.d.ts 模板目录files/参考 basic-lib.spec.ts 的写法用createTreeWithEmptyWorkspace编写基于虚拟文件树的单元测试在 generators.json 中注册新生成器factory 指向实现文件schema 指向参数定义最后运行nx test nx-plugin验证。关于 Nx 插件开发本身官方文档推荐继续阅读 Nx 官方的插件开发与库类型资料见 libs/nx-plugin/README.md 的 Further Learning 部分这里不再展开。小结bitwarden/nx-plugin是 Bitwarden clients 仓库中一个小而关键的基础设施它把新建一个符合标准、接入全链路配置的库从一串容易出错的手工操作收敛成一条nx g bitwarden/nx-plugin:basic-lib命令。透过 basic-lib.ts 的源码可以看到生成器远不止复制模板——路径别名注册、CODEOWNERS 归属、jest 聚合配置、依赖安装、格式化与容错处理共同构成了一个完整的工程化闭环而 basic-lib.spec.ts 中的测试则为这个闭环提供了行为契约。对任何在 Bitwarden clients 仓库中工作的开发者来说掌握basic-lib的参数与产物就意味着掌握了团队约定的库创建标准对想要扩展 Nx 生态的工程师而言它也是一份结构清晰的自定义生成器参考实现。【免费下载链接】clientsBitwarden client apps (web, browser extension, desktop, and cli).项目地址: https://gitcode.com/GitHub_Trending/cl/clients创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表