Skip to main content

Release 4.0.0-beta

· 4 minute read
Harry Chen
Maintainer of Midway

这是全新的 Midway 4.0 的变化,这是一个非常重大的版本。

  • 全局变化
    • 框架支持从 Node.js >=20 开始
    • 默认开启 asyncLocalStorage
  • 编程范式
    • 不再以黑盒方式提供框架启动时的目录文件扫描自动绑定能力,改为显式声明,每个组件都可以有自己的绑定和加载方式
    • 组件包查找规范变化,现在会查找 index.tsconfiguration.ts,以及 package.json 中 main 定义的路径
    • 统一规范函数式的导出路径,为组件包下的 functional 路径,如 @midwayjs/core/functional
  • 【core】
    • 通用能力
      • 由于使用率较低且影响依赖注入容器逻辑,移除了流程控制 Pipeline 相关的能力
      • 移除之前版本中框架启动时的目录文件扫描自动绑定能力,现在需要显式增加一个 file detector,可以自由配置其需要扫描和忽略的目录或者文件
      • 移除了会和 validate 的转换产生歧义的请求参数自动 DTO 转换功能,现在自动转换仅在 validate 或者 validation 组件开启时生效
      • onReady 等生命周期现在增加了超时机制,默认 30s
    • 函数式编程
      • 提供与 @Configuration 同样功能的 defineConfiguration 方法
      • 提供内置的 hooks 方法,如 useContext, useLogger, useInject, useConfig, useApp, useMainApp
      • 提供了函数式方法的导出规范,新开发的 hooks 放在 functional 目录中,使用子模块方式导出
    • 装饰器部分
      • 为了更好的管理元数据,重构了 DecoratorManager,增加新的 MetadataManager,增加了更加方便的聚合和拷贝元数据的能力
      • 明确各种装饰器继承的情况,默认情况下,类装饰器和参数装饰器不继承,属性装饰器和方法装饰器继承
      • 使用 @MainApp() 代替 @App() 空参数
      • 使用 @Config(ALL) 替换为更为明确的 @AllConfig() 装饰器
      • 移除 @Configuration 中的 conflictCheckdetectorOptions, 这些配置将移动到 detector
      • DecoratorManager 中的 listPrelaodModules 调整为 listPreStartModulesavePreloadModule 调整为 savePreStartModule ,使其语义更加明确
    • 依赖注入
      • 移除了 container.getcontainer.getAsync 的一部分无用的参数
      • 优化了循环依赖时展示的依赖链路信息以及 definition 未找到时的输出信息
      • 单例对象现在和 registerObject 的对象存储的位置一致了
      • 增加了一个动态依赖注入容器,用于在开发期动态替换实例,支持 HMR 功能
    • 框架机制
      • BaseFramework 移除了令人疑惑的 container 相关 hook 方法,现在都统一使用 applicationInitialize
      • 移除框架的 MidwayFrameworkType,以及对应的 getFrameworkType() 方法
      • 移除了特定框架下令人疑惑的 contextLoggerApplyLoggercontextLoggerFormat 配置,现在如果要配置框架特定的 logger,使用 setFrameworkLoggerName 方法
      • ServiceFactoryDataSourceManager 现在启动可以通过 initClients 的参数 concurrent 支持并发,由组件自行控制是否支持
      • DataSourceManager 原有的 cacheInstancevalidateConnection 选项废弃
      • MidwayConfigServce 在获取配置时可以增加默认值
      • 增加服务发现基础功能,增加了 consulredisetcd 的实现
  • 【decorator】移除,API 都移动到 @midwayjs/core,不再单独提供 4.x 版本
  • 【async-hooks-context-manager】现在默认开启 async_local_storage,代码合并至 core 模块中
  • 【axios】移除了废弃的 axios 导出
  • 【socketio】移除了内置的 socket.io-redis
  • 【validate】
    • 由于固化了 Joi 作为验证器,不再更新
    • 移除 @Rule 作为类装饰器的功能
    • 移除属性 @Rule 参数传递类本身的功能
  • 【validation】新增组件,替代原有 validate 组件
    • 支持多种验证器,如 Joi, zod, class-validator,提供内置的 i18n 支持
    • 可自定义扩展验证器
  • 【mock】
    • 由于移除了框架启动的扫描能力,如果有大量历史测试不方便修改,可以使用提供的 createLegacyAppcreateLegacyLightAppcreateLegacyFunctionApp ,对应之前的 createAppcreateLightApp, createFunctionApp
    • 移除了 createAppcreateLightApp, createFunctionApp 方法的最后一个参数,现在额外指定组件可以写到 options.imports
  • 【sequelize】
    • 移除老版本配置的兼容代码,以及历史装饰器导出,如 @BaseTable
    • 移除默认启动时数据源连接校验 validateConnection,如有需求,可以在配置中单独开启
  • 【tags】移除,不再提供 4.x 版本
  • 【processAgent】移除,不再提供 4.x 版本
  • 【event-emitter] 新增组件,提供事件触发和监听能力支持

Release 3.20.0

· 3 minute read
Harry Chen
Maintainer of Midway

升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。

本次 3.20 版本,主要引入了全新的 BullMQ 组件,作为 Bull 组件的升级替代,提供了更好的性能和更多的功能。

下面是更为细节的描述。

BullMQ 组件

从 v3.20 开始,我们引入了全新的 BullMQ 组件,作为 Bull 组件的下一代实现。BullMQ 提供了更好的性能和更丰富的功能,包括:

  • 更好的类型支持
  • 更强大的任务流(Flow Producer)功能
  • 更完善的事件系统
  • 更灵活的任务处理机制

基础使用示例:

// 定义任务处理器
@Processor('test')
export class TestProcessor implements IProcessor {
async execute(data: any) {
// 处理任务逻辑
console.log('processing job:', data);
}
}

// 执行任务
const testQueue = this.bullmqFramework.getQueue('test');
await testQueue?.runJob({
name: 'harry'
});

任务流示例:

// 创建任务流
const flowProducer = bullmqFramework.createFlowProducer({}, 'test-flow');

await flowProducer.add({
name: 'flow-test',
queueName: 'flow-queue-1',
data: { value: 1 },
children: [
{
name: 'child-job',
queueName: 'flow-queue-2',
data: { value: 2 }
}
]
});

更多的内容,请参考 BullMQ 组件文档

Bull 组件迁移提示

从 v3.20 开始,我们推荐使用 BullMQ 组件替代原有的 Bull 组件。虽然 Bull 组件仍然可用,但我们建议在新项目中使用 BullMQ,并逐步将现有项目迁移到 BullMQ。

主要的变化包括:

  1. 配置方式的调整
// Bull
export default {
bull: {
defaultQueueOptions: {
redis: {
port: 6379,
host: '127.0.0.1',
},
}
},
}

// BullMQ
export default {
bullmq: {
defaultConnection: {
port: 6379,
host: '127.0.0.1',
},
},
}
  1. Worker 和事件处理
// BullMQ 新增了独立的 Worker 和 QueueEvents
const worker = bullmqFramework.createWorker(
'queueName',
async (job) => {
// 处理任务
}
);

const queueEvents = queue.createQueueEvents();
queueEvents.on('completed', ({ jobId }) => {
console.log(`Job ${jobId} completed!`);
});
  1. 任务流支持
// BullMQ 支持创建任务依赖关系
const flowProducer = bullmqFramework.createFlowProducer();
await flowProducer.add({
name: 'flow-test',
queueName: 'flow-queue-1',
children: [/* 子任务 */]
});
  1. 队列操作的增强
// BullMQ 提供了更多队列操作方法
const queue = bullmqFramework.createQueue('test');
await queue.runJob(data); // 执行任务
await queue.createQueueEvents(); // 创建事件监听
await queue.createQueueEventsProducer(); // 创建事件生产者

其他更新

  • typeorm 组件现在可以指定自定义的 DataSource 了,以支持一些自定义数据源的场景
  • 更新了一些依赖库以提高安全性和稳定性

更多的更新内容和详细信息,请参考我们的 ChangeLog

Release 3.19.0

· 2 minute read
Harry Chen
Maintainer of Midway

升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。

本次 3.19 版本,主要引入了 Kafka 组件的重构,以及一些性能优化和 bug 修复。

下面是更为细节的描述。

Kafka 组件重构

从 v3.19 开始,Kafka 组件进行了重构,配置和使用方法与之前有较大差异。虽然原有的使用方式仍然兼容,但文档不再保留。新的 Kafka 组件提供了更灵活的配置和更强大的功能。

// src/config/config.default.ts
export default {
kafka: {
consumer: {
sub1: {
connectionOptions: {
clientId: 'my-app',
brokers: ['localhost:9092'],
},
consumerOptions: {
groupId: 'groupId-test-1',
},
subscribeOptions: {
topics: ['topic-test-1'],
}
},
},
producer: {
clients: {
pub1: {
connectionOptions: {
clientId: 'my-app',
brokers: ['localhost:9092'],
},
producerOptions: {
// ...
}
}
}
}
}
}

更多的内容,请参考 Kafka 组件文档

Mock 功能分组

3.19.0 开始,Midway 的 mock 功能支持通过分组来管理不同的 mock 数据。你可以在创建 mock 时指定一个分组名称,这样可以在需要时单独恢复或清理某个分组的 mock 数据。

import { mockContext, restoreMocks } from '@midwayjs/mock';

it('should test mock with groups', async () => {
const app = await createApp();

// 创建普通对象的 mock
const a = {};
mockProperty(a, 'getUser', async () => {
return 'midway';
}, 'group1');

// 创建上下文的 mock
mockContext(app, 'user', 'midway', 'group1');
mockContext(app, 'role', 'admin', 'group2');

// 恢复单个分组
restoreMocks('group1');

// 恢复所有分组
restoreAllMocks();
});

通过分组,你可以更灵活地管理和控制 mock 数据,特别是在复杂的测试场景中。

新增了一个启动性能分析的命令

在开发环境下,新增了一个 perf-init 命令,用于在启动时初始化性能分析,需要配合最新的 mwtsc 一同使用。

{
"scripts": {
"dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js --perf-init"
}
}

其他更新

  • 更新了一些依赖库以提高安全性和稳定性。

更多的更新内容和详细信息,请参考我们的 ChangeLog

Release 3.18.0

· 2 minute read
Harry Chen
Maintainer of Midway

升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。

本次 3.18 版本,主要修复了新的 busboy 组件的一些遗留问题,以及新增了一种上传模式。

下面是更为细节的描述。

异步迭代器上传模式

为了支持单次多个文件的流式上传,新版本使用了异步迭代器模型转换了上传流,这个新的模式用于替代原有的流式模式。

// src/config/config.default.ts
export default {
// ...
busboy: {
mode: 'asyncIterator',
},
}

装饰器的入参也已经变成了异步迭代器。

import { Controller, Post, Files, Fields } from '@midwayjs/core';
import { UploadStreamFileInfo, UploadStreamFieldInfo } from '@midwayjs/busboy';

@Controller('/')
export class HomeController {

@Post('/upload', /*...*/)
async upload(
@Files() fileIterator: AsyncGenerator<UploadStreamFileInfo>,
@Fields() fieldIterator: AsyncGenerator<UploadStreamFieldInfo>
) {
// ...
}
}

我们可以通过循环迭代器获取到每个上传的文件。

for await (const file of fileIterator) {
const { filename, data } = file;
// ...
}

进而可以方便的做后续处理。

更多的内容,请参考 细节文档

此外还有更多的变化

  • 流式上传时的 fieldName 字段现在恢复了
  • httpClient 现在默认的配置不再会被单次请求覆盖
  • 数据源的优先级 NPE 报错现在已经修复了
  • 业务中的 https 配置现在在 dev 的输出提示中也变得正常了

以及一大批依赖进行了更新,可以参考我们的 ChangeLog

Release 3.17.0

· 3 minute read
Harry Chen
Maintainer of Midway

升级请参考 如何更新 Midway 中描述,请不要单独升级某个组件包。

本次 3.17 版本,我们增加了一些新的特性,以及修复了一些问题,主要有:

  • 1、使用 替换原有的上传组件
  • 2、busboy 上传的数据中的 filedName,在流式模式下不再提供
  • 3、增加了一个新的服务端响应格式
  • 4、class 中间件现在可以复用了

下面是更为细节的描述。

定制服务端响应格式

在 3.17 版本中,我们增加了一个新的特性,可以定制服务端的响应的通用格式。

在之前的版本中,我们依靠中间件和过滤器来实现这个功能,但是这种方式有一些局限性,代码也会分散在不同的地方。

如果由一个统一的可调整的返回逻辑,可能更为合理,为此,添加了 ServerResponseHttpServerResponse 的实现。

import { ServerResponse, HttpServerResponse } from '@midwayjs/core';

@Controller()
export class HomeController {
@Inject()
ctx: Context;

@Get('/')
async index() {
return new HttpServerResponse(this.ctx).json({
success: true,
data: 'hello world',
});
}
}

HttpServerResponseServerResponse 的一个 Http 实现,提供了一些常用的方法。

最为特殊的是他可以针对不同的数据格式,设置成功和失败的模版。

比如针对 JSON 数据,框架提供了以下的默认结构。

HttpServerResponse.JSON_TPL = (data, isSuccess) => {
if (isSuccess) {
return {
success: 'true',
data,
};
} else {
return {
success: 'false',
message: data || 'fail',
};
}
};

这样,当返回 JSON 格式时,就会按照这个模版进行返回。

// 失败的返回
return new HttpServerResponse(this.ctx).fail().json('hello world');

就会获取到以下的数据。

{
success: 'false',
message: 'hello world',
}

此外,基于这个模式,也同时实现了 SSE 的响应返回,也有其他的一些数据结构的返回,更多的内容,请参考 细节文档

上传组件

由于在小文件场景下上传碰到一些问题,从 v3.17 开始,基于 busboy 实现了一个新的上传组件,替换原有的 @midwayjs/upload

和原有的组件比有一些不同。

  • 1、不再默认加载中间件,因为上传只是少部分接口的特殊逻辑,不需要全局加载
  • 2、配置的 key 为了避免冲突,从 upload 变为 busboy

其余的使用方式和原有的上传组件一致,

更多细节请访问 文档

类中间件复用

在之前,如果需要复用中间件,只能使用函数中间件。

const mw = (ctx, next) => {
// ...
}

@Controller(/**/)
export class HomeController {

@Get('/', { middleware: [mw]})
async home() {}

@Get('/api', { middleware: [mw]})
async api() {}
}

但是如果希望用上继承,或者 matchignore 功能的,则是类的行为更为方便。

这个版本框架提供了 createMiddleware 功能,保留原有的逻辑同时,可以创建出一个新的中间件实例。


@Middleware()
export class ReportMiddleware implements IMiddleware<Context, NextFunction> {
// ...
}

@Controller(/**/)
export class HomeController {

@Get('/', { middleware: [createMiddleware(ReportMiddleware, {}, 'name1')]})
async home() {}

@Get('/api', { middleware: [createMiddleware(ReportMiddleware, {}, 'name2')]})
async api() {}
}

通过向 createMiddleware 传递不同的参数,以及中间件名字,就可以引用到不同的逻辑。

更多的细节,请查看 Web中间件 文档。

更多的变化

  • 修复了一个多语言匹配 key 的问题
  • 一些不合理类型定义的调整

以及一大批依赖进行了更新,可以参考我们的 ChangeLog