lerna工作流程

1 minute read

lerna 的体验

为什么使用 lerna

lerna 是基于git+npm的多package项目管理工具 工程化思想的两个维度:1、大幅减少重复操作 2、提升操作的标准化。以效能为核心。

实现原理

1、通过import-local预先调用本地lerna命令 2、通过yargs生成脚手架,先注册全局属性,在注册命令,最后通过parse方法解析参数 3、lerna命令注册时需要传入builder和handler两个方法,builder方法用户注册命令专属的options,handler用来处理命令的业务逻辑 5、lerna通过配置npm本地依赖的方法来进行本地开发,具体写法是在package.json的依赖中写入:file:your-local-module-path,在lerna publish时会自动将该路径替换

脚手架项目初始化

1、 初始化npm项目

mkdir fe-cli && cd fe-cli
npm init -y

2、 安装lenrna

yarn add lerna -D

3、 lerna init 初始化项目 将会在该文件夹下生成 packages文件夹、lerna.json

lerna init

创建 package

1、lerna create 创建 package

lerna create core

会在packages下创建名为core的npm包 2、lerna add 安装依赖

lerna add react 将会把 react 安装进 packages 下所有的包中
lerna add react packages/core 将会把 react 安装进指定的 packages/包中
https://github.com/lerna/lerna/tree/main/commands/add#readme

3、lerna link 链接依赖 完成内部文件的相互依赖,会为你生成软链

lrwxr-xr-x  1 liuyan  staff    14B  7  6 16:09 utils -> ../../../utils

脚手架开发和测试

1、lerna exec 执行 shell 脚本

可以为你批量执行shell脚本(也可以指定scope) lerna exec – rm -rf node_modules/ 2、lerna run 执行 npm 命令 lerna run test 批量执行packages中的test命令

3、lerna clean 清空依赖 清除 packages 下所有的 node_modules

4、lerna bootstrap 重装依赖 将原本 package.json 中记录的依赖重新安装

脚手架的发布上线

1、lerna version

2、lerna changed 查看哪些包有了改动

3、lerna diff commit之间的diff对比

4、lerna publish

lerna 源码学习

1、入口文件

#!/usr/bin/env node

"use strict";

/* eslint-disable import/no-dynamic-require, global-require */
const importLocal = require("import-local");

if (importLocal(__filename)) {
  require("npmlog").info("cli", "using local version of lerna");
} else {
  require(".")(process.argv.slice(2));
  // require(".") 中的 . 等价于 ./ 又等价与 ./index.js
}

2、进入 require(“.”) 对应的index.js

"use strict";
// 代码的运行是一行一行往下的,会一条一条解析require文件
const cli = require("@lerna/cli");

const addCmd = require("@lerna/add/command");
const publishCmd = require("@lerna/publish/command");
const versionCmd = require("@lerna/version/command");

const pkg = require("./package.json");

module.exports = main;

function main(argv) {
  const context = {
    lernaVersion: pkg.version,
  };

// 可以看出这是使用设计模式:构造者。对一个对象不断调用自身方法,并且在返回自身,不断壮大自己。
  return cli()
    .command(addCmd)
    .command(publishCmd)
    .command(versionCmd)
    .parse(argv, context);
}

3、若是在packages内部的包相互使用,更轻松的安装方式

//在某个包中使用另一个分包
 "dependencies": {
    "@lerna/command": "file:../../core/command"
 }

但是你想想,file多对应的文件是怎么发布上线的? 看到 publish 命令中的代码

 resolveLocalDependencyLinks() {
    // resolve relative file: links to their actual version range
    const updatesWithLocalLinks = this.updates.filter((node) =>
      Array.from(node.localDependencies.values()).some((resolved) => resolved.type === "directory")
    );

    return pMap(updatesWithLocalLinks, (node) => {
      for (const [depName, resolved] of node.localDependencies) {
        // regardless of where the version comes from, we can't publish "file:../sibling-pkg" specs
        const depVersion = this.updatesVersions.get(depName) || this.packageGraph.get(depName).pkg.version;

        // it no longer matters if we mutate the shared Package instance
        node.pkg.updateLocalDependency(resolved, depVersion, this.savePrefix);
      }

      // writing changes to disk handled in serializeChanges()
    });
  }

SuiBu

SuiBu

Engineer

Comments

  Write a comment ...