背景
最近有这么一个项目,这个项目需要依赖多个npm包,这些npm包有部分依赖是相同的(或者包与包之间有相互联系),如下:
![ef7fbb2976742a1404ba585e770a026a.png](https://i-blog.csdnimg.cn/blog_migrate/6a36030174f784f56be676f32971c9e3.jpeg)
图1
如图1所示,这里有两个npm包:npm1和npm2,它们有公共的依赖base2。这种情况下我们该如何管理本地代码呢?
如果npm1和npm2本地代码分别存入一个单独的仓库,那么base2就需要copy一份,并且更新时两侧都要保持同步,另外如果还有更多的包,更多的公共依赖,那代码的维护就更加麻烦了!
为了解决这个问题,我们引入一个包管理工具——lerna。
使用介绍
1、全局安装lerna
npm install lerna -g
安装完成后,我们看一下控制台有没有这个命令:
![2aa793502aa74de1510096366b2797e9.png](https://i-blog.csdnimg.cn/blog_migrate/9733877e54f51455882d2c4c7182213e.jpeg)
图2
图2显示版本为3.16.4,说明我们已经安装成功了。
2、初始化我们的项目仓库,先创建一个lerna-repo目录,然后进入此目录运行下面的命令
lerna init //先采用默认模式,生成图3目录结构
![e70e0c03200c7ab5b125f6103f380ce9.png](https://i-blog.csdnimg.cn/blog_migrate/34394af34c195f3eaf4c4356f33be6b6.jpeg)
图3
很明显lerna.json是lerna的配置文件(你会发现很多工具都有本地的配置文件以便用户可以根据自己的业务自定义能力),打开这个json文件,如下图:
![cb5f997fcf77acdce21a60033aad8ead.png](https://i-blog.csdnimg.cn/blog_migrate/b8578a3947bc19882a4e59088608a8b2.jpeg)
图4
我们先关注这个packages属性,它是一个数组,每个元素代表可以发布的npm包的目录,比如图4中代表packages目录(初始化生成的)下所有的文件夹都是可以发版的npm包,另外也可以自定义npm包的目录,如下:
![b622380434758867ad9309b707fd8feb.png](https://i-blog.csdnimg.cn/blog_migrate/09c2ca090c87f5a208bf6f9591038d4c.jpeg)
图5
图5中我们自定义了一个目录——packages/plugins下所有的文件夹都是可以发版的npm包。
我们再看一眼图3,一般lerna-repo目录下可以存放各种依赖lib和入口entry,通过构建工具script tool将这些代码打包进packages目录中
3、生成一个npm包
lerna create [目录]
![74e15e56e178b74783cd4235b0d05796.png](https://i-blog.csdnimg.cn/blog_migrate/761a0e90293c4fffca54a06c7f20f1b3.jpeg)
图6
图6中,我们在packages/plugins目录下生成一个名为npm1的包,生成后的目录结构如下:
![46610d4bdff293a9783bafcbe4ac1eae.png](https://i-blog.csdnimg.cn/blog_migrate/f559c6387f79aba383ed27a02001b803.jpeg)
图7
4、为包添加依赖
lerna add 包名 [--scope=特定的某个包] [--dev]
功能类似于npm install 包名,scope指定为某个包添加依赖,如果没有scope选项,就会为packages下所有的包添加这个依赖;dev选项代表依赖添加进devDependencies中。
5、查看整个工程目录下有哪些包
lerna list [-l]
![8272d82f67039f22178caa0324f80984.png](https://i-blog.csdnimg.cn/blog_migrate/0e4ac18ca749949b56a2e4dc7b0a6075.jpeg)
图8
个人比较喜欢加一个-l先选项,信息会更加全面一些。
6、为每个包安装依赖
lerna bootstrap [--scope=特定的某个包]
功能和npm install差不多,如果不加scope,lerna会把工程下的所有包的依赖都安装好!
7、删除包下面的node_modules
上面的命令安装依赖会在每个包目录下生成node_modules,下面的命令就是将node_modules删除
lerna clean
8、导入外部的包(这个命令比较有意思)
lerna import 外部包的位置 --dest=工程下的位置
![31adcd94ca80b694b7999b89c2a17db3.png](https://i-blog.csdnimg.cn/blog_migrate/21b66e9dfe357b787a3ab2a98e6554e0.jpeg)
图9
图9中,koa是一个开源的包,我们用git下载到本地,然后用上面的命令导入到packages/plugins目录下,不仅代码会被导入,连git的操作历史也会被一起导入,所以它的应用场景也就非常的明确,就是为了将已经存在的npm包代码库迁移到 lerna 仓库中。
9、运行包的script命令
lerna run 命令 [--scope=特定的某个包]
和npm run [命令] 没什么区别,如果没有scope选项,lerna会运行每个包的script命令,如下:
![e59e55ee11b747d810a42c8c0f0bd901.png](https://i-blog.csdnimg.cn/blog_migrate/48c14cd2f26105af5b0f7def820a361a.jpeg)
图10
图10中运行了两个包下的test命令。
10、查看diff
lerna diff
和git diff 基本没区别,会显示工程下所有的修改
11、查看可以发布的包
lerna changed
![a023ad39c938f906932b09377aafbf09.png](https://i-blog.csdnimg.cn/blog_migrate/1b9b38fb2df2d7bf92a37e3d7414c3b5.jpeg)
图11
图11中显示有两个包可以发布,当你发布完成后再运行这个命令,红色区域就会显示No changed packages found。
12、发布
lerna publish [--dist-tag=tag名]
![8b168014914ea8ada101de525712fa9c.png](https://i-blog.csdnimg.cn/blog_migrate/182fae2394b338e37bea6c4711bdb8df.jpeg)
图12
如图12所示,控制台会让用户选择要发版的版本号(最后一个可以自定义)
dist-tag选项可以发版一个其他分支的包,在测试时比较有用!
![d80c7a9b971b5f5345582f17cca5eed1.png](https://i-blog.csdnimg.cn/blog_migrate/e22e59381624bb7a6280dea53463723a.jpeg)
图13
测试时可以发布一个beta版(--dist-tag=beta),通过手动@版本号安装(npm install 默认安装latest)!
13、模式
lerna init初始化默认使用的是fixed模式,回看图4中有个version选项,lerna在它的配置文件中记录了当前工程下所有包中最大的版本号,每个包发版时都是在这个版本号的基础上增加,发布完成,这个version也会更新到最大版本号!
比如 npm1 版本号是 0.0.1,npm2 版本号是 0.0.3,lerna配置文件的version是0.0.3,你现在修改npm1,准备发布新包,你认为新包的版本号可能是0.0.2?错!此模式下,lerna会以配置文件的version向上递增:
- 如果增加patch,npm1发包后版本号是0.0.4,npm2的版本号不变;
- 如果增加major或者minor,packages下的所有包都会统一增加,npm1和npm2都会统一变成0.1.0或者1.0.0;
babel和vue就是采用这种模式的。
另一种模式是independent
lerna init --independent
这种模式下lerna就不会帮忙记录版本号了,各包按照自己的规则递增。
总结
此篇文章主要介绍了lerna如何使用,有时看文档比较晦涩不容易懂,希望这篇文章能让读者更清楚的认识lerna!篇幅有限,还有很多的命令和配置没有讲到,在使用时如果有疑问可以在命令后面加一个--help选项,就会有使用介绍!
喜欢我的文章就关注我吧,后续会更多干货输出,让我们一起学习,共同成长!