Javascript is required
自定义组件

组件(Component)是一个可复用与多框架的模块包,一般用于几种场景:

  • 1、包装往下游调用的代码,包裹三方模块简化使用,比如 orm(数据库调用),swagger(简化使用) 等
  • 2、可复用的业务逻辑,比如抽象出来的公共 Controller,Service 等

组件可以本地加载,也可以打包到一起发布成一个 npm 包。组件可以在 midway v3/Serverless 中使用。你可以将复用的业务代码,或者功能模块都放到组件中进行维护。几乎所有的 Midway 通用能力都可以在组件中使用,包括但不限于配置,生命周期,控制器,拦截器等。

设计组件的时候尽可能的面向所有的上层框架场景,所以我们尽可能只依赖 @midwayjs/core

定义package.json

  1. 打包后的入口 main字段
  2. 打包命令 midwa-bin build -c
  3. 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 作为入口启动文件

注意

  1. 需要加一个 namespace 作为组件的命名空间
  2. 和整个 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

总结

  1. 组件的代码需要导出一个 Configuration 属性,其必须是一个带有 @Configuration 装饰器的 Class,用于配置组件自身能力
  2. 所有 显式导出的代码 才会被依赖注入容器加载,简单来说,所有 被装饰器装饰 的类都需要导出,包括控制器,服务,中间件等等
  3. package.json 中指定 main 路径