lerna的使用简介

163 阅读5分钟

北京的野桃花也开了,又是一年春草绿。

技术日新月异,似乎一眨眼间一年、三年、五年抑或十年、二十年就这么过去了。

人在江湖,看人来人往,是否也有这样一个问题从你脑海掠过——远望前路,什么东西,或可抵岁月漫长?

是外力吗?肯定不是,至少外力不可持续依赖。

是激情吗?未必,火热的东西往往来得快去得也快。

是毅力吗?那么毅力又因何而来的呢?

真正催人奋进的,应该是一个接一个的所谓梦想吧。

——题记

一、初始化项目

首先执行如下命令:

mkdir test-lerna
cd test-lerna
lerna init

这时,我们得到初始目录结构如下,并发现在根目录下生成了lerna.json。

image.png

接着,我们在packages目录下新建两个文件夹: package1 和 package2,其中通过npm init各生成一个package.json文件,并把package.json中的name分别改为:'@dennis/package1' 和 '@dennis/package2'。文件内容如下。

package1/package.json:

{
  "name": "@dennis/package1",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}

package2/package.json:

{
  "name": "@dennis/package2",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT"
}

这时目录结构如下:

image.png

不过,其实创建package有可以直接使用的命令,比如执行lerna create @dennis/package3就可以在packages目录下创建一个package3,生成的package的目录如下所示:

image.png

二、给某一package添加依赖

执行:

lerna add typescript --scope=@dennis/package1 -D

添加后package1/package.json如下所示:

{
  "name": "@dennis/package1",
  "version": "0.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT",
  "devDependencies": {
    "typescript": "^4.2.3"
  }
}

我们发现,devDependencies中添加了typescript这一依赖项。并且,typescript依赖也被安装到了package1文件夹下的node_modules目录下。如下图所示:

image.png

其中,

--scope 参数用于指定单独为某个package添加一个依赖;

-D 参数和npm install -D中的-D所表示的含义一样(-D也可改成--dev),即将该依赖添加到devDependencies中。如果不指定-D的话,这个依赖默认会被添加到dependencies中。

三、让packages下的package1依赖package2

如果想让packages下的package1依赖package2,怎么实现呢?

注意,这个时候不需要将package2先发布到NPM。

首先,先执行:

lerna add @dennis/package2 --scope=@dennis/package1@^0.1.0

这样会把@dennis/package2加入到package1的denpendencies中。另外,我们会发现执行该命令后package1/node_modules目录下已经“安装”上了@dennis/package2这个依赖。如下图所示:

image.png

其中,@^0.1.0用于指定@dennis/package1的版本号。

当指定的版本号与@dennis/package2的package.json中真实的版本号不相匹配时,会出现如下错误提示:

image.png

接下来,我们来给package1和package2写点代码,测试下依赖是否能正常使用。

package2/index.js:

module.exports = {
  log: function(str) {
    console.log(str);
  }
}

package1/index.js:

const { log } = require('@dennis/package2');

log('Hello, world!');

然后再切换到test-lerna/packages/package1目录下执行node index.js,可在控制台看到输出了

Hello, world!

这表明依赖是可以正常工作的。

接下来,我们来测试下如果package2/index.js进行了修改会怎么样。

我们把package2/index.js的内容改成如下(即在原有的基础上添加的sayHi方法):

module.exports = {
  log: function(str) {
    console.log(str);
  },
  sayHi: function() {
    console.log('Hi!');
  }
}

同时把package1/index.js的内容改成如下:

const { log, sayHi } = require('@dennis/package2');

log('Hello, world!');
sayHi();

然后再切换到test-lerna/packages/package1目录下再次执行node index.js,可在控制台看到输出了

Hello, world!
Hi!

表明package2的更新会自动作用过来,并不需要做什么类似对package2进行再次添加依赖之类的工作。

四、给所有package添加同一依赖

如果想给packages目录下的所有pakcage都添加同一依赖(比如underscore)应该怎么做呢?可以执行如下命令:

lerna add underscore

这样就会给packages目录下的所有pakcage都添加上underscore这一依赖。相比于上面讲过的给某一package添加依赖,区别就是没有指定--scope选项。

但这样处理有个问题,那就是会在每个package下的node_modules中安装一份underscore模块。package和package之间并不是共用的。怎么做到共用呢?

首先我们执行lerna clean将packages目录下所有的packages下每个package下面的node_modules全部清除,并通过手工方式将package-lock.json都删除,同时将package.json的dependencies中的underscore依赖项删除。

然后我们test-lerna目录下的package.json修改成:

{
  "name": "root",
  "private": true,
  "devDependencies": {
    "lerna": "^3.22.1"
  },
  "workspaces": [
    "packages/*"
  ]
}

同时把test-lerna目录下的lerna.json修改成:

{
  "version": "0.0.0",
  "npmClient": "yarn",
  "useWorkspaces": true
}

然后再次执行lerna add underscore就会发现,如下图所示underscore被安装到了下test-lerna/node_modules目录中,实现了多个package中共用这一份:

image.png

五、执行某个package下的命令

使用:

lerna run serve --scope=@dennis/package1

效果相当于:

cd packages/package1
npm run serve

六、lerna的一些其它常用命令

lerna bootstrap:等同于 lerna link + yarn install,用于创建符合链接并安装依赖包;

lerna run:会像执行一个 for 循环一样,在所有子项目中执行 npm script 脚本,并且,它会非常智能的识别依赖关系,并从根依赖开始执行命令;

lerna exec:像 lerna run 一样,会按照依赖顺序执行命令,不同的是,它可以执行任何命令,例如 shell 脚本;

lerna publish:发布代码有变动的 package,因此首先您需要在使用 Lerna 前使用 git commit 命令提交代码,好让 Lerna 有一个 baseline;

Lerna 还提供了一些参数满足我们更灵活的需求,例如:

--concurrency :参数可以使 lerna 利用计算机上的多个核心,并发运行,从而提升构建速度。