Skip to content

midway2.x 深度躺坑记(持续更新)

Vern Brandl edited this page Mar 1, 2021 · 5 revisions

前言

小编曾是 Koa 的 Contributor。也基于 Koa 自己搭建过 Web 框架,整过亿级流量的服务,单台4核8G机器 QPS 去到15000(前面就简单水一下……^_^)

从 egg.js 1.x 到 egg.js 2.x 再到 midway 1.x midway 2.x 一路玩过来,颇有些波折。今天主要记录下从 midway 1.x 到 midway 2.x 迁移到一些坑点。 同时这个仓库会有 midway1.x midway2.x 到一些实践。

目录别名映射

在 JS/TS 项目中,我们都喜欢配置路径别名,以便于深层减少 ../../ 都使用,使得 import 的时候,代码显得更简洁一些。 在 midway 1.x 中,按照官方文档在 tsconfig.json 中配置了 paths 无效 配置即可

而在 midway 2.x 中,情况有些变化,项目启动最先加载的文件不再是 plugin.ts 而是 configuration.ts。 所以更改配置的位置即可

src/configuration.ts

// eslint-disable-next-line node/no-unpublished-import
import 'tsconfig-paths/register';
.
.
.

config 中 match 和 ignore 不生效

在 midway 1.x 中,基于 egg.js 作为下层框架,在中间件配置里面,可以设置 match/ignore 对特殊的路径进行启用/屏蔽操作 src/config/config.default.ts

  config.jwt = {
    enable: true,
    client: {
      secret: '123456',
    },
    ignore: ['/auth/login', '/ping'],
  }

注意事项

npm run test的时候,这个配置是无效的。需要在项目根目录建立一个文件 jest.config.js,指定moduleNameMapper的配置 内容如下:

const path = require('path');

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
  coveragePathIgnorePatterns: ['<rootDir>/test/'],
  moduleNameMapper: {
    "^@/(.*)$": '<rootDir>src/$1'
  }
};

如上,在 midway 2.x 中是不起作用的。原因 midwayjs/packeges/web/app.js#didLoad 这个函数没有写这块逻辑。

将 midway 依赖版本更新到2.3.12后可以解决这问题。下面是核心代码 midway/packages/web/app.js#L19

  async didLoad() {
    // 这里的逻辑是为了兼容老 cluster 模式
    if (this.app.options['isClusterMode'] !== false) {
      this.framework = new Framework().configure({
        processType: 'application',
        app: this.app,
        globalConfig: this.app.config,
      });
      Bootstrap.configure({
        baseDir: this.app.appDir,
      }).load(this.framework);
      await Bootstrap.run();
      this.app.options['webFramework'] = this.framework;
    }

    // 等 midway 加载完成后,再去 use 中间件
    for (const name of this.appMiddleware) {
      if (this.app.getApplicationContext().registry.hasDefinition(name)) {
        const mwIns = await this.app.generateMiddleware(name);
        this.app.use(mwIns);
      } else {
        // egg
        const options = this.app.config[name];
        if (options.enable === false) {
          continue;
        }
        // support options.match and options.ignore
        const mw = this.app.middlewares[name](options);
        if (!options.match && !options.ignore) {
          this.app.use(mw);
        } else {
          const match = pathMatching(options);
          const fn = (ctx, next) => {
            if (!match(ctx)) return next();
            return mw(ctx, next);
          };
          fn._name = mw._name + 'middlewareWrapper';
          this.app.use(fn);
        }
      }
    }
  }

特别注意的一点,如果有自定义的中间件,在 config.middleware 中使用时,如果没有为该中间件配置 enable 属性,启动是会抛错的。截止2020/10/13日小编已经修复该问题,查看PR: fix: when middleware config options is undefined, options.match

FFA7A25C-F1A0-4BFA-8B33-1FBD6D63E260

midway 启动报错

出现错误

TypeError: Cannot convert undefined or null to object
95828391-850dd180-0d67-11eb-95ec-196f66596de1

出现这个问题的原因是,受 @midwayjs/orm 依赖到影响,@midwayjs/core 内声明的 MidwayFrameworkType 在依赖包安装到 node_modules 后,由于内外包到引用问题,为 undefined. (也就是说没有安装到正确到版本)

95828998-42002e00-0d68-11eb-85ab-3ec69bdb38ea

不过该问题现在已经修复了。


以下2020年12月21日更新

最近发现 midway2.x 在 Node.js 10.x 版本跑 CI 会经常丢失 applicationContext,如果你正在使用 Node.js 10.x 的版本,建议升级使用最新的 LTS 版本。排查该问题后,会在文章更新最新的状态。