在 Egg 里面,有插件,也有框架(Beidou就是基于Eggjs的框架之一),前者还包括了 path
和 package
两种加载模式,那我们应该如何选择呢?
本文将以实例的方式,一步步给大家演示下,如何渐进式地进行代码演进。
全部的示例代码可以参见 eggjs/examples/progressive。
假设我们有一段分析 UA 的代码,实现以下功能:
ctx.isAndroid
ctx.isIOS
通过之前的教程,大家一定可以很快的写出来,我们快速回顾下:
对应的代码参见 step1。
目录结构:
example-app
├── app
│ ├── extend
│ │ └── context.js
│ └── router.js
├── test
│ └── index.test.js
└── package.json
核心代码:
// app/extend/context.js
module.exports = {
get isIOS() {
const iosReg = /iphone|ipad|ipod/i;
return iosReg.test(this.get('user-agent'));
},
};
我们很明显能感知到,这段逻辑是具备通用性的,可以写成插件。
但一开始的时候,功能还没完善,直接独立插件,维护起来比较麻烦。
此时,我们可以把代码写成插件的形式,但并不独立出去。
对应的代码参见 step2。
新的目录结构:
example-app
├── app
│ └── router.js
├── config
│ └── plugin.js
├── lib
│ └── plugin
│ └── egg-ua
│ ├── app
│ │ └── extend
│ │ └── context.js
│ └── package.json
├── test
│ └── index.test.js
└── package.json
核心代码:
-
app/extend/context.js
移动到lib/plugin/egg-ua/app/extend/context.js
。 -
lib/plugin/egg-ua/package.json
声明插件。
{
"eggPlugin": {
"name": "ua"
}
}
config/plugin.js
中通过path
来挂载插件。
// config/plugin.js
const path = require('path');
exports.ua = {
enable: true,
path: path.join(__dirname, '../lib/plugin/egg-ua'),
};
经过一段时间开发后,该模块的功能成熟,此时可以考虑抽出来成为独立的插件。
首先,我们抽出一个 egg-ua 插件,看过插件文档的同学应该都比较熟悉,我们这里只简单过一下:
目录结构:
egg-ua
├── app
│ └── extend
│ └── context.js
├── test
│ ├── fixtures
│ │ └── test-app
│ │ ├── app
│ │ │ └── router.js
│ │ └── package.json
│ └── ua.test.js
└── package.json
对应的代码参见 step3/egg-ua。
然后改造原有的应用,对应的代码参见 step3/example-app。
- 移除
lib/plugin/egg-ua
目录。 package.json
中声明对egg-ua
的依赖。config/plugin.js
中修改依赖声明为package
方式。
// config/plugin.js
exports.ua = {
enable: true,
package: 'egg-ua',
};
注意:在插件还没发布前,可以通过 npm link
的方式进行本地测试,具体参见 npm-link。
$ cd example-app
$ npm link ../egg-ua
$ npm i
$ npm test
综上所述,大家可以看到,我们是如何一步步进行渐进式演进的,得益于 Egg 强大的插件机制,代码的共建,复用和下沉,竟然可以这么的无痛。
- 一般来说,当应用中有可能会复用到的代码时,直接放到
lib/plugin
目录去,如例子中的egg-ua
。 - 当该插件功能稳定后,即可独立出来作为一个
node module
。 - 如此以往,应用中相对复用性较强的代码都会逐渐独立为单独的插件。
- 当你的应用逐渐进化到针对某类业务场景的解决方案时,将其抽象为独立的 framework 进行发布。Beidou就是基于egg的上层框架
- 当在新项目中抽象出的插件,下沉集成到框架后,其他项目只需要简单的重新
npm install
下就可以使用上,对整个团队的效率有极大的提升。 - 注意:不管是应用/插件/框架,都必须编写单元测试,并尽量实现 100% 覆盖率。