我的客户端开发已经进入到比较深入的阶段,不得不研究一下 hexo 的原理了,不过,看 hexo 源码是非常痛苦的。无论看什么源码都是非常痛苦的。
昨天我萌生了一个很好的主意,我们使用 hexo 的时候,都是从命令行输入命令的,那么我要从 hexo 的执行过程开始,找到一个阅读 hexo 源码突破口。
于是我发现 hexo 虽然是一个静态文件生成的引擎,但是它的入口却隐藏在一个 hexo-cli 的包里。
于是,早上开始,我就在那里阅读这个 hexo-cli 的代码。到这会儿下午 3 点多,终于基本看懂了这个包在干什么。
其实,我是有点无语的,这个包就好像一个马甲,又像一个分身,我也不知道怎么形容。这里有一个假的 Hexo 对象。套用一些术语,你可以认为这里其实是一个 Mock。
主体文件是一个 lib/hexo.ts,里面是什么呢?
function entry(cwd = process.cwd(), args) {
args = camelCaseKeys(args || minimist(process.argv.slice(2), { string: ['_', 'p', 'path', 's', 'slug'] }));
let hexo = new Context(cwd, args);
let { log } = hexo;
// Change the title in console
process.title = 'hexo';
function handleError(err) {
if (err && !(err instanceof HexoNotFoundError)) {
log.fatal(err);
}
process.exitCode = 2;
}
return findPkg(cwd, args).then(path => {
if (!path) return;
hexo.base_dir = path;
return loadModule(path, args).catch(err => {
log.error(err.message);
log.error('Local hexo loading failed in %s', magenta(tildify(path)));
log.error('Try running: \'rm -rf node_modules && npm install --force\'');
throw new HexoNotFoundError();
});
}).then(mod => {
if (mod) hexo = mod;
log = hexo.log;
registerConsole(hexo);
return hexo.init();
}).then(() => {
let cmd = 'help';
if (!args.h && !args.help) {
const c = args._.shift();
if (c && hexo.extend.console.get(c)) cmd = c;
}
watchSignal(hexo);
return hexo.call(cmd, args).then(() => hexo.exit()).catch(err => hexo.exit(err).then(() => {
// `hexo.exit()` already dumped `err`
handleError(null);
}));
}).catch(handleError);
}
犹豫再三,还是放个代码吧。这段就是主体了。
这个函数,就是 hexo-cli 的主体,是一个 entry 函数,这个函数的作用,就好像一般的软件的 main 方法,跟它的名字一样,是入口。
第一个作用在第1行,就是 cwd=process.cwd ,这个作用是取到当前的工作目录。
第二个作用是第2行,就是 args,解析了命令执行的参数。
第三个重点在17行,findPkg,这是干什么呢,就是找寻 hexo 这包在什么地方,记住我们现在是 hexo-cli 包,它要寻找 hexo 包在哪里。 怎么找呢?通过 cwd 下面的 package.json,它首先检查现在是不是一个 hexo 的目录,第二就是找到里面指定的 hexo 包的路径。
第四个在 22 行,找到 hexo 包的所在,会执行 loadModule,加载 hexo 包。
第五个在 29 行,加载 hexo 包成功后,会将 hexo 对象替换现在的对象。
你可能要问,如果现在不是一个 hexo 的目录,或者没找到 hexo 的包怎么办?注意看 第 3 行,hexo 已经是一个对象了,是 Context 的对象,里面的一些属性,和真正的 hexo 的对象,其实有一些是一样的,但是只包含最简单的几个,所以是一个 hexo 对象的 Mock,如果加载失败就会是这个 Context 对象出来顶缸。
第六个是 44 行,如果 hexo 对象从李鬼替换成李逵后,会真的调用 hexo 支持的命令。
所以综上,hexo-cli 就是 hexo 的一个壳,最重要的就是解析了命令行参数,如果在目录不正确的情况下,可以展示友好的帮助信息。
-- End --