`

egg-bin dev机制

 
阅读更多

1.项目文件package.json中添加script:{start:"egg-bin dev"}语句,执行npm start命令将调用egg-bin包的启动命令。

 

2.egg-bin包下bin文件夹添加egg-bin.js文件,同时package.json中添加bin:{"egg-bin":"bin/egg-bin.js"}语句,可使命令行执行脚本时无需使用node file形式。

#!/usr/bin/env node

'use strict';

const run = require('common-bin').run;

run(require('../lib/program'));

 

3."lib/program.js"模块,通过common-bin机制实现为单个Program,待执行的程序,可用于添加命令。common-bin将解析命令行参数,获取正在执行的命令名,并调用相应的脚本文件,如dev命令将调用"lib/dev_command.js"脚本并执行。

'use strict';

const path = require('path');
const BaseProgram = require('common-bin').Program;

// 注册版本号和子命令,如egg-bin dev执行dev_command.js脚本文件
// __dirname执行中的当前文件路径
class Program extends BaseProgram {
  constructor() {
    super();
    this.version = require('../package.json').version;
    this.addCommand('dev', path.join(__dirname, 'dev_command.js'));
    this.addCommand('debug', path.join(__dirname, 'debug_command.js'));
    this.addCommand('test', path.join(__dirname, 'test_command.js'));
    if (process.platform === 'win32') {
      this.addCommand('cov', path.join(__dirname, 'test_command.js'));
    } else {
      this.addCommand('cov', path.join(__dirname, 'cov_command.js'));
    }
  }
}

module.exports = Program;

 

4."lib/dev_command.js"模块,作为命令行键入dev时待执行的脚本文件,基于“egg-bin”包下的"lib/command.js"模块实现。dev_command模块的主要意义是向待执行的start-cluster模块注入配置项。start-cluster模块调用egg框架或其他基于egg实现的node框架的startCluster方法,以启动服务。

'use strict';

const debug = require('debug')('egg-bin:dev');
const Command = require('./command');

class DevCommand extends Command {
  // 参数cwd为当前用户脚本所在目录,将作为start-cluster模块启动时的baseDir参数传入egg或其他基于egg实现的框架中
  // args为命令行键入的剩余参数
  * run(cwd, args) {
    // 命令行参数只允许"--debug"或"--inspect"
    const execArgv = args ? args.filter(str => str.indexOf('--debug') === 0 || str.indexOf('--inspect') === 0) : [];

    // 获取egg模块路径
    const eggPath = this.getFrameworkOrEggPath(cwd);

    // 获取start-cluster模块执行时携带的参数
    args = yield this.helper.formatArgs(cwd, args, { eggPath });

    // 环境变量
    const options = {
      env: Object.assign({}, process.env),
      execArgv,
    };

    options.env.NODE_ENV = options.env.NODE_ENV || 'development';

    debug('%s %j %j, %j', this.helper.serverBin, args, execArgv, options.env.NODE_ENV);

    yield this.helper.checkDeps();

    // this.helper.serverBin即start-cluster模块的文件路径
    // this.helper.forkNode(filepath)调用执行路径为filepath的文件,由commin-bin包提供该功能
    yield this.helper.forkNode(this.helper.serverBin, args, options);
  }

  help() {
    return 'local env start';
  }

  // 获取egg模块路径
  getFrameworkOrEggPath(cwd) {
    return this.utils.getFrameworkOrEggPath(cwd);
  }
}

module.exports = DevCommand;

 

4.1 command.js模块,基于commin-bin的同名模块,构建egg-bin自有command类的基类,最主要的不同时改造helper属性和添加utils属性。

'use strict';

const utils = require('egg-utils');
const BaseCommand = require('common-bin').Command;
const helper = require('./helper');

// 创建Command命令的基类,在require('common-bin').Command的基础上修改helper、utils属性
class Command extends BaseCommand {
  constructor() {
    super();
    this.helper = Object.assign({}, this.helper, helper);
  }

  run(/* cwd, args */) {
    throw new Error('Must impl this method');
  }

  help() {
    throw new Error('Must impl this method');
  }

  get utils() {
    return utils;
  }
}

module.exports = Command;

 

4.2 helper.js为command类注入工具方法,dev命令所用的是formatArgs方法为startCluster指令注入参数,同时helper.serverBin指向egg-bin包下用于启动服务的start-cluster模块。

'use strict';

const fs = require('fs');
const path = require('path');
const glob = require('glob');
const detect = require('detect-port');
const debug = require('debug')('egg-bin');

// 默认端口
exports.defaultPort = 7001;

// "egg-bin"的"start-cluster"模块的所在目录
exports.serverBin = path.join(__dirname, 'start-cluster');

exports.getTestFiles = () => {
  const files = process.env.TESTS || 'test/**/*.test.js';
  const base = process.cwd();
  return glob.sync(files, {
    cwd: base,
  }).map(file => {
    return path.join(base, file);
  });
};

exports.getTestSetupFile = () => {
  const setupFile = path.join(process.cwd(), 'test/.setup.js');
  if (fs.existsSync(setupFile)) {
    return setupFile;
  }
  return null;
};

exports.formatTestArgs = args => {
  const newArgs = [
    '--timeout', process.env.TEST_TIMEOUT || '30000',
    '--require', require.resolve('thunk-mocha'),
  ];
  if (process.env.TEST_REPORTER) {
    newArgs.push('--reporter');
    newArgs.push(process.env.TEST_REPORTER);
  }

  if (args.indexOf('intelli-espower-loader') !== -1) {
    console.warn('[egg-bin] don\'t need to manually require `intelli-espower-loader` anymore');
  } else {
    // should be require before args
    newArgs.push('--require');
    newArgs.push(require.resolve('intelli-espower-loader'));
  }

  // auto add setup file as the first test file
  const setupFile = exports.getTestSetupFile();
  if (setupFile) {
    newArgs.push(setupFile);
  }

  return newArgs.concat(exports.getTestFiles()).concat(args);
};

// TODO: add egg-dependencies
// const checkDeps = require('egg-dependencies');
exports.checkDeps = function* () {
  return true;
};

// 获取start-cluster模块执行时携带的参数
exports.formatArgs = function* (cwd, args, options) {
  options = options || {};

  // start-cluster模块设定参数的解析形式,当前方法中传入参数baseDir为cwd,cluster为1,eggPath为options.eggPath
  args.push('--baseDir');
  args.push(cwd);
  args.push('--cluster');
  args.push('1');

  if (options.eggPath) {
    args.push(`--eggPath=${options.eggPath}`);
  }

  // auto detect available port
  if (args.indexOf('-p') === -1 && args.indexOf('--port') === -1) {
    debug('detect available port');

    // 通过co的机制将co内部的onFulfilled函数传入detect函数作为回调resolve,detect内部赋予其参数realPort,即端口
    // 生成器next方法执行时,常量port也即赋值为确切的端口
    const port = yield detect(exports.defaultPort);
    
    if (port !== exports.defaultPort) {
      args.push('-p', port);
      console.warn(`[egg-bin] server port ${exports.defaultPort} is in use, now using port ${port}\n`);
    }
    debug(`use available port ${port}`);
  }
  return args;
};

 

5.start-cluster执行egg或其他基于egg实现的框架的startCluster方法,以启动服务。

#!/usr/bin/env node

'use strict';

const debug = require('debug')('egg-bin:start-cluster');
const assert = require('assert');
const commander = require('commander');

// 使用commander模块解析进程的参数
commander
  .option('--eggPath [eggPath]')
  .option('--baseDir [baseDir]')
  .option('-p, --port [port]')
  .option('--cluster [workers]')
  .allowUnknownOption(true)
  .parse(process.argv);

// 用户的启动目录
const baseDir = commander.baseDir;
const workers = commander.cluster ? Number(commander.cluster) : 1;
// 端口
const port = commander.port;
// egg模块或其他基于egg实现的框架的路径
const customEgg = commander.eggPath;

assert(customEgg, 'eggPath required, missing any egg frameworks?');

const options = {
  baseDir,
  workers,
  port,
  customEgg,
};

debug('eggPath:%s options:%j', customEgg, options);

// 调用egg或其他基于egg实现的框架的startCluster方法,启动服务;options设置端口,用户代码所在目录等
require(customEgg).startCluster(options);

 

附注:

commander模块用于单纯解析命令行参数。

co模块将生成器函数的下一条next方法作为上一段执行代码返回值Promise的回调函数,同时生成器函数的next方法获得Promise成功时回调函数赋予的参数。

 

0
0
分享到:
评论

相关推荐

    egg-bin:鸡蛋开发工具

    安装$ npm i egg-bin --save-dev用法将egg-bin添加到package.json脚本中: { " scripts " : { " dev " : " egg-bin dev " , " debug " : " egg-bin debug " , " test-local " : " egg-bin test " , " test " : " npm...

    egg-ts-helper::cooking:生成Egg的TypeScript定义文件(d.ts)

    Egg-ts-helper 在应用程序中创建d.ts简单工具。 通过将controller, proxy, service, etc.注入到鸡蛋的定义类型(例如...$ egg-bin dev --dts 或在package.json添加配置egg.declarations 命令行界面 $ ets -h Usa

    egg-whistle:在鸡蛋中吹口哨

    蛋哨 在蛋上涂口哨。 什么是哨声 Whistle是基于Node.js的出色Web调试工具。 参见 安装 ...$ npx egg-bin dev 吹口哨 $ open http://127.0.0.1:7001/__whistle__ 应用程序启动后,egg中的http请求

    酒店管理系统(HotelManage)

    这个是我自己做的酒店管理系统,是用vs2005+oracle做的。里面有详细的使用说明以及建表、存储过程、视图的相关SQL语句!

    egg

    需要全局安装一个脚手架 (只需要全局安装一次) 安装完成之后,我们就可以全局使用 egg-init 命令,来初始化 egg 项目 初始化完成后,进入目录 ...安装 egg-bin 依赖,这个是命令行工具包,是开发依赖

    vuejs-admin-server:vuejs-admin项目服务端部分

    本地开发$ npm i$ npm run dev$ open http://localhost:7001/部署$ npm start$ npm stop单元测试[egg-bin]内置了[mocha],[thunk-mocha],[power-assert],[istanbul]等框架,让你可以专注于写单元测试,无需理会...

    liumingyi-blog-api

    [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。 断言库非常推荐使用 [power-assert]。 具体参见 。 内置指令 使用 npm run lint 来做...

    ctf-platform-nodejs:这是危险模式下CTFer的平台

    本地开发$ npm i$ npm run dev$ open http://localhost:7001/部署$ npm start$ npm stop单元测试[egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会...

    ckanext-geokurmeta:GeoKur CKAN的主题和元数据方案

    ckanext-geokurmeta 要求 与CKAN 2.9和Python 2.7一起使用。...sudo apt-get install python-dev libxml2-dev libxslt1-dev libgeos-c1v5 sudo apt-get install postgresql-11-postgis-2.5 sudo apt

    memcached 1.2.6 1.2.5

    The Good Egg SimpleIni SimpleOpt MemCacheClient Moji memcached show_menu2 menusys StringWrapper ML Fancy Excerpt LangSelect Visual Studio CommentsThis page contains a modified version of memcached (v...

    setuptools_0

    4、可爱的 Python: 使用 setuptools 孵化 Python egg:http://www.ibm.com/developerworks/cn/linux/l-cppeak3.html 5 5、Python中setuptools的简介:http://www.juziblog.com/?p=365001 6 6、ez_setup.py脚本:...

    codewarrior:代码搜索工具和静态分析-Beta

    egg / =外部模块,使用正则表达式搜索代码 conf / whitelist.conf =可以访问HTTPd服务器的IP列表 bin / =要执行的文件... doc / =正在建设中... lib / =外部库 cert / =在此处加载TLS的证书 您无需安装,编译和...

    appengine-buildout-template:将zc.buildout与Google App Engine项目一起使用的模板项目

    Google App Engine + zc.buildout模板 将zc.buildout与Google App Engine项目一起使用的...$ ./bin/dev_appserver 享受 通过以下食谱成为可能 zc.buildout zc.recipe.egg appfy.recipe.gae pbp.recipe.noserunner

Global site tag (gtag.js) - Google Analytics