课程名称:web前端架构师
课程章节:第14周 第八章 添加 Mongoose 以及 egg.js 插件原理
主讲老师:张轩
课程内容: 将mongoose models 自动加在到 egg app 上
将mongoose models 自动加在到 egg app 上
昨天最后实现了加载器,将mongoose models 挂载到了 App 上,那么现在通过代码来使用下
首先编写测试代码,创建一个 service
import { Service } from 'egg';
export default class UserController extends Service {
public async getUser() {
return this.app.model.User.find().limit(10);
}
}
上面代码就是我们想要的结果,通过 app.model 访问到 models下的 model
下面编写一个 UserModel
import { Application } from 'egg';
import { Schema } from 'mongoose';
const ObjectId = Schema.Types.ObjectId;
const UserSchema = new Schema({
username: String,
password: {
type: String,
select: false,
},
hobbies: [ String ],
date: Date,
createAt: Date,
age: Number,
team: {
type: ObjectId,
ref: 'team',
},
}, {
collection: 'users',
});
function UserModel(app: Application) {
return app.mongoose.model('user', UserSchema);
}
export default UserModel;
此时我们还需要在 typings 生命app 下的 model, 因为我们在 service 下访问 app.model, ts 无法识别就会报错
import 'egg';
import { Model, type Connection } from 'mongoose'
declare module 'egg' {
type mongooseModels = {
[k: string]: Model<any>
}
interface Application {
model: mongooseModels
mongoose: Connection
}
}
然后就可以运行代码就像测试了,就可以得到我们实现的结果
将逻辑抽象为 egg.js 插件
之前我们完成了 mongose 的绑定到 app 对象上,如果我们有其他项目也想要这个功能,我们可能就需要进行拷贝,这样做肯定不是很好
这时,我们就需要了解 egg.js 到插件的开发 . 参考文档 https://www.eggjs.org/zh-CN/advanced/plugin
初始化插件项目
mkdir egg-hello && cd egg-hello
npm init egg --type=plugin
npm i
npm test
一个插件其实就是一个『迷你的应用』,下面展示的是一个插件的目录结构,和应用(app)几乎一样。
插件和应用的区别
插件没有独立的 router 和 controller
插件需要在 package.json 中的 eggPlugin 节点指定插件特有的信息
{String} name
- 插件名(必须配置),具有唯一性,配置依赖关系时会指定依赖插件的 name。{Array} dependencies
- 当前插件强依赖的插件列表(如果依赖的插件没找到,应用启动失败)。{Array} optionalDependencies
- 当前插件的可选依赖插件列表(如果依赖的插件未开启,只会 warning,不会影响应用启动)。{Array} env
- 只有在指定运行环境才能开启,具体有哪些环境可以参考运行环境。此配置是可选的,一般情况下都不需要配置。
"name": "egg-hismongoose",
"eggPlugin": {
"name": "hismongoose",
"dependencies": ["registry"],
"optionalDependencies": ["vip"],
"env": ["local", "test", "unittest", "prod"]
}
}
插件没有 plugin.js
插件规范
- 命名规范
- npm 包名以 egg- 开头,且为全小写,例如:egg-xx。比较长的词组用中划线:egg-foo-bar
- 对应的插件名使用小驼峰,小驼峰转换规则以 npm 包名的中划线为准 egg-foo-bar => fooBar
- 对于可以中划线也可以不用的情况,不做强制约定,例如:userservice(egg-userservice) 还是 user-service(egg-user-service) 都可以
- package.json 书写规范
- 按照上面的说明添加 eggPlugin 节点
- 在 keywords 里加上 egg、egg-plugin、eggPlugin 等关键字,便于索引
编写发布 egg mongoose 插件
在插件项目根目录下新建文件 app.js, 然后把我们之前编写的 app.ts 拿过来,改造成 nodejs 代码
const mongoose = require('mongoose');
const path = require('path');
const { createConnection } = mongoose
class AppBook {
constructor(app) {
this.app = app;
const { url } = this.app.config.mongoose;
const db = createConnection(url);
db.on('connected', () => {
console.log('connected success');
});
this.app.mongoose = db;
}
configWillLoad() {
const dir = path.join(this.app.config.baseDir, 'app/model');
this.app.loader.loadToApp(dir, 'model', {
caseStyle: 'Upper',
});
}
async willReady(){
console.log(this.app.config.coreMiddleware);
}
}
module.exports = AppBook
新建 index.d.ts 文件。用于声明类型。把我们之前声明的类型文件拿过来就可以了
同时还需要增加一个 config 提示,这样在我们的项目中config 文件中使用时就会有mongoose 提示
import 'egg';
import { Model, type Connection } from 'mongoose'
declare module 'egg' {
type mongooseModels = {
[k: string]: Model<any>
}
interface Application {
model: mongooseModels
mongoose: Connection
}
interface EggAppConfig{
mongoose: {
url?: string
}
}
}
然后发布 npm 包就可以了.
然后安装我们发布的 npm 包,这里我发布的是 egg-hismongoose
npm i egg-hismongoose
把我们之前在 app.ts 文件中写的monoose代码删除掉,然后在config.default.js文件中配置mongoose
import { EggAppConfig, EggAppInfo, PowerPartial } from 'egg';
export default (appInfo: EggAppInfo) => {
const config = {} as PowerPartial<EggAppConfig>;
// 这里编写就会有mongoose提示
config.mongoose = {
url: 'mongodb://user:password@localhost:27017',
};
// add your special config in here
const bizConfig = {
sourceUrl: `https://github.com/eggjs/examples/tree/master/${appInfo.name}`,
myLogger: {
allowedMethod: [ 'POST' ],
},
// mongoose: {
// url: 'mongodb://user:password@localhost:27017',
// },
};
// the return config will combines to EggAppConfig
return {
...config as {},
...bizConfig,
};
};
这样我们编写的 mongoose 插件就可以在egg.js 项目中运行了