gnosis23 / hello-world-blog

还是 issues 里面写文章方便
https://bohao.work
0 stars 0 forks source link

翻翻 roadhog 源码 #29

Closed gnosis23 closed 4 years ago

gnosis23 commented 5 years ago

谈不上源码解读,仅仅说说学到的东西

1 Mock 接口

roadhog 依赖于 webpack-dev-server,然后 webpack-dev-server 底层使用了 express

1.1 添加路由规则

解析配置文件,逐条添加路由规则。

// .roadhogrc.mock.js
export default {
  // Support type as Object and Array
  'GET /api/users': { users: [1,2] },

  // Method like GET or POST can be omitted
  '/api/users/1': { id: 1 },

  // Support for custom functions, the API is the same as express@4
  'POST /api/users/create': (req, res) => { res.end('OK'); },
};

如上面这个文件,路由就会被转化为如下代码(略作简化):

  const config = getConfig();
  const mockRules = [];

  Object.keys(config).forEach(key => {
    const keyParsed = parseKey(key);

    mockRules.push({
      path: keyParsed.path,
      method: keyParsed.method,
      target: config[key],
    });
  });

  mockRules.forEach(mock => {
    app[mock.method](
      mock.path,
      createMockHandler(mock.method, mock.path, mock.target)
    )
  });

其他的也大致同理。

require.cache

这里有个细节, require 同一个文件会有缓存。可以操作 require.cache 来解决

function getConfig() {
  if (existsSync(configFile)) {
    // disable cache
    Object.keys(require.cache).forEach(file => {
      if (file === configFile) {
        debug(`delete cache ${file}`);
        delete require.cache[file];
      }
    });
    return require(configFile);
  } else {
    return {};
  }
}

1.2 重新刷新路由

文件监控,一旦发生变化就重新加载路由,这里涉及到动态修改 express 的路由。 可以用 app._router.stack 来操作路由对象

  const watcher = chokidar.watch(configFile, {
    ignored: /node_modules/,
    persistent: true
  });
  watcher.on('change', path => {
    console.log(chalk.green('CHANGED'), path);
    watcher.close();

    app._router.stack.splice(lastIndex + 1, mockRules.length + 2);

    applyMock(app);
  });

2 babel/register

让 Node 代码支持 ES6 语法。

const files = [
  'app.js',
  'mock.js',
  'route.config.js'
];

require('@babel/register')({
  only: [new RegExp(files.join('|'))],
  ignore: [/node_modules/]
});
require('./app.js');

另外 .babelrc 需要配好