你好,我是 Kagol,个人公众号:前端开源星球

OpenTiny TinyVue 采用了一套由 pnpm workspaces 驱动的复杂 monorepo 架构,旨在管理一个支持 Vue 2 和 Vue 3、PC 和移动平台的企业级组件库。这种结构能够在保持构建效率和依赖一致性的同时,协调多个相互依赖的包的开发。

工作区配置

工作区的基础在根目录的 pnpm-workspace.yaml 配置中定义,该配置建立了三个主要包类别:生产包、开发示例和内部工具。此配置使 pnpm 能够通过工作区协议管理包间依赖,确保跨包的更改被正确跟踪和安装。工作区还利用 pnpm 的目录功能,为 TypeScript、Vite、Vitest 和 Playwright 等关键依赖维护统一版本,减少 monorepo 中的版本冲突。

根包管理

根目录的 package.json 强制执行严格的工具要求,要求 Node.js 18+ 和 pnpm 9.5+,并通过预安装钩子确保只使用 pnpm 进行包管理。这防止了因不同包管理器导致的安装不一致问题。根包通过集中脚本协调所有构建操作,这些脚本使用 pnpm 的过滤功能委托给特定工作区。例如,pnpm dev 和 pnpm dev2 等开发命令分别针对 Vue 3 和 Vue 2 示例环境,而构建命令则协调复杂的多包构建序列。

包架构

packages/ 目录包含按逻辑域组织的核心库架构:

包类别 用途 关键包
核心组件 组件实现 vue, vue-runtime, vue-common
逻辑层 无渲染/无头组件 renderless
主题 视觉设计系统 theme, theme-saas
工具 辅助函数和工具 utils, vue-hooks, vue-directive
图标 图标组件库 vue-icon, vue-icon-saas, vue-icon-multicolor
国际化 语言支持 vue-locale
设计规范 设计系统资源 design (aurora, saas, smb)

主要的 @opentiny/vue 包作为入口点,通过工作区依赖聚合了超过 200 个独立组件包。每个组件包遵循一致的结构,拥有自己的构建配置,同时依赖 @opentiny/vue-renderless 等共享包处理业务逻辑,依赖 @opentiny/vue-theme 处理样式。

无渲染架构

@opentiny/vue-renderless 包实现了无头组件模式,仅包含业务逻辑而不包含 UI 实现。这种分离允许同一逻辑在不同视觉实现和主题变体中复用。该包使用 tsup 进行高效的 TypeScript 编译,生成保留模块结构的 ESM 格式输出,以实现最优的 tree-shaking。构建配置包含通过自定义路径映射的专门类型生成,这些映射解析工作区别名和虚拟模块。

主题系统

主题架构通过独立的主题包支持多个设计系统。@opentiny/vue-theme 包使用 Gulp 提供 CSS 处理的基础实现,包括 autoprefixer、压缩和 Less 编译。@opentiny/vue-theme-saas 变体通过 Tailwind CSS 集成和自定义插件扩展了这一基础,展示了 monorepo 如何在不修改核心组件的情况下支持不同产品环境的主题定制。

开发环境

examples/ 目录为不同场景提供了隔离的开发环境:

  • vue3/ - 在端口 7130 上运行的 Vue 3 开发环境,使用 Vite,通过不同的 Vite 配置模式支持标准和 SaaS 模式
  • vue2/ - 在端口 7126 上的 Vue 2 开发环境,使用传统 Vue 工具链,包括 vue-template-compiler 和 Composition API polyfill 以实现功能对等
  • sites/ - 官方文档站点,具有针对不同部署目标(生产、alpha、SaaS、移动端)的多种构建模式
  • docs/ - 支持 PC 和移动优先模式的文档模板

两个 Vue 环境都使用工作区协议依赖直接从源代码消费包,实现无需构建步骤的实时重载开发。它们还包括使用 Playwright 进行 E2E 测试和使用 Vitest 进行单元测试的全面测试基础设施。

内部工具

internals/ 目录包含构建基础设施和自动化工具,这些工具不发布但对开发至关重要:

工具 用途
cli 构建协调、入口生成和组件脚手架
automate SVG 到 JS 转换、自动发布和资源管理
playwright-config 共享的 E2E 测试配置
unplugin-virtual-template 用于虚拟模板模块解析的 Vite 插件
vite-plugin-template2jsx 模板到 JSX 转换插件
vue-test-utils 具有 PC 和移动挂载模式的自定义测试工具

内部 CLI 作为构建协调器,处理生成组件入口点、映射依赖关系和构建运行时包等复杂操作。这些工具展示了 monorepo 如何通过针对组件库特定需求定制的自定义自动化来扩展 pnpm 的功能。

依赖管理策略

Monorepo 通过多种机制采用复杂的依赖管理:

  1. 工作区协议 - 内部包使用 workspace:* 或 workspace:~ 表示法,允许 pnpm 本地解析它们并在构建期间自动更新版本
  2. 目录依赖 - TypeScript、Vite 和 Vitest 等通用开发依赖通过目录功能管理,确保所有包的版本一致
  3. 覆盖 - Vue 版本等关键依赖在根级别被覆盖,以防止版本冲突并启用双 Vue 2/3 支持策略
  4. 补丁依赖 - 对 depcheck 和 tsup 等工具的自定义补丁解决了这些工具在特定用例中的限制

带有波浪号的工作区协议(workspace:~)尤为重要,因为它允许 pnpm 将依赖解析到工作区版本,同时保持语义版本兼容性,确保开发构建期间的顺利更新。

构建和发布工作流

构建管道展示了 monorepo 的协调能力。构建完整组件库涉及由内部 CLI 管理的多个阶段:

  1. 组件映射生成识别所有组件及其依赖
  2. 入口点生成创建优化的导入路径
  3. 主题、无渲染、工具和钩子的并行包构建
  4. 按需加载的运行时包组装
  5. 分发到 packages/dist2(Vue 2)和 packages/dist3(Vue 3)

发布工作流利用 pnpm 的过滤功能原子地发布多个包。pnpm pub:all 等命令协调 Vue 2、Vue 3、主题、无渲染和工具包到 npm 的顺序发布,每个包都定位到其适当的分发目录。

Monorepo 优势

这种架构带来了几个关键优势:

  • 代码复用 - 无渲染层实现 Vue 2 和 Vue 3 实现之间的逻辑共享,将组件业务逻辑的重复减少约 50%
  • 隔离开发 - 每个包可以独立开发、测试和版本控制,同时保持清晰的依赖关系
  • 高效构建 - pnpm 的工作区感知依赖提升和构建协调最小化冗余安装和编译
  • 灵活消费 - 开发者可以导入完整库、特定组件,甚至直接导入无渲染层,实现不同的使用模式
  • 跨平台支持 - 通过适配器层和条件编译,单一代码库支持 Vue 2、Vue 3、PC 和移动端

联系我们

GitHub:https://github.com/opentiny/tiny-vue(欢迎 Star ⭐)

官网:https://opentiny.design/tiny-vue

个人博客:kagol.com.cn

小助手微信:opentiny-official

公众号:OpenTiny

Logo

OpenTiny 是企业智能前端开发解决方案,以生成式 UI 和 WebMCP 两大自主核心技术为基础,加速企业应用的智能化改造。我们会在社区定期为大家分享一些前后端的技术文章。

更多推荐