使用lerna创建库

monorepo、lerna是什么?

Monorepo 是管理项目代码的一个方式,指在一个项目仓库 (repo) 中管理多个模块/包 (package),不同于常见的每个模块建一个 repo。
Lerna是一种Monorepo的解决方案
Lerna是一个用来优化托管在 git\npm 上的多 package 代码库的工作流的一个管理工具,可以让你在主项目下管理多个子项目,从而解决了多个包互相依赖,且发布时需要手动维护多个包的问题。

典型场景描述

  • 有一个业务组件仓库,里边有 N个 业务组件
  • 每个业务组件是一个 单独 的 npm 包
  • 作为一个 包管理者
  • 每一次仓库的更新,都意味极有可能需要发一遍包

lerna处理机制

lerna 对于包的管理,有两种模式:固定模式(fixed)、独立模式(independent)。

  • 固定模式(fixed):所有包是统一的版本号,每次升级,所有包版本统一更新

    lerna 的配置文件 lerna.json 中永远会存在一个确定版本号

  1. {
  2. "version": "0.0.1"
  3. }
  • 独立模式(independent):每个包是单独的版本号,每次lerna 触发发布命令,每个包的版本都会单独变化.

    lerna 的配置文件 lerna.json 中没有一个确定版本号

  1. {
  2. "version": "independent"
  3. }

Lerna 初始化

安装lerna

  1. $ npm i lerna -g

项目初始化

  1. $ cd lerna-first
  2. # 默认是 fixed 模式
  3. $ lerna init
  4. # 创建的项目多数采用 independent 模式
  5. $ lerna init -i #或者 lerna init --independent

生产目录结构

  1. └── lerna-pro/
  2. ├── packages/
  3. ├── lerna.json
  4. └── package.json

创建package包

  1. lerna create lvue //创建一个新的由 lerna 管理的包lvue

执行的配置命令采用默认

  1. package name: (lvue)
  2. version: (1.0.0)
  3. description:
  4. keywords:
  5. homepage:
  6. license: (ISC)
  7. entry point: (lib/lvue.js)
  8. git repository: (https://gitee.com/shenshuai89/lerna-first.git)
  9. About to write to /Users/shuai/Desktop/code/nodeapp/lerna-pro/lerna-second/packages/lvue/package.json:
  10. {
  11. "name": "lvue",
  12. "version": "1.0.0",
  13. "description": "> TODO: description",
  14. "author": "shuai <shenshuai89@qq.com>",
  15. "homepage": "",
  16. "license": "ISC",
  17. "main": "lib/lvue.js",
  18. "directories": {
  19. "lib": "lib",
  20. "test": "__tests__"
  21. },
  22. "files": [
  23. "lib"
  24. ],
  25. "repository": {
  26. "type": "git",
  27. "url": "https://gitee.com/shenshuai89/lerna-first.git"
  28. },
  29. "scripts": {
  30. "test": "echo \"Error: run tests from root\" && exit 1"
  31. }
  32. }
  33. Is this OK? (yes)
  34. lerna success create New package lvue created at ./packages/lvue

同样创建其它两个包

  1. lerna create lreact
  2. lerna create lnode

此时项目目录结构

  1. ├── lerna.json
  2. ├── package.json
  3. └── packages
  4. ├── lnode
  5. ├── README.md
  6. ├── __tests__
  7. └── lnode.test.js
  8. ├── lib
  9. └── lnode.js
  10. └── package.json
  11. ├── lreact
  12. ├── README.md
  13. ├── __tests__
  14. └── lreact.test.js
  15. ├── lib
  16. └── lreact.js
  17. └── package.json
  18. └── lvue
  19. ├── README.md
  20. ├── __tests__
  21. └── lvue.test.js
  22. ├── lib
  23. └── lvue.js
  24. └── package.json

查看项目下所有包

  1. lerna list
  2. # lerna info versioning independent
  3. # lnode
  4. # lreact
  5. # lvue
  6. # lerna success found 3 packages

添加包的依赖

使用lerna add packageName

  • 给所有 package 安装依赖,执行下面命令后给三个包的package.json 添加了axios包依赖

    1. lerna add axios
  • 给指定 package 安装依赖

    1. # 给lvue安装vue
    2. lerna add vue --scope=lvue
    3. # 或 lerna add vue packages/lvue
    4. # 或 lerna add vue **/lvue
    5. # 给lreact安装react
    6. lerna add react --scope=lreact
    7. # 给lnode安装lodash
    8. lerna add lodash --scope=lnode
  • workspace 之间的依赖 命令执行完成后
    lreact/package.json lnode/package.json

    1. # lreact添加lnode依赖
    2. lerna add lnode --scope lreact
    3. # lnode添加lvue依赖
    4. lerna add lvue --scope lnode
    1. "dependencies": {
    2. "axios": "^0.21.4",
    3. "lnode": "^1.0.1",
    4. "react": "^17.0.2"
    5. }
    1. "dependencies": {
    2. "axios": "^0.21.4",
    3. "lodash": "^4.17.21",
    4. "lvue": "^1.0.1"
    5. }

执行包的命令

lerna exec [command]

将三个包下的package.json中的scripts添加start命令,用来执行入口文件

  1. "scripts": {
  2. "start": "node lib/lnode.js"
  3. }

修改lreact包下的/lib/lreact.js

  1. // 引入lnode包
  2. const lnode = require("lnode");
  3. module.exports = lreact;
  4. function lreact() {
  5. // TODO
  6. console.log("lreact");
  7. // 执行lnode包
  8. lnode();
  9. }
  10. lreact();

修改lnode包下的/lib/lnode.js

  1. module.exports = lnode;
  2. const lvue = require("lvue");
  3. const _ = require('lodash')
  4. function lnode() {
  5. // TODO
  6. console.log("lnode");
  7. console.log(_.flattenDeep([1, [2, [3, [4]], 5]]));
  8. lvue();
  9. }
  10. lnode();
  • 修改完成后,可以执行,该命令会执行三个包中的所有yarn run start脚本

    1. lerna exec -- yarn run start
  • 单独执行不同包下的脚本

    1. lerna exec --scope=lnode -- yarn run start
    2. lerna exec --scope=lreact -- yarn run start

删除包中的依赖node_modules

lerna clean
从所有包中删除 node_modules 目录。不会删除项目最外层的根 node_modules

发布包到npm

发布之前需要先登录npm,使用npm adduser进行登录。

执行发布包 命令

  1. lerna publish