插件机制是 Egg 框架的一大特色。它不但可以保证框架核心的足够精简、稳定、高效,还可以促进业务逻辑的复用,生态圈的形成。
插件也跟应用一样,包含了 Service、中间件、extend等等,没有独立的 Router 和 Controller,也没有 plugin.js
这份插件配置文件。
搭建开发环境
使用 Egg 提供的脚手架 egg-boilerplate-plugin 来开发插件
$ mkdir egg-hello && cd egg-hello
$ npm init egg --type=plugin
$ npm i
$ npm test
插件开发需要在 package.json
的 eggPlugin
节点配置插件信息
{
"name": "egg-rpc",
"eggPlugin": {
// 插件名(必须),生成插件名为 egg-{name}
"name": "rpc",
// 插件依赖列表(可选),依赖插件没找到,应用启动失败
"dependencies": [ "registry" ],
// 插件可选依赖列表(可选)
"optionalDependencies": [ "vip" ],
// 指定环境开启插件(可选)
"env": [ "local", "test", "unittest", "prod" ]
}
}
插件是自己管理依赖的,应用在加载所有插件前会预先从它们的 package.json
中读取 eggPlugin > dependencies
和 eggPlugin > optionalDependencies
节点,然后根据依赖关系计算出加载顺序
插件作用
插件主要有以下作用:
-
支持扩展内置对象接口
app/extend/request.js
- 扩展 Koa#Request 类- app/extend/response.js - 扩展 Koa#Response 类
app/extend/context.js
- 扩展 Koa#Context 类app/extend/helper.js
- 扩展 Helper 类app/extend/application.js
- 扩展 Application 类app/extend/agent.js
- 扩展 Agent 类
-
插入自定义中间件
-
在
app.js
中将中间件插入到合适位置// index 指插入位置, 插入中间件为 static app.config.coreMiddleware.splice(index, 0, 'static');
-
-
应用启动时做一些初始化工作
- 异步启动逻辑,可以使用
app.beforeStart
API - 添加 agent 启动逻辑,使用
agent.beforeStart
API
- 异步启动逻辑,可以使用
-
设置定时任务
插件写法
对于使用同一服务可以产生多个实例的插件, Egg 提供了 app.addSingleton(name, creator)
方法来统一创建相应的服务。通过配置文件 config.js
里插件的 client
或 clients
key来配置多个实例的属性。
下面是官方的 egg-mysql 案例
// egg-mysql/app.js
module.exports = app => {
// 第一个参数 mysql 指定了挂载到 app 上的字段,我们可以通过 `app.mysql` 访问到 MySQL singleton 实例
// 第二个参数 createMysql 接受两个参数(config, app),并返回一个 MySQL 的实例
app.addSingleton('mysql', createMysql);
}
/**
* @param {Object} config 框架处理之后的配置项,如果应用配置了多个 MySQL 实例,会将每一个配置项分别传入并调用多次 createMysql
* @param {Application} app 当前的应用
* @return {Object} 返回创建的 MySQL 实例
*/
function createMysql(config, app) {
assert(config.host && config.port && config.user && config.database);
// 创建实例
const client = new Mysql(config);
// 做启动应用前的检查
app.beforeStart(async () => {
const rows = await client.query('select now() as currentTime;');
app.coreLogger.info(`[egg-mysql] init instance success, rds currentTime: ${
rows[0].currentTime}`);
});
return client;
}
单实例的文件配置
// config/config.default.js
module.exports = {
mysql: {
client: {
host: 'mysql.com',
port: '3306',
user: 'test_user',
password: 'test_password',
database: 'test',
},
},
};
多实例的文件配置
// config/config.default.js
exports.mysql = {
clients: {
// clientId, access the client instance by app.mysql.get('clientId')
db1: {
user: 'user1',
password: 'upassword1',
database: 'db1',
},
db2: {
user: 'user2',
password: 'upassword2',
database: 'db2',
},