自定义组件
Midway
组件(Component)是一个可复用与多框架的模块包,一般用于几种场景:
- 1、包装往下游调用的代码,包裹三方模块简化使用,比如 orm(数据库调用),swagger(简化使用) 等
- 2、可复用的业务逻辑,比如抽象出来的公共 Controller,Service 等
组件可以本地加载,也可以打包到一起发布成一个 npm 包。组件可以在 midway v3/Serverless 中使用。你可以将复用的业务代码,或者功能模块都放到组件中进行维护。几乎所有的 Midway 通用能力都可以在组件中使用,包括但不限于配置,生命周期,控制器,拦截器等。
设计组件的时候尽可能的面向所有的上层框架场景,所以我们尽可能只依赖 @midwayjs/core
定义package.json
- 打包后的入口 main字段
- 打包命令 midwa-bin build -c
- files 上传的文件
组件目录
组件的结构和 midway 的推荐目录结构一样,组件的目录结构没有特别明确的规范,和应用或者函数保持一致即可。简单的理解,组件就是一个 “迷你应用"。
推荐的组件目录结构
.
├── package.json
├── src
│ ├── index.ts // 入口导出文件
│ ├── configuration.ts // 组件行为配置
│ └── service // 逻辑代码
│ └── bookService.ts
├── test
├── index.d.ts // 组件扩展定义
└── tsconfig.json
最终打包产物会保持目录不变,文件平行编译产出
定义入口
对于组件来说,唯一的规范是入口导出的 Configuration 属性,其必须是一个带有 @Configuration 装饰器的 Class。
例子
// configuration.ts
import { Configuration } from '@midwayjs/core';
import * as cacheComponent from '@midwayjs/cache';
import * as DefaultConfig from './config/config.default'; // 默认配置
@Configuration({
namespace: 'captcha',
imports: [cacheComponent],
importConfigs: [
{
default: DefaultConfig,
},
],
})
export class CaptchaConfiguration { }
index.ts 导出
export { CaptchaConfiguration as Configuration } from './configuration';
export * from './interface';
export * from './service';
组件生命周期
组件使用 src/configuration.ts 作为入口启动文件
注意
- 需要加一个 namespace 作为组件的命名空间
- 和整个 Midway 通用的 生命周期扩展 能力相同
// src/configuration.ts
import { Configuration } from '@midwayjs/core';
@Configuration({
namespace: 'book'
})
export class BookConfiguration {
async onReady() {
// ...
}
}
flowchart LR start["生命周期函数 src/configuration.ts"] 0["onConfigLoad"] 1["onReady"] 2["onServerReady"] 3["onStop"] start --> 0 start --> 1 start --> 2 start --> 3
interface ILifeCycle {
/**
* 在应用配置加载后执行
*/
onConfigLoad?(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;
/**
* 在依赖注入容器 ready 的时候执行
*/
onReady(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;
/**
* 在应用服务启动后执行
*/
onServerReady?(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;
/**
* 在应用停止的时候执行
*/
onStop?(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;
}
组件配置
// src/configuration.ts
...
@Configuration({
namespace: 'book',
importConfigs: [
{ // 默认配置
default: DefaultConfig,
local: LocalConfig
}
]
})
...
ts类型推导
在根目录下的 index.d.ts 中增加配置定义
// 例子 index.d.ts
import { CaptchaOptions } from './dist/index';
export * from './dist/index';
declare module '@midwayjs/core/dist/interface' {
interface MidwayConfig {
captcha?: Partial<CaptchaOptions>;
}
}
同时,组件的 package.json 也有对应的修改
{
"name": "****",
"main": "dist/index.js",
"typings": "index.d.ts", // 这里的类型导出文件使用项目根目录的
// ...
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"index.d.ts" // 发布时需要额外带上这个文件
],
}
组件发布
组件就是一个普通 Node.js 包,编译后发布到 npm 分发即可。
// 编译并发布对应的component
$ npm run build && npm publish
总结
- 组件的代码需要导出一个 Configuration 属性,其必须是一个带有 @Configuration 装饰器的 Class,用于配置组件自身能力
- 所有 显式导出的代码 才会被依赖注入容器加载,简单来说,所有 被装饰器装饰 的类都需要导出,包括控制器,服务,中间件等等
- package.json 中指定 main 路径