远子 💖 Vina

读 eggjs

远子 •  2020年11月04日 • 评论

egg 是基于 Koa 封装的 Node 框架,我司大量使用了此框架。

我试着从初学者的角度探索 egg 的源码。

image.png

先来首BGM:

1. 初始化 egg 项目

快速初始化npm >=6.1.0):

# 创建一个文件夹
mkdir simple && cd simple

# 使用 npm 初始化一个 simple 类型的 egg 项目
npm init egg --type=simple

npm init 命令用于初始化 Node 项目,它的语法为 npm init <initializer>,initializer 是可选的:

  1. 如果留空,npm 会在当前目录创建 package.json
  2. 如果有值,npm 会使用指定的 initializer 创建项目。这里有个约定,以 create-* 名称开头的 npm 包就是一个合法的 initializer。

npm init egg 的意思是使用 create-egg 创建项目,等价于 npx create-egg

npx 用于从本机缓存或者从网络下载 npm 包并运行。

create-egg/package.json 中的 bin 字段表明了可执行文件为 create-egg/bin/create-egg.js

因此,npm init egg --type=simple 又等价于 create-egg/bin/create-egg.js --type=simple

create-egg/bin/create-egg.js 的代码如下:(只有一行代码:调用 egg-init/bin/egg-init.js)

#!/usr/bin/env node

'use strict';

require('egg-init/bin/egg-init');

egg-init 会解析 --type=simple 参数,type 用于指定模板,simple 指向到了 egg-boilerplate-simple,egg-init 会询问用户一些参数比如项目名称、Author、secret key,还有一些其他逻辑: 指定镜像地址、指定项目路径、替换模板参数之类的。

egg-init 大量使用了 function*yield 的语法实现异步转同步。

完整的调用链为:

  1. npm init egg --type=simple
  2. npx create-egg --type=simple
  3. create-egg/bin/create-egg.js --type=simple
  4. egg-init/bin/egg-init.js --type=simple
  5. egg-init 负责下载 egg-boilerplate-simple 到用户磁盘,至此,egg 项目就创建完成了。

2. 启动开发服务

命令:

cd simple
npm run dev

npm run dev 是 npm scripts 的别名,会执行 simple/package.jsonscripts.devegg-bin dev 命令。

查看 simple/node_module/.bin 目录,可以看到有一堆可执行文件:

调用链如下:

  1. npm run dev
  2. egg-bin dev
  3. 执行 egg-bin/lib/cmd/dev.js(此文件中定义了默认端口为 7001);

    • egg-bin/lib/cmd/dev.js 继承了 egg-bin/lib/command.js
    • egg-bin/lib/command.js 继承了 common-bin/lib/command.js
  4. 执行 common-bin/lib/command.jsstart 方法;
  5. 执行 egg-bin/lib/cmd/dev.jsrun 方法;
  6. 执行 common-bin/lib/helper.jsforkNode 方法,此方法会创建一个子进程启动开发服务。

3. 启动生产服务

命令:

cd simple
npm run start

开发服务用 egg-bin,生产服务用 egg-scrips,这两个包都 common-bin 子类。

npm run start 会执行 egg-scripts start --daemon --title=egg-server-sample--daemon 参数的意思是以守护模式启动,--title 是进程的名称。

守护模式时,child_process.spawn(command [,args] [,options])options.detachedtrue,可以使子进程在父进程退出后继续运行。

3.1 一些进程的知识

Node 中有 4 种方式创建子进程

  • spawn()spawnSync():启动一个子进程来执行命令;
  • fork():与 spawn() 类似,不同点在于它创建 Node 的子进程只需指定要执行的 JavaScript 文件模块即可;
  • exec()execSync():启动一个子进程来执行命令,与 spawn() 不同的是其接口不同,它有一个回调函数获知子进程的状况;
  • execFile()execFileSync():启动一个子进程来执行可执行文件;

*Sync 后缀的方法是同步版本,会阻塞 Node 事件循环。

spawn()exec()execFile() 不同的是,后两者创建时可以指定 timeout 属性设置超时时间,一旦创建的进程运行超过设定的时间将会被杀死。

exec()execFile() 不同的是,exec() 适合执行已有的命令,execFile() 适合执行文件。

用户代码的降级


我要发表看法

«-必填
«-必填,不公开