lerna

http://www.febeacon.com/lerna-docs-zh-cn/
Lerna + Yarn Workspace

  • lerna 发布管理
  • Yarn Workspace 依赖管理

    总体版本采用 lerna publish 进行总体发布,此时会强行将各个 npm 包版本保持到和 lerna 发布的版本同步(因此 lerna 是进行统一 npm 包版本管理)。

  1. npm install -g lerna
  2. 进入文件夹
  3. lerna init

lerna init

初始化,加上--independent参数,lerna 将会以独立版本控制的模式进行管理,即每个包将会是独立的版本号。

  1. ├── lerna.json
  2. ├── package.json
  3. └── packages
  4. ├── pkg1
  5. ├── index.js
  6. └── package.json
  7. └── pkg2
  8. ├── index.js
  9. └── package.json

lerna add

将本地或远程package作为依赖项添加到当前 Lerna 存储库中的包。一般用来软连接

  1. #将 module-1 包添加到 'prefix-' 前缀文件夹中的包中
  2. lerna add module-1 packages/prefix- *
  3. #将模块 1 安装到模块 2
  4. lerna add module-1 --scope=module-2
  5. #在 devDependencies 中安装 module-1 到 module-2
  6. lerna add module-1 --scope=module-2 --dev
  7. #在 peerDependencies 中安装 module-1 到 module-2
  8. lerna add module-1 --scope=module-2 --peer
  9. #在除module-1之外的所有模块中安装module-1
  10. lerna add module-1
  11. #在所有模块中安装 babel-core
  12. lerna add babel-core

lerna bootstrap

这个命令主要是用来执行 packages/ 目录下每个包的 npm install 命令,并将这些包直接的相互依赖关系进行链接。

lerna publish

通过 lerna publish 发布所有 npm 包的统一版本号,使所有 npm 包统一提升 MINOR 版本或 MAJOR 版本,通过 lerna 发布版本的同时会对项目整体进行打 tag。

  1. lerna publish # 用于发布更新
  2. lerna publish --skip-git # 不会创建git commit或tag
  3. lerna publish --skip-npm # 不会把包publish到npm上
  1. {
  2. // 定义各个项目存放的位置,这里我们新增一个examples/
  3. "packages": ["packages/*"],
  4. // lerna 总体版本
  5. "version": "0.0.0",
  6. // 执行命令的client,默认为npm,这里我们需要配置为yarn
  7. "npmClient": "yarn",
  8. // 使用workspace,需要配置package.json
  9. "useWorkspaces": true
  10. }

开启yarn工作区

  1. {
  2. "name": "root",
  3. "private": true,
  4. "devDependencies": {
  5. "lerna": "^4.0.0"
  6. },
  7. "workspaces": [
  8. "packages/*" // 开启yarn工作区
  9. ]
  10. }
  1. yarn add jest -W // 根目录安装 全局安装
  2. yarn workspace test1 add vue // 子项目安装

MAJOR.MINOR.PATCH(主版本号.次版本号.修订号):

无论是 yarn 还是 lerna 都可以总结为

  • 将所有 package 的依赖都以扁平化的方式安装在工作区的根目录 node_modules,同时对于同一个依赖的不同版本,将其中一个版本安装到根目录,其他版本安装在各自 package 下的node_modules,解决依赖不同版本的冲突问题
  • 通过将各个 package 都软链到根目录 node_modules,各个 package 利用 node 的递归查找机制,可以导入其他 package,不需要手动 link
  • 通过将各个 package 中的 node_modules 的 bin 文件夹软链到根目录中的 node_modules,保证每个package 的 npm script 能正常运行

虽然解决了核心问题,但是又引入其他问题

  • 幻影依赖(phatom)被放大,例如全部依赖声明都扁平化在根目录 node_modules,由于 node 的递归查找,你可以访问到任何其他 package 的依赖,以及依赖的依赖。
  • 分身(doppelgangers)更容易出现,大量依赖的依赖不同版本,随机出现在 node_modules 的第一层,或者依赖的依赖中。

pnpm

pnpm介绍

  • npm 1/2的问题:依赖是递归安装的,会导致文件路径过深,依赖重复下载的问题,导致node_modules体积过大。
  • npm 3/yarn的问题:扁平化安装:
    • 幽灵依赖问题:引用了依赖模块的依赖,但是未来可能被删除
    • 分身依赖问题 :扁平化安装过程中,相同依赖的不同版本会同时存在各依赖模块中
      • 非单例
      • 体积大
  • monorepo问题:幽灵依赖和分身依赖问题会被放大

  • 软链接 sybbolic link 和 硬链接 hard link

    硬链接:inode 都指向同一个文件在硬盘中的区块,只能为文件创立 软链接:类似于windows系统中的快捷方式,与硬链接不同,软链接就是一个普通文件,只是数据块内容有点特殊,文件用户数据块中存放的内容是另一文件的路径名的指向,通过这个方式可以快速定位到软连接所指向的源文件实体。软链接可对文件或目录创建。

monorepo和pnpm - 图1

pnpm使用

  • 安装 pnpm
    1. npm i pnpm -g

然后pnpm init 项目
在根目录新建 pnpm-workspace.yaml,内容如下:

  1. packages:
  2. # all packages in subdirs of packages/ and components/
  3. - 'packages/**

我们所有的子项目都放在 packages 目录下。

  • 用 pnpm 安装全局共用的包,比如 lodash。注意这里使用-w表示把包安装在 root 下,

该包会放置在 /node_modules 下。

  1. pnpm install lodash -w // add也可以
  2. pnpm remove
  3. pnpm up //更新所有依赖项
  4. pnpm upgrade //更新包
  • 如需要把依赖安装在所有 packages 下的各个包中,使用-r

  • 使用 --filter 后面接子 package 的 name

    1. pnpm i vue@2 --filter pkg1
  • 项目内互相依赖

    1. pnpm i pkg2 -r --filter pkg1
  1. "dependencies": {
  2. "dayjs": "^1.11.1",
  3. "pkg2": "workspace:^1.0.0", // 用workspace: *,就可以保持依赖的最新版本
  4. "vue": "2"
  5. }
  1. ├── packages
  2. ├── pkg1
  3. ├── package.json
  4. └── pnpm-lock.yaml
  5. ├── pkg2
  6. ├── package.json
  7. └── pnpm-lock.yaml
  8. ├── package.json
  9. ├── pnpm-lock.yaml
  10. └── pnpm-workspace.yaml

参考资料

https://cloud.tencent.com/developer/article/1913720
https://zhuanlan.zhihu.com/p/419399115