立诚勿怠,格物致知
It's all about connecting the dots

lin-cms-koa源码阅读之:入口和启动

git仓库地址:https://github.com/TaleLin/lin-cms-koa

一、从入口文件开始

查看package.json,可知入口文件为项目根目录下的index.js文件:

require('@babel/register');

require('./app/starter');

言简意赅,两行代码。第一行引用了@babel/register这个node包,查阅其官网(https://babeljs.io/docs/en/babel-register)可知这个库会修改node提供的require方法,当node程序去require对应后缀名(.es6、.es、.jsx、.mjs和.js)的文件(默认情况下不会去编译node_modules目录里文件)时,这个库会先把库给编译掉再提供给node使用(见下图,往exports对象上绑定了register函数,在register函数里通过hookExtensions函数对指定拓展名的文件添加自定义的compileHook,其中添加hook的addHook方法是从pirates包中导入的)。

 

compileHook的内容很简单,就是判断当前没有在编译的话就把代码编译一下:

let compiling = false;

function compileHook(code, filename) {
  if (compiling) return code;

  try {
    compiling = true;
    return compile(code, filename);
  } finally {
    compiling = false;
  }
}

现在我们看下核心的compile函数:

function compile(code, filename) {
  // merge in base options and resolve all the plugins and presets relative to this file
  const opts = new OptionManager().init(
    // sourceRoot can be overwritten
    {
      sourceRoot: path.dirname(filename) + path.sep,
      ...deepClone(transformOpts),
      filename,
    },
  );

  // Bail out ASAP if the file has been ignored.
  if (opts === null) return code;

  let cacheKey = `${JSON.stringify(opts)}:${babel.version}`;

  const env = babel.getEnv(false);

  if (env) cacheKey += `:${env}`;

  let cached = cache && cache[cacheKey];

  if (!cached || cached.mtime !== mtime(filename)) {
    cached = babel.transform(code, {
      ...opts,
      sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
      ast: false,
    });

    if (cache) {
      cache[cacheKey] = cached;
      cached.mtime = mtime(filename);
    }
  }

  if (cached.map) {
    if (Object.keys(maps).length === 0) {
      installSourceMapSupport();
    }
    maps[filename] = cached.map;
  }

  return cached.code;
}

这里的主要逻辑是判断是否有缓存了的编译结果,如果有的话就直接使用之前缓存的编译结果没必要重新编译了,如果没有对应的缓存则通过babel.transform方法对源码进行编译处理。所以,项目中其他源码文件里我们就可以使用import/export关键字替代require来进行模块的导入导出了。

二、应用的启动app/starter.js、app/app.js

作用:加载一堆配置文件,然后启动web应用(添加数据解析、跨域支持、静态服务、日志打印等)。代码如下:

'use strict';
const fs = require('fs');
const path = require('path');

const { config } = require('lin-mizar/lin/config');

/**
 * 获取配置
 */
function applyConfig () {
  const cwd = process.cwd();
  const files = fs.readdirSync(path.resolve(`${cwd}/app/config`));
  for (const file of files) {
    config.getConfigFromFile(`app/config/${file}`);
  }
  // 加载其它配置文件
  config.getConfigFromFile('app/extensions/file/config.js');
}

const run = async () => {
  applyConfig();
  const { createApp } = require('./app');
  const app = await createApp();
  const port = config.getItem('port');
  app.listen(port, () => {
    console.log(`listening at http://localhost:${port}`);
  });
};

// 启动应用
run();

这里的createApp函数很核心,其内部实现直接看源码中的中文注释即可,见下图:

赞(1) 打赏
文章名称:《lin-cms-koa源码阅读之:入口和启动》
文章链接:https://www.orzzone.com/source-code-read-lin-cms-koa-entry-run.html
商业联系:yakima.public@gmail.com

本站大部分文章为原创或编译而来,对于本站版权文章,未经许可不得用于商业目的,非商业性转载请以链接形式标注原文出处。
本站内容仅供个人学习交流,不做为任何投资、建议的参考依据,因此产生的问题需自行承担。

评论 抢沙发

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力提供更多优质内容!

支付宝扫一扫打赏

微信扫一扫打赏

登录

找回密码

注册