Egg 插件

2020-02-06 14:10 更新

插件機(jī)制是我們框架的一大特色。它不但可以保證框架核心的足夠精簡(jiǎn)、穩(wěn)定、高效,還可以促進(jìn)業(yè)務(wù)邏輯的復(fù)用,生態(tài)圈的形成。有人可能會(huì)問(wèn)了

  • Koa 已經(jīng)有了中間件的機(jī)制,為啥還要插件呢?
  • 中間件、插件、應(yīng)用它們之間是什么關(guān)系,有什么區(qū)別?
  • 我該怎么使用一個(gè)插件?
  • 如何編寫一個(gè)插件?
  • ...

接下來(lái)我們就來(lái)逐一討論

為什么要插件

我們?cè)谑褂?Koa 中間件過(guò)程中發(fā)現(xiàn)了下面一些問(wèn)題:

  1. 中間件加載其實(shí)是有先后順序的,但是中間件自身卻無(wú)法管理這種順序,只能交給使用者。這樣其實(shí)非常不友好,一旦順序不對(duì),結(jié)果可能有天壤之別。
  2. 中間件的定位是攔截用戶請(qǐng)求,并在它前后做一些事情,例如:鑒權(quán)、安全檢查、訪問(wèn)日志等等。但實(shí)際情況是,有些功能是和請(qǐng)求無(wú)關(guān)的,例如:定時(shí)任務(wù)、消息訂閱、后臺(tái)邏輯等等。
  3. 有些功能包含非常復(fù)雜的初始化邏輯,需要在應(yīng)用啟動(dòng)的時(shí)候完成。這顯然也不適合放到中間件中去實(shí)現(xiàn)。

綜上所述,我們需要一套更加強(qiáng)大的機(jī)制,來(lái)管理、編排那些相對(duì)獨(dú)立的業(yè)務(wù)邏輯。

中間件、插件、應(yīng)用的關(guān)系

一個(gè)插件其實(shí)就是一個(gè)『迷你的應(yīng)用』,和應(yīng)用(app)幾乎一樣:

他們的關(guān)系是:

  • 應(yīng)用可以直接引入 Koa 的中間件。
  • 當(dāng)遇到上一節(jié)提到的場(chǎng)景時(shí),則應(yīng)用需引入插件。
  • 插件本身可以包含中間件。
  • 多個(gè)插件可以包裝為一個(gè)上層框架。

使用插件

插件一般通過(guò) npm 模塊的方式進(jìn)行復(fù)用:

$ npm i egg-mysql --save

注意:我們建議通過(guò) ^ 的方式引入依賴,并且強(qiáng)烈不建議鎖定版本。

{
"dependencies": {
"egg-mysql": "^3.0.0"
}
}

然后需要在應(yīng)用或框架的 config/plugin.js 中聲明:

// config/plugin.js
// 使用 mysql 插件
exports.mysql = {
enable: true,
package: 'egg-mysql',
};

就可以直接使用插件提供的功能:

app.mysql.query(sql, values);

參數(shù)介紹

plugin.js 中的每個(gè)配置項(xiàng)支持:

  • {Boolean} enable - 是否開啟此插件,默認(rèn)為 true
  • {String} package - npm 模塊名稱,通過(guò) npm 模塊形式引入插件
  • {String} path - 插件絕對(duì)路徑,跟 package 配置互斥
  • {Array} env - 只有在指定運(yùn)行環(huán)境才能開啟,會(huì)覆蓋插件自身 package.json 中的配置

開啟和關(guān)閉

在上層框架內(nèi)部?jī)?nèi)置的插件,應(yīng)用在使用時(shí)就不用配置 package 或者 path,只需要指定 enable 與否:

// 對(duì)于內(nèi)置插件,可以用下面的簡(jiǎn)潔方式開啟或關(guān)閉
exports.onerror = false;

根據(jù)環(huán)境配置

同時(shí),我們還支持 plugin.{env}.js 這種模式,會(huì)根據(jù)運(yùn)行環(huán)境加載插件配置。

比如定義了一個(gè)開發(fā)環(huán)境使用的插件 egg-dev,只希望在本地環(huán)境加載,可以安裝到 devDependencies。

// npm i egg-dev --save-dev
// package.json
{
"devDependencies": {
"egg-dev": "*"
}
}

然后在 plugin.local.js 中聲明:

// config/plugin.local.js
exports.dev = {
enable: true,
package: 'egg-dev',
};

這樣在生產(chǎn)環(huán)境可以 npm i --production 不需要下載 egg-dev 的包了。

注意:

  • 不存在 plugin.default.js
  • 只能在應(yīng)用層使用,在框架層請(qǐng)勿使用。

package 和 path

  • package 是 npm 方式引入,也是最常見的引入方式
  • path 是絕對(duì)路徑引入,如應(yīng)用內(nèi)部抽了一個(gè)插件,但還沒(méi)達(dá)到開源發(fā)布獨(dú)立 npm 的階段,或者是應(yīng)用自己覆蓋了框架的一些插件
  • 關(guān)于這兩種方式的使用場(chǎng)景,可以參見漸進(jìn)式開發(fā)
// config/plugin.js
const path = require('path');
exports.mysql = {
enable: true,
path: path.join(__dirname, '../lib/plugin/egg-mysql'),
};

插件配置

插件一般會(huì)包含自己的默認(rèn)配置,應(yīng)用開發(fā)者可以在 config.default.js 覆蓋對(duì)應(yīng)的配置:

// config/config.default.js
exports.mysql = {
client: {
host: 'mysql.com',
port: '3306',
user: 'test_user',
password: 'test_password',
database: 'test',
},
};

具體合并規(guī)則可以參見配置。

插件列表

如何開發(fā)一個(gè)插件

參見文檔:插件開發(fā)。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)