最近在写一个eslint config的整合包,因为有不同语言,会发多个 npm 包,通过 Lerna 来管理多包发布,它优化了使用 git 和 npm 管理多包存储库的工作流,Vue、Babel、React 都有使用 Lerna。这里记录下使用过程中的一些点。
¶一、两种工作模式
¶1.1、固定模式
  Fixed/Locked mode,Vue,Babel 都是用这种,在 publish 的时候,会依据lerna.json文件里面的"version": "0.0.1"进行增加,只选择一次,其他有改动的包自动更新版本号。
¶1.2、独立模式
  Independent mode,执行lerna init --independent命令初始化项目,lerna.json文件里面会设置"version": "independent"。每次 publish 时,会得到一个提示符,提示每个已更改的包,以指定是补丁、次要更改、主要更改还是自定义更改(x.y.z)。
¶二、初始化
  新建一个文件夹eslint-config-liuxy0551,并进入该文件夹;为了方便 github action,安装 lerna 到开发环境:
1  | npm init -y  | 
因为 lerna 经常需要用到,我们全局安装下:
1  | yarn global add lerna  | 
  安装完成后输入lerna -v查看版本号:

1  | lerna init  | 
  我们使用固定模式,然后进入packages文件夹初始化几个不同语言对应的 eslint config 包:
1  | cd packages  | 
项目结构如下:
1  | eslint-config-liuxy0551  | 
  按照约定 Shareable Configs,包名应该以eslint-config-开头,例如:eslint-config-liuxy0551-basic。依次将 packages 下的几个 package.json 中的 name 改成如:@liuxy0551/eslint-config-liuxy0551-basic,version 改成 0.0.0。
每个子 package 都有自己的 node_modules,通过如下设置,就可以只在根目录创建 node_modules,只有开启了 private 的项目才能使用 workspaces。依次修改根目录的 package.json 和 lerna.json,添加以下配置项:
1  | "private": true,  | 
1  | "useWorkspaces": true,  | 
¶三、绑定 git 和 npm
接下来与远程仓库绑定,并登录 npm:
1  | git remote add origin git@github.com:liuxy0551/eslint-config-liuxy0551.git  | 
1  | npm whoami  | 
注意
如果上述命令报错,排查 npm 源:npm config ls
设置 npm 官方源:npm config set registry https://registry.npmjs.org/
如果未登录则执行npm login登录
¶四、配置内容
在 packages/basic 文件夹下新建 index.js,内容如下:
1  | module.exports = {  | 
  rules对象就是我们可以自己改动的配置项,在Airbnb/JavaScript仓库中的 https://github.com/airbnb/javascript/issues/1089,告诉了我们有哪些规则可以被修改。
¶五、lerna 命令
¶5.1、创建一个包
lerna create <包名> [存放的目录]
1  | lerna create packageName  | 
¶5.2、查看当前列表
1  | lerna list  | 

¶5.3、增加本地或者远程 package 作为当前项目 packages 里面的依赖
lerna add [@version] [--scope=localPackageName] [-D] [--exact]
- -D 表示安装到 devDependencies
 - –exact 表示安装准确版本,不带 ^
 
注意
以下基于node 12版本安装插件,需要兼容低版本的可以在插件后加上版本号
1  | lerna add eslint  | 
1  | lerna add --scope=@liuxy0551/eslint-config-liuxy0551-basic eslint-loader  | 
  加上--scope=表示给本地指定的包安装依赖,也可以 cd 到这个包的文件夹下安装,就不用加--scope=了;不加则是给所有子包都安装该依赖。
1  | lerna add --scope=@liuxy0551/eslint-config-liuxy0551-typescript @liuxy0551/eslint-config-liuxy0551-basic  | 
1  | lerna add --scope=@liuxy0551/eslint-config-liuxy0551-react @liuxy0551/eslint-config-liuxy0551-typescript  | 
1  | lerna add --scope=@liuxy0551/eslint-config-liuxy0551-prettier @liuxy0551/eslint-config-liuxy0551-react  | 
¶5.4、安装依赖
  因为我们指定过使用 yarn,直接执行yarn install就会把所有包的依赖安装到根目录的 node_modules。
1  | lerna bootstrap  | 
¶5.5、删除依赖
1  | lerna clean --scope=特定的某个包  | 
  和rm -rf node_modules功能一致,--scope=表示指定包,不会移除根目录的 node_modules。
¶5.6、建立软链接
lerna link [--force-local]
1  | lerna link --force-local  | 
  类似npm link的使用,–force-local 表示不论本地的版本是否符合,都使用本地的版本。
¶5.7、列出更新的包
1  | lerna changed  | 
列出改动过的包,发布时只更新改动过的包。

¶5.8、指定版本号
1  | lerna version 0.0.2 -y  | 
需要本地分支和远程分支无差别。
¶5.9、发布
lerna publish [--conventional-commits -y]
1  | lerna publish  | 
  需要先执行 git commit,会打 tag,--conventional-commits表示生成 changelog。如果包名是带 scope 的格式,如:@liuxy0551/eslint-config-liuxy0551,则需要在 package.json 中添加配置项,packages 下的每个包都需要加:
1  | "publishConfig": {  | 


¶六、发布整合包
lerna publish 只会发布 packages 下的包,当前文件夹并不会作为一个包发布
  在 packages 文件夹下新建一个main,作为入口:
1  | cd packages  | 
将 main 下 package.json 中的 name 改成如:@liuxy0551/eslint-config-liuxy0551,version 改成 0.0.0。添加依赖:
1  | lerna add --scope=@liuxy0551/eslint-config-liuxy0551 eslint@^7.0.0  | 
在 packages/main 文件夹下新建 index.js,内容如下:
1  | /** Export all */  | 
  lerna 不会发布标记私有的项目,需要修改根目录 package.json 中的配置"private": false
1  | npm whoami  | 
1  | lerna publish  | 
访问https://www.npmjs.com/search?q=@liuxy0551/eslint-config-liuxy0551 可以看到发布的包。
常见错误
第一次发布失败后出现 Current HEAD is already released
执行lerna publish from-package
  可选步骤删除测试发布的 npm 包:
1  | npm unpublish @liuxy0551/eslint-config-liuxy0551-react --force  |