使用lerna管理大型前端项目
Others 2022-05-12 03:49:14 2022-05-12 03:49:14 1280 次浏览一、前言
最近准备开发前端的一个模块化的库,业务级别,要求可以任意插拔随意组合。大型工程,需要多人维护。
以前的项目都是业务级,单个包项目。简单,便于管理。但是,当一个大的项目库代码量剧增之后,管理起来就是一件比较麻烦的事情,为了方便代码的共享,就需要将代码库拆分成独立的包。
调研了一下lerna
库,适合我们的场景,babel即用这个工具进行管理。
二、lerna基础
初始化:
$ npm i -g lerna
$ mkdir lerna-repo && cd $_ $ lerna init
生成文件路径如下:
lerna-repo/ packages/ package.json
lerna.json
默认情况下,packages/下即保存多包地址。
管理模式
使用lerna管理项目时,可以选择两种模式。
默认的为固定模式(Fixed mode),当使用lerna init命令初始化项目时,就默认为固定模式,也可以使用 lerna init --independent 命令初始化项目,这个时候就为独立模式(Independent mode)。
固定模式中,packages下的所有包共用一个版本号(version),会自动将所有的包绑定到一个版本号上(该版本号也就是lerna.json中的version字段),所以任意一个包发生了更新,这个共用的版本号就会发生改变。
独立模式允许每一个包有一个独立的版本号,在使用lerna publish命令时,可以为每个包单独制定具体的操作,同时可以只更新某一个包的版本号。此种模式时,lerna.json中的version字段指定为independent
即可。
常用命令
-
启动
lerna bootstrap
切记使用这个指令代替 npm install。默认使用npm安装,如果需要使用yarn或者cnpm可参考4.
这个指令会执行以下操作:
- 在每个 package 下面执行 npm install 。
-
根据各个 package 下 package.json 里面的 dependencies 和 devDependencies 配置,使用
symlink
在各个 package 的 node_modules 下面建立引用关系。 -
在每个 package 下执行
npm run prepublish
。 -
在每个 package 下执行
npm run prepare
。
- 添加依赖
lerna add <pkg> [globs..] /*
Add a dependency to matched packages
位置:
pkg Package name to add as a dependency [字符串] [必需]
globs Optional package directory globs to match [数组] [默认值: []]
*/
例如目录结构为:
lerna-repo/ packages/ super-page-component/ package.json
index.ts
node_modules/ ... other-xxx-module/ package.json
lerna.json
</div>
<p>
给 <code>super-page-component</code> 添加 依赖 <code>vue-class-component</code>,scope后要跟package.json里面的名字,而不是文件夹名。如果全部安装,去掉scope即可。
</p>
<div class="_2Uzcx_">
<button class="VJbwyy" type="button" aria-label="复制代码"><i aria-label="icon: copy" class="anticon anticon-copy"><svg viewbox="64 64 896 896" focusable="false" class="" data-icon="copy" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M832 64H296c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h496v688c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8V96c0-17.7-14.3-32-32-32zM704 192H192c-17.7 0-32 14.3-32 32v530.7c0 8.5 3.4 16.6 9.4 22.6l173.3 173.3c2.2 2.2 4.7 4 7.4 5.5v1.9h4.2c3.5 1.3 7.2 2 11 2H704c17.7 0 32-14.3 32-32V224c0-17.7-14.3-32-32-32zM350 856.2L263.9 770H350v86.2zM664 888H414V746c0-22.1-17.9-40-40-40H232V264h432v624z"></path></svg></i></button>
lerna add vue-class-component --scope=@mfelibs/superpage-component
</div>
<ol start="3">
<li>
发布<br />
lerna publish
用于发布更新,默认发到npm上,如需修改可参考4。运行该命令会执行如下的步骤:
- 运行lerna updated来决定哪一个包需要被publish
- 如果有必要,将会更新lerna.json中的version
- 将所有更新过的的包中的package.json的version字段更新
- 将所有更新过的包中的依赖更新
- 为新版本创建一个git commit或tag
- 将包publish到npm上
同时,该命令也有许多的参数,例如--skip-git 将不会创建git commit或tag,--skip-npm将不会把包publish到npm上。
-
指定源
如果你的项目并不是用npm管理,像我们一样,可以在需要的操作上都指定源。
例如使用yarn管理包lerna bootstrap --npm-client=yarn
例如使用cnpm发布包lerna publish --npm-client=cnpm
(注意,3.x版本无效)
三、遇到的问题
1. symlink 的问题
看我们前面提到的lerna bootstrap
执行的操作第二步,使用 symlink 在各个 package 的 node_modules 下面建立引用关系。
如果我们的package中有webpack,那么其中的loader很有可能会出问题。
假设 package 下面有一个包 pkg1 ,依赖 package 下面的另一个包 pkg2 。
运行 lerna bootstrap 之后, pkg1/node_modules 下就会出现 pkg2 的 symlink 。
我们遇到的问题是在pkg2中有一个TS文件,export出去。pkg1中去引入,但是发现总是没有命中真实的loader。
如果使用 webpack 系列工具来编译运行 pkg1 ,由于 webpack loader 判断路径默认是按照真实路径来的,所以 pkg2 对应到的路径是 [project root]/package/pkg2
,而不是 [project root]/package/pkg1/node_modules/pkg2
。
这样一来,如果需要 pkg2 中的源码过 pkg1 的 loader (比如 pkg2 中的 TS 通过 pkg1 的 ts-loader),就需要特殊配置。这和不涉及 symlink 的真实场景存在较大差异。
同时,很多配置(比如 postcssrc 、 babelrc 、 eslintrc 等)是以 resolve 到的文件去解析的。
比如要用 babel 编译 pkg2 下面的 [project root]/package/pkg2/src/Report.ts 源码,会按照如下目录顺序查找 babelrc 配置:
[project root]/package/pkg2/src/ [project root]/package/pkg2/ [project root]/package/ [project root]/ ...
</div>
<p>
而此时很可能希望能在 [project root]/package/pkg1/ 目录下寻找配置。
</p>
<p>
所以此时其实很希望 webpack loader 基于 symlink 的路径去解析判断 include / exclude 等配置,而不是按照真实文件的路径。
</p>
<p>
所以需要配置webpack 的 <code>resolve.symlinks</code> 来解决这个问题,具体参见<a href="https://webpack.js.org/configuration/resolve/#resolve-symlinks" target="_blank" rel="nofollow">官方文档</a>。
</p>
<h4>
2. 指定cnpm源无效
</h4>
<p>
据<a href="https://github.com/lerna/lerna/issues/942" target="_blank" rel="nofollow">gitlab issue</a> publish时不接受参数,只能使用npm仓库。<br />
但是旧版本 2.x 的支持,本人测试,截止到3.3.2
,3.x的lerna指定cnpm源publish均无效。
Links: 556