• Lerna入门与实战


    一、Lerna简介

    1.1 lerna背景

    维护过多个package项目的同学可能都会遇到一个问题:package是放在一个仓库里维护还是放在多个仓库里单独维护。当package数量较少的时候,多个仓库维护不会有太大问题,但package数量逐渐增多时,一些问题逐渐暴露出来:

    • package之间相互依赖,开发人员需要在本地手动执行npm link,维护版本号的更替;
    • issue难以统一追踪,管理,因为其分散在独立的repo里;
    • 每一个package都包含独立的node_modules,而且大部分都包含babel,webpack等开发时依赖,安装耗时冗余并且占用过多空间。

    正是在这一需求背景下,babel团队推出的多包管理工具lerna,旨在优化基于Git+npm的多package项目的包管理方式。 像现在流行的vue-cli, create-react-app 等脚手架工具都有用到lerna。lerna是架构优化的产物,而架构优化的主要目标是以提高ROI为核心的多package管理。

    作为一种多包依赖解决方案,lerna具体如下特点:

    • 可以管理公共依赖和单独依赖;
    • 多package相互依赖直接内部 link,不必发版;
    • 支持项目的单独发布和全体发布;
    • 多包放一个git仓库,利于代码管理,如配置统一的代码规范;

    1.2 两种模式

    lerna有两种工作模式,Independent模式和Fixed/Locked模式。这两种模式有什么区别呢?lerna的默认模式是Fixed/Locked mode,在这种模式下,lerna会是把工程当作一个整体来对待,每次发布packges,都是全量发布,无论修改与否。但是在Independent mode下,lerna会配合Git,检查文件变动,只发布有改动的包。

    二、快速上手

    2.1 安装lerna

    使用lerna之前,需要全局安装lerna,安装的命令如下:

    yarn global add lerna 
    #or     
    npm install lerna -g
    
    • 1
    • 2
    • 3

    如果是在已经存在的项目中安装lerna,使用下面的方式:

    lerna bootstap
    
    • 1

    2.2 初始化项目

    使用lerna 初始化项目的方式和使用npm方式类似。首先,我们在一个空目录中执行如下初始化命令。

    lerna init
    
    • 1

    默认使用的是固定模式,packages下的所有包共用一个版本号,如果使用独立模式,需要在init后面加一个参数。

    lerna init --independent
    
    • 1

    执行上面的命令后,lerna会创建一个lerna.json配置文件和packages文件夹,此时项目的目录结构如下。

    lerna-repo/
      packages/
      package.json
      lerna.json
    
    • 1
    • 2
    • 3
    • 4

    lerna.json中的packages配置是一个通配符列表,用于匹配包含了package.json的的目录。

    2.2.1 lerna.json

    其中,lerna.json的文件配置内容如下:

    {
      "version": "1.1.3",
      "npmClient": "npm",
      "command": {
        "publish": {
          "ignoreChanges": ["ignored-file", "*.md"],
          "message": "chore(release): publish",
          "registry": "https://npm.pkg.github.com"
        },
        "bootstrap": {
          "ignore": "component-*",
          "npmClientArgs": ["--no-package-lock"]
        }
      },
      "packages": ["packages/*"]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    下面是部分属性的说明:

    • version:当前版本
    • npmClient:指定运行命令的客户端,设定为"yarn"则使用yarn运行,默认值是"npm"。
    • command.publish.ignoreChanges:通配符的数组,其中的值不会被 lerna 监测更改和发布,使用它可以防止因更改发布不必要的新版本。
    • command.publish.message:执行发布版本更新时的自定义提交消息。
    • command.publish.registry:使用它来设置要发布的自定义注册 url,而非 npmjs.org。
    • command.bootstrap.ignore:运行lerna bootstrap指令时会忽视该字符串数组中的通配符匹配的文件。
    • command.bootstrap.npmClientArgs:该字符串数组中的参数将在lerna bootstrap命令期间直接传递给npm install。
    • command.bootstrap.scope:该通配符的数组会在lerna bootstrap命令运行时限制影响的范围。
    • packages :表示包位置的全局变量数组。

    2.2.2 其他命令

    除了上面的init命令外,项目使用过程中还会用到很多其他有用的命令。

    • lerna create:此命令的作用是用来创建一个子包名为xx的项目。
    • lerna add:此命令用于安装依赖,格式为lerna add [@version] [–dev]。
    • lerna list:查看当前包名列表。
    • lerna link:将所有相互依赖的包符号链接在一起。
    • lerna exec:在每个包中执行任意命令。
    • lerna run:在每个包中运行npm脚本如果该包中存在该脚本。

    2.3 新建模块

    接下来,新建moduleA和moduleB两个模块, 并且moduleA需要依赖moduleB。

    lerna create module-a
    lerna create module-b
    
    • 1
    • 2

    在module-a中引入module-b,module-a代码如下。

    // module-a
    'use strict';
    const moduleB = require('module-b');
    console.log('moduleB:', moduleB());
    
    
    module.exports = moduleA;
    
    
    function moduleA() {
        return 'it's module a';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    module-b的代码如下。

    // module-b
    'use strict';
    
    
    module.exports = moduleB;
    
    
    function moduleB() {
        return 'it's module b';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    此时,我们运行node packages/module-a/lib/module-a.js 可能会报错,提示找不到module-b模块,这是因为我们还没在moduleA中安装依赖,需要使用下面的命令安装依赖。

    lerna add module-b --scope=module-a
    
    • 1

    可以看到,module-a node_modules目录下安装了module-b包,重新运行上面的module-a代码会输出如下内容。

    $ node packages/module-a/lib/module-a.js                               
    moduleB: it's module b
    
    • 1
    • 2

    2.4 发布

    执行发布的时候,需要Git工具的配合,请确认此时该lerna工程已经连接到Git的远程仓库。如果是第一次发布,可能需要先执行如下命令。

    npm login --registry=https://registry.npmjs.org
    
    • 1

    然后,我们将module-a、module-b进行统一改个名称,比如统一加上@m_alfred前缀。

    @m_alfred/module-a
    @m_alfred/module-b
    
    • 1
    • 2

    然后,执行在输入用户名及密码之后执行发布命令。

    lerna publish
    
    • 1

    发布完成之后,即可在npm仓库看到对应的提交信息。

    $ lerna publish
    lerna notice cli v3.22.1
    lerna info current version 0.0.2
    lerna info Looking for changed packages since v0.0.2
    ? Select a new version (currently 0.0.2) Patch (0.0.3)
    
    
    Changes:
     - @m_alfred/module-a: 0.0.2 => 0.0.3
     - @m_alfred/module-b: 0.0.2 => 0.0.3
    
    
    ? Are you sure you want to publish these packages? Yes
    lerna info execute Skipping releases
    lerna info git Pushing tags...
    lerna info publish Publishing packages to npm...
    lerna info Verifying npm credentials
    lerna http fetch GET 200 https://registry.npmjs.org/-/npm/v1/user 1257ms
    lerna http fetch GET 200 https://registry.npmjs.org/-/org/m_alfred/package?format=cli 1405ms
    lerna info Checking two-factor auth mode
    lerna http fetch GET 200 https://registry.npmjs.org/-/npm/v1/user 408ms
    lerna success published @m_alfred/module-b 0.0.3
    lerna notice 
    lerna notice 📦  @m_alfred/module-b@0.0.3
    lerna notice === Tarball Contents === 
    lerna notice 1.1kB LICENSE        
    lerna notice 94B   lib/module-b.js
    lerna notice 584B  package.json   
    lerna notice 116B  README.md      
    lerna notice === Tarball Details === 
    lerna notice name:          @m_alfred/module-b                      
    lerna notice version:       0.0.3                                   
    lerna notice filename:      m_alfred-module-b-0.0.3.tgz             
    lerna notice package size:  1.3 kB                                  
    lerna notice unpacked size: 1.9 kB                                  
    lerna notice shasum:        f530a9abcab3373758574f5b48c6f9eb65788d2a
    lerna notice integrity:     sha512-KFEkbN8COpoSj[...]2LRs0hY5U+z2w==
    lerna notice total files:   4                                       
    lerna notice 
    lerna http fetch PUT 200 https://registry.npmjs.org/@m_alfred%2fmodule-b 3077ms
    lerna success published @m_alfred/module-a 0.0.3
    lerna notice 
    lerna notice 📦  @m_alfred/module-a@0.0.3
    lerna notice === Tarball Contents === 
    lerna notice 1.1kB LICENSE        
    lerna notice 177B  lib/module-a.js
    lerna notice 620B  package.json   
    lerna notice 116B  README.md      
    lerna notice === Tarball Details === 
    lerna notice name:          @m_alfred/module-a                      
    lerna notice version:       0.0.3                                   
    lerna notice filename:      m_alfred-module-a-0.0.3.tgz             
    lerna notice package size:  1.3 kB                                  
    lerna notice unpacked size: 2.0 kB                                  
    lerna notice shasum:        27a2413b6761b76548ac199aa2df0377768715f5
    lerna notice integrity:     sha512-2H1QB5FdRaAuR[...]p7RYrOI2QdjSQ==
    lerna notice total files:   4                                       
    lerna notice 
    lerna info lifecycle root@undefined~publish: root@undefined
    lerna http fetch PUT 200 https://registry.npmjs.org/@m_alfred%2fmodule-a 6363ms
    
    
    > root@undefined publish /Users/alfred/workspace/jack-bean/lerna-example
    > lerna publish
    
    
    lerna notice cli v3.22.1
    lerna info current version 0.0.3
    lerna notice Current HEAD is already released, skipping change detection.
    lerna success No changed packages to publish 
    Successfully published:
     - @m_alfred/module-a@0.0.3
     - @m_alfred/module-b@0.0.3
    lerna success published 2 packages
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    发布成功后,单独修改moduleB代码,然后再执行发布命令。

    Changes:
     - @m_alfred/module-a: 0.0.3 => 0.0.4
     - @m_alfred/module-b: 0.0.3 => 0.0.4
    
    • 1
    • 2
    • 3

    可以看到,module-a版本也升级了,这是由于我们l在初始化erna init的时候使用的是默认的Fixed mode模式,所以packages下所有包都会使用同一版本号。

    2.5 共用devDependencies

    在开发过程中,很多模块都会依赖babel、eslint等模块,这些大多都是可以共用的。此时,我们可以通过lerna link convert命令将各个包package.json中共同的devDependencies移动到根目录的package.json中,将它们提升到项目根目录中,这样做的好处有:

    • 所有包使用相同版本的依赖,统一管理;
    • 可使用自动化工具让根目录下的依赖保持更新;
    • 减少依赖的安装时间,一次安装,多处使用;
    • 节省存储空间,安装在根目录的node_module下。

    三、工作过程总结

    下面是使用lerna的完整工作流程图。
    在这里插入图片描述
    参考:http://www.febeacon.com/lerna-docs-zh-cn/routes/basic/about.html

  • 相关阅读:
    Transforms的使用2(ToTensor类)
    C语言入门log03
    Playwright for Python:基础用法
    紫杉醇联合2-甲氧基雌二醇的白蛋白纳米粒/荜茇酰胺白蛋白纳米粒的研究制备
    秋招项目总结
    【华秋&Nidec尼得科】滑动开关CL-SB的应用
    荣誉丨“Qspace|轻空间”荣获“盐城市零碳空间工程技术研究中心”称号
    猿创征文|我是怎么学习编程的?
    Springboot jpa 查询排序Sort,分页Page使用报错
    web前端练习一
  • 原文地址:https://blog.csdn.net/xiangzhihong8/article/details/128142293