lerna.js管理大型项目

一、前言

最近准备开发前端的一个模块化的库,业务级别,要求可以任意插拔随意组合。大型工程,需要多人维护。
以前的项目都是业务级,单个包项目。简单,便于管理。但是,当一个大的项目库代码量剧增之后,管理起来就是一件比较麻烦的事情,为了方便代码的共享,就需要将代码库拆分成独立的包。
调研了一下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即可。

常用命令

  1. 启动
    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
  1. 添加依赖
lerna add  [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

super-page-component 添加 依赖 vue-class-component,scope后要跟package.json里面的名字,而不是文件夹名。如果全部安装,去掉scope即可。

lerna add vue-class-component --scope=@mfelibs/superpage-component  

  1. 发布
    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上。

  1. 指定源
    如果你的项目并不是用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]/
...

而此时很可能希望能在 [project root]/package/pkg1/ 目录下寻找配置。

所以此时其实很希望 webpack loader 基于 symlink 的路径去解析判断 include / exclude 等配置,而不是按照真实文件的路径。

所以需要配置webpack 的 resolve.symlinks 来解决这个问题,具体参见官方文档。

2. 指定cnpm源无效

据gitlab issue publish时不接受参数,只能使用npm仓库。
但是旧版本 2.x 的支持,本人测试,截止到3.3.2,3.x的lerna指定cnpm源publish均无效。

参考链接:

用Lerna管理多包JS项目
primer
当 webpack 遇上 symlink

作者:NowhereToRun
链接:https://www.jianshu.com/p/2f9c05b119c9
来源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(lerna.js管理大型项目)