lerna管理开源前端项目

2019-09-29  本文已影响0人  pansly

前言

由于公司项目大多采用react-native实现,在APP内部运行,但也要有H5的使用场景,以前很多项目都开发多套代码, 造成人力成本大幅浪费,基于此, 我主导开发了一套RN转H5的一套开发框架以及一整套的代码规范、推送CND等一系列的前端工程化体系, 然而有较多的私有库发布到公司内部NPM镜像上,私有库多了,每个库之间又相互依赖,一段时间下来,版本号就很难管理,大多数时候需要手动更新版本依赖;

其实babel的重要贡献者Jamie Kyle1,在为 Babel 6 工作的过程中发现所有东西都拆分成漂亮的小插件包,但同时也就需要管理数十个软件包, 也遇到同样的问题。因此,多包存储库管理工具 Lerna 应运而生。为让项目更好用,他对项目进行了多次重写,试图让架构更完善。

什么是Lerna

Lerna官网对此给出了官方的解释:Lerna是一个管理包含多个软件包的JavaScript项目的工具。它可以:

1、解决包之间的依赖关系。

2、通过git仓库检测改动,自动同步。

3、根据相关的git提交的commit,生成CHANGELOG。

Lerna是一个命令行工具,可以将其安装在系统全局。简单的命令说明,可以使用:lerna -h查看命令帮助。

两种包管理模式

  1. 默认的为固定模式(Fixed mode),当使用lerna init命令初始化项目时,就默认为固定模式,也可以使用 lerna init --independent 命令初始化项目,这个时候就为独立模式(Independent mode)。

  2. 固定模式中,packages下的所有包共用一个版本号(version),会自动将所有的包绑定到一个版本号上(该版本号也就是lerna.json中的version字段),所以任意一个包发生了更新,这个共用的版本号就会发生改变。
    独立模式允许每一个包有一个独立的版本号,在使用lerna publish命令时,可以为每个包单独制定具体的操作,同时可以只更新某一个包的版本号。此种模式时,lerna.json中的version字段指定为independent即可。

添加lerna.json配置

{
    "version": "0.7.30", 
    "packages": [
        "packages/package-1",
        "packages/package-2",
        "packages/package-3",
        "packages/package-4"
    ],
    "command": {
        "publish": {
            "message": "chore(release): publish %s"
        },
        "bootstrap": {
            "npmClientArgs": [
                "--no-package-lock"
            ]
        }
    },
    "npmClient": "npm"
}

备注: 上面的配置文件中,部分字段做下如下说明:

  1. version指定的是所有包的统一版本号;对于independent模式,这个字段请指定为independent;

  2. npmClient指定的是npm的客户端。默认的,lerna将使用npm。读者也可依所需将程序设置为yarn,甚至cnpm等等。

  3. command字段,可以对publish和bootstrap命令进行参数传递和命令定制。如:command.publish.ignoreChanges,用来设置一些忽略的文件,以避免无关文件的提交对于版本号的变更,如README.md等等。command.bootstrap.npmClientArgs指定在bootstrap命令时,传递的默认参数,比如我们会常常使用--no-package-lock来禁止package-lock.json或yarn.lock等等。

  4. packages字段指定包所在的目录。

常用命令

Lerna命令

初始一个多包的工程

lerna init

上述命令会初始化一个多包工程。初始化之后会在根目录生成packages目录、lerna.json,如果使用independent模式,请使用命令:lerna init --independent

创建子包

lerna create <package> [-y]

在packages所指目录下创建package包。

添加包

lerna add <package>[@version] [--dev] [--exact] [--scope=module名]

上述命令会添加一个包package指明的软件包。

指定--dev是添加在devDependencies中。

指定--exact,则将用精确匹配的版本添加包。

指定--scope将只在此指明的模块中安装这个软件包,否则将在所有packages目录中的包中安装。

对于packages目录下的子包,将通过设立systemlink来解决依赖。

对于npm镜像中存在的包,将安装镜像中的包。

运行命令

运行命令分为两种:任意命令和npm scripts定义的命令。

对于任意命令使用,lerna exec;对于npm scripts定义的命令使用lerna run

以lerna exec为例:

lerna exec [--concurrency number] [--stream] [--parallel] -- <command> [..args]此命令,在所有包中运行所指定的命令。

特别地,lerna exec -- rm -rf ./node_modules将删除所有包中的依赖。lerna exec -- npm uninstall <package>将移除所有的package依赖。

lerna exec 和 lerna run 如需要每个子模块相继的执行并按顺序输出,可以指定--concurrency 1。

对于指定了--stream的命令,将把所有子进程的输出立即回显此举可能造成子进程显示顺序交叉,为了分辨输出来源,每个输出,会带上包名;指定了--parallel的命令,则会在scope指定的范围内,并行地执行相关地命令。

lerna run与上述命令不一样的情况在于,lerna run build将在每一个包中scripts字段中执行定义的build命令。

安装所有依赖

lerna bootstrap

上述命令安装所有的依赖、将所有的相关链接做好,同时在所有的包中运行npm run prepublish。随后,在所有包中运行npm run prepare。此时,所有的依赖均已完备。

发布

lerna publish  // 发布所有的包。

清理

lerna clean // 删除所有的node_modules

一些优化

合并公共依赖

我们在开发过程中,经常发现包依赖类似。这样,我们发现运行lerna bootstrap之后,会重复安装依赖包,这样会造成空间的浪费和效率的降低。为此,我们可以把同样的依赖包在根目录安装一次即可。此时,可以使用lerna bootstrap --hoist命令,则公用的依赖,只会在顶层目录安装一次。

发布带有scope公有包

带有scope的包,需要发布时候,如果是公有的包,需要在npm publish时候使用npm publish --access public。为了能够成功publish,并使用lerna流程,请在每个子包的lerna.json中加入:

"publishConfig": {
    "access": "public"
  }

检测循环依赖

lerna本身内置了检测循环依赖的功能,如果出现循环依赖。会在bootstrap时候给出提示:

image.png

此时,请依照提示去掉循环依赖,以保证软件包的正常运行。

配置lerna后目录结构

.
├── CHANGELOG.md
├── README.md
├── docs
├── lerna.json
├── package.json
├── packages
│   ├── package-1
│   ├── ── package.json
│   ├── package-2
│   ├── ── package.json
│   ├── package-3
│   ├── ── package.json
│   ├── package-4
│   ├── ── package.json
│   └── package-5
│   ├── ── package.json
├── tslint.json
└── website

运行脚本

"scripts": {
    "bootstrap:ci": "lerna bootstrap --npm-client=npm",
    "bootstrap:lerna": "lerna bootstrap -- --ignore-engines",
    "release:lerna": "lerna publish --exact --skip-temp-tag --registry http://127.0.0.1:4873",
     "release:beta": "lerna publish --exact --skip-temp-tag  --preid=beta --npm-tag=beta --registry http://127.0.0.1:4873"
}

上一篇下一篇

猜你喜欢

热点阅读