Pnpm + Turbo 搭建 Web Component Monorepo 组件库

技术选型

使用 Pnpm + Turbo 搭建 Web Component Monorepo项目 stencil-component-ui 组件库

  • pnpm 作为包管理器
  • Turborepo 作为构建系统
  • Vitepress 管理文档

    pnpm 技术

    什么是 pnpm? 它有哪些优势?

    pnpm 跟 npm、yarn一样,都是用于管理Node包依赖的管理器,它是号称新一代的最先进包管理工具。按照官网说法,它相比其他包管理工具,可以大大节约磁盘空间并提升安装速度,创建非扁平化的 node_modules 文件夹,目录结构很清晰,具体介绍可以参考 pnpm 官网

    pnpm 提出了 workspace 的概念,内置了对 monorepo 的支持,那么为什么用 pnpm 取代之前的 lerna 呢?

    这里总结了以下几点原因:

    • lerna 已经不再维护,后续有任何问题社区无法及时响应
    • pnpm装包效率更高,并且可以节约更多磁盘空间
    • pnpm本身就预置了对monorepo的支持,不需要再额外第三方包的支持

      pnpm 搭建 menorepo 工程

      在工程根目录下新建 packages 目录,并且在 packages 目录下创建 components 和 icons 两个子项目,这里使用 stencil 脚手架,进入 packages 目录,根据 Stencil 官网 创建项目

      pnpm create stencil
      

      有三个选项,直接回车选择第一个 components 是创建组件库项目的,输入项目名称即可创建项目

      分别使用 stencil 创建了 components 和 icons 项目,components 是来开发组件库源码的,icons 是用来开发编译 svg 图片和组件的,目录如下

      在工程根目录建一个 pnpm-workspace.yaml,用于启用 workspace :

      packages:
        - "packages/*"
        - "docs"
      

      以上指定工作空间内的包依赖关系,packages 用于管理源码,docs 编写文档,然后执行 pnpm install 安装依赖

      由于工程根目录 package.json 不需要发包,需要配置 "private": true

      在项目中安装包

      Pnpm 启用了 workspace,用 Pnpm 安装依赖必须指定安装的位置。-w 是 --workspace-root 的别名,即安装到工程根目录,作为所有子模块的公共依赖。也可以用 -r 递归给每个子模块安装,或者用 --filter 给指定子模块安装。-D 是 --save-dev 的别名,即安装依赖到 devDependencies 节点下,不指定参数默认安装到 dependencies 节点。

      给每个项目起个包名,修改components 和 icons 项目 package.json 中的 name 字段为 @swc-ui/components 和 @swc-ui/icons,docs 使用 vitepress 搭建,包名直接用 docs

      这一步比较关键,安装包、构建、发包都需要用到这个包名。@swc-ui 是提前创建好的 scope,如果没有的话需要先创建

      图标库、组件库包安装到 docs 使用,图标库包安装到组件库项目中使用,使用 --filter 指定安装包的位置

      pnpm add @swc-ui/components @swc-ui/icons  --filter=docs
      pnpm add @swc-ui/icons  --filter=@swc-ui/components
      

      components 安装 @swc-ui/icons 后,package.json新增了 "@swc-ui/icons": "workspace:^"

      "dependencies": { "@swc-ui/icons": "workspace:^"
        }
      

      通过 Pnpm 提供的 Workspace Protocol,可以很方便地实现子模块互相引用。在开发的时候,也推荐使用 workspace:^,这样可以确保依赖的是最新版本代码。当我们用 pnpm publish 发包的时候,Pnpm 会将 workspace:^ 替换为实际的版本。

      只允许 pnpm

      当在项目中使用 pnpm 时,如果不希望开发者使用 yarn 或者 npm 安装依赖,可以将下面的这个 preinstall 脚本添加到工程根目录下的 package.json 中:

      "preinstall": "npx only-allow pnpm"
      

      因为在在 Pnpm workspace 模式下 npm install 或者 yarn install 安装依赖无法兼容,整个工程很可能跑不起来,所以用 only-allow 库去限制包管理器,当用了其他包管理器,会直接抛异常退出进程。

      Turborepo

      在项目开发和打包发布,必须先启动 icons 和 components 项目编译构建,才能运行 docs 文档,如果使用 pnpm 构建,可能需要使用 -r 或者 && 并行执行,如

      { "scripts": { "build": "pnpm -r --parallel --filter=./packages/* run build",
          "test": "pnpm -r --parallel --filter=./packages/* run test"
        }
      }
      

      Pnpm 给我们提供的 -r 参数递归执行 NPM scripts,但是它不能按照先后顺序执行串行的任务,并且 -r 过于简单粗暴,有些模块明明没有修改代码,任务还是全量执行,影响 CI 构建效率。

      专业的事交给专业的工具去解决,而 Turborepo 就非常擅长实现任务编排

      什么是Turborepo?

      Turborepo 是一个高性能的 JavaScript 和 TypeScript 项目构建系统,采用Go语言实现,所以在语言层面上就具有一定的性能优势,可以大大提高monorepo项目的构建速度。

      在开发层面, Turborepo抽象出所有繁琐的配置、脚本和工具,减少项目配置的复杂性,可以让我们专注于业务的开发,并且支持使用 Yarn、Npm、Pnpm

      TurboRepo的优势

      1、多任务并行处理

      Turbo支持多个任务的并行运行,我们在对多个子包,编译打包的过程中,turbo会同时进行多个任务的处理

      对于项目中 A 依赖于 B,B 依赖于 C,构建串行顺序为 C、B、A。Turbo它能够有效地安排任务类似于瀑布可以同时异步执行多个任务,而 lerna 一次只能执行一项任务 所以Turbo的性能不言而喻。

      2、更快的增量构建

      如果我们的项目过大,构建多个子包会造成时间和性能的浪费,turborepo中的缓存机制 可以帮助我们记住构建内容 并且跳过已经计算过的内容,优化打包效率。

      3、任务管道

      用配置文件定义任务之间的关系,然后让Turborepo优化构建内容和时间。

      4、远程云缓存

      Turbo通过其远程缓存功能,团队成员、CI/CD 共享远程构建缓存,以实现更快的构建。

      安装到项目

      1、在项目根目录下,安装turbo依赖

      pnpm i turbo --save-dev -w
      

      2、在根目录下添加 turbo.json 配置文件,向 pipeline 字段中配置 npm scripts 中的命令,比如 dev, build 命令

      { "$schema": "https://turbo.build/schema.json",
        "pipeline": { "build": { "dependsOn": ["^build"],
            "outputs": [".next/**", "!.next/cache/**"]
          },
          "dev": { "cache": false,
            "persistent": true
          }
        }
      }
      

      3、在根目录 package 配置 scripts

      "scripts": { "dev": "turbo run dev",
        "build": "turbo run build"
      }
      

      以上 Turborepo 项目就简单配置完成了,Turbo 和 Pnpm Workspace 很好的结合起来管理 monorepo 项目

      Turbo 开发环境

      当执行 npm run dev 命令,Turbo 会分析 Package 包的依赖关系,运行 @swc-ui/icons、@swc-ui/components docs 开发环境,通过 turbo.json 配置一行命令就启动了开发环境,不需要手动去执行 icon、components、docs的命令

      Turbo 构建打包

      Turbo 构建提供了缓存,当执行 npm run build 全部构建需要花费1分钟06秒 ,第二次构建修改了一个包,花费了 30 秒,第三次没有修改源码重新构建,1秒内构建完,明显可以感受到 Turbo 缓存构建的优势。

      如对新技术开发组件库感兴趣,也欢迎加入stencil-component-ui,给个 star 鼓励一下 👏👏