【umi】umi dev 和build 的时候在做什么?

umi dev 和 build 规则, 什么样的东西会进入umi.js(携带相当一部分 esnext 的 polyfill 和框架本身的运行时)

当我们运行umi dev的时候, 一般会有个bin文件,

我们去packages/umi/package.json 看下这个,根据入口就能找到umi dev执行的全过程。umi中的command 都是依赖于api.registerCommand来实现的

bin入口文件umi.js

packages/umi/package.json, 根据文件入口会找到bin/umi.js

【umi】umi dev 和build 的时候在做什么?

packages/umi/bin/umi.js,

在这段代码中, 上面这代码如果是debugger模式的话,当输出日志、警告或错误信息时,同时输出这些方法的代码的堆栈信息,以便于调试和定位问题。 下面那代码没啥好说,直接require 编译后dist 文件夹下的 cli.js

【umi】umi dev 和build 的时候在做什么?

umi 是用father打包,所以运行father dev 或 father build的时候都会生成dist 目录

【umi】umi dev 和build 的时候在做什么?

cli入口文件,对各种命令进行不同的处理

packages/umi/src/cli/cli.ts

如果是dev命令,则运行dev()方法, 否则Serive对象的run2()方法, 然后去看下dev(), 当然我不是很清楚为什么只有dev才需要单独写方法处理, 看看dev()干了什么

【umi】umi dev 和build 的时候在做什么?

创建子进程并处子进程的终止信号

packages/umi/src/cli/dev.ts

// 这段代码是一个Node.js函数,用于创建一个子进程并处理子进程的终止信号。
export function dev() {
// 使用`fork`方法创建一个子进程,脚本路径是`../../bin/forkedDev`.
  const child = fork({
    scriptPath: require.resolve('../../bin/forkedDev'),
  });
  // ref:
  // http://nodejs.cn/api/process/signal_events.html
  // https://lisk.io/blog/development/why-we-stopped-using-npm-start-child-processes
 // 监听`process`对象的`SIGINT`和`SIGTERM`事件
  process.on('SIGINT', () => {
    child.kill('SIGINT');
    // ref:
    // https://github.com/umijs/umi/issues/6009
    process.exit(0);
  });
  process.on('SIGTERM', () => {
    child.kill('SIGTERM');
    process.exit(1);
  });
}
  • SIGINT, 代表着中断信号,通常是用户按下Ctrl+C发送的信号,结束当前进程,退出码是0
  • SIGTERM, 代表着终止信号, 结束当前进程,退出码是1

更多信号事件

代码里都是会结束子进程,然后结束当前进程,为什么其他命令不需要这么处理? 我们根据路径../../bin/forkedDev去看下一步骤

处理服务运行中各种终止信号

packages/umi/src/cli/forkedDev.ts

前面解析了命令行参数,创建Service实例调用run2()方法,这不和packages/umi/src/cli/cli.ts对上了,后面的也是监听了process对象的SIGINT(中断信号)、SIGQUIT(退出信号)和SIGTERM(终止信号)事件

(async () => {
  try {
    const args = yParser(process.argv.slice(2));
    const service = new Service();
    await service.run2({
      name: DEV_COMMAND,
      args,
    });

    let closed = false;
    // kill(2) Ctrl-C 中断信号
    process.once('SIGINT', () => onSignal('SIGINT'));
    // kill(3) Ctrl-\ 退出信号
    process.once('SIGQUIT', () => onSignal('SIGQUIT'));
    // kill(15) default 终止信号
    process.once('SIGTERM', () => onSignal('SIGTERM'));
    
    function onSignal(signal: string) {
      if (closed) return;
      closed = true;
      // 退出时触发插件中的 onExit 事件
      service.applyPlugins({
        key: 'onExit',
        args: {
          signal,
        },
      });
      process.exit(0);
    }
  } catch (e: any) {
  // 捕捉错误信息,记录日志
    logger.fatal(e);
    printHelp.exit();
    process.exit(1);
  }
})();

处理命令的大小写

packages/umi/src/service/service.ts

这里开始,只要运行umi xx 都会进入这里

  async run2(opts: { name: string; args?: any }) {
    let name = opts.name;
    if (opts?.args.version || name === 'v') {
      name = 'version';
    } else if (opts?.args.help || !name || name === 'h') {
      name = 'help';
    }

    // TODO
    // initWebpack

    return await this.run({ ...opts, name });
  }

run方法是插件的生命周期

packages/core/src/service/service.ts

之前也介绍过, umi的插件核心机制,也是umi的核心。详情见umi 生命周期

【umi】umi dev 和build 的时候在做什么?

【umi】umi dev 和build 的时候在做什么?

运行对应的command

packages/preset-umi/src/commands/dev/dev.ts

【umi】umi dev 和build 的时候在做什么?

【umi】umi dev 和build 的时候在做什么?

原文链接:https://juejin.cn/post/7311871555528114230 作者:南蓝

(0)
上一篇 2023年12月14日 上午11:08
下一篇 2023年12月14日 下午4:00

相关推荐

发表回复

登录后才能评论