文:羽航
dora 本质就是使用 koa 模块启动一个 koa 服务器。通常,我们使用 koa 编写应用时,会有如下的代码流程:
- 通过
const app = require('koa')()
引入模块。 - 使用
app.use()
方法为koa
应用注入中间件。比如我们都知道的koa-route
,koa-static
等中间件, 也可以是我们自己写的中间件。 - 调用
const server = http.createServer(app.callback())
来创建 http 服务器。 - 调用
server.listen(port, callback)
来启动服务器,其中 callback 是服务器启动完成后的回调,通常我们会在 callback 里面打印 'listen on 127.0.0.1:8000' 这样的信息。
如果你对上面 4 个步骤理解很模糊,请先通过 goolge 了解 koa 及期中间件的使用方法,再来接着阅读下文。
dora 的代码也是上面的 4 个步骤,只不过在这些步骤之间,可以通过插件的方式,动态地加载功能。
为了理解 dora 的插件,我们先结合上述 4 个步骤介绍 dora 的几个事件时间点:
middleware.before
:在步骤 1 和步骤 2 之间执行。middleware
在步骤 2 中,加载插件中提供的中间件。这个时间点的插件可以处理 http 的网络请求。middleware.after
在步骤 2 和 3 之间执行。server.before
在middleware.after
之后,步骤 3 之前执行。server.after
第 4 步的 callback 回调函数里执行。
整个 dora 的执行逻辑如下(伪代码):
// 扫描所有需要使用的插件,放到插件列表里。
resolvePlugins();
async.series([
// 执行所有注册到 middleware.before 时间点的插件。
next => _applyPlugins('middleware.before', null, next),
// 执行所有注册到 middleware 时间点的插件,app 实例会传递给插件,用来通过调用`app.use()`注册 koa 中间件。
next => _applyPlugins('middleware', null, next),
// 执行所有注册到 middleware.after 时间点的插件。
next => _applyPlugins('middleware.after', null, next),
next => { server = context.server = http.createServer(app.callback()); next(); },
// 执行所有注册到 server.before 时间点的插件。
next => _applyPlugins('server.before', null, next),
next => {
server.listen(port, () => {
log.info('dora', `listened on ${port}`);
next();
});
},
// 执行所有注册到 server.after 时间点的插件。
next => _applyPlugins('server.after', null, next),
], callback);
那么,dora 的插件是如何注册的呢,特别是如何注册到不同的时间点。其实也很简单,我们以dora-plugin-atool-build
为例,这个插件就是一个标准的 npm 模块,只有一个入口文件 index.js
,内容如下(伪代码):
import webpack;
import koa-webpack-dev-middleware;
let webpackConfig;
module.exports = {
'middleware.before': () => {
// 获取默认的 webpack 配置,并和用户项目里面的自定义配置合并。
webpackConfig = getAndMergeConfig();
},
'middleware': (args, pluginArgs) => {
// 返回 koa-webpack-dev-middleware 组件产生的 koa 中间件。
const comiper = webpack.compiper(webpackConfig);
return koa-webpack-dev-middleware(compiper)
},
'middleware.after': () => { // do nothing },
'server.after': () => {
console.log('dora-plugin-webpack-server ready.');
}
};
从上面代码可以看出,dora 的插件注册也很简单,就是通过如 'middleware.before' 的字符串注册插件到相应的时间点。dora 加载一个插件的模块后,会把其不同时间点的函数注册到不同时间点的插件列表里,applyPlugins()
执行时,只要把对应时间点的插件列表取出来挨着执行下就行了,整个 dora 的机制还是非常简单的。
需要注意下的是,在插件模块里,middleware
这个字段对应的函数,一定要返回一个 koa 的中间件(比如上面的代码里,返回了 koa-webpack-dev-middleware 中间件,也可以返回自己写的中间件,更多细节请查阅 koa 中间件相关资料),dora 会帮你调用 app.use
来注册这个返回的中间件;除此外的 middleware.before
, middleware.after
, server.before
, server.after
这 4 个时间点的函数,都是普通的任意函数。
最后还剩的一点疑虑是,dora 是如何知道要加载哪些插件呢?
现阶段 dora 不会自动扫描任何目录,你需要通过参数(命令行参数或函数调用参数)明确告知需要哪些插件。
比如执行 dora -p 8000 --plugins proxy
会在 node_modules
目录下看 dora-plugin-proxy
模块是否存在,如果存在则加载;不存在则看 proxy
模块是否存在。