跳到主要内容
版本:4.0.0 🚧

ESModule 使用指南

在过去的几年中,Node.js一直致力于支持运行 ECMAScript模块 (ESM)。这是一个很难支持的功能,因为 Node.js 生态系统的基础是建立在一个不同的模块系统,称为 CommonJS (CJS)。

两个模块系统之间的互操作带来了巨大的挑战,并具有许多功能差异。

自 Node.js v16 之后,ESM 的支持相对已经稳定,TypeScript 的一些配合功能也相继落地。

在此基础上,Midway 支持了 ESM 格式的文件加载,业务也可以使用这种全新的模块加载方式来构建自己的业务。

警告

在没有了解 ESM 前,不建议用户使用。

推荐阅读:

脚手架

由于改动较多,Midway 提供了全新的 ESM 格式的脚手架,如有 ESM 的需求,我们推荐用户重新创建后再来开发业务。

$ npm init midway@latest -y

选择 esm 分组中的脚手架。

和 CJS 项目的差异

1、package.json 的变化

package.json 中的 type 必须设置为 module

{
"name": "my-package",
"type": "module",
// ...
"dependencies": {
}
}

2、tsconfig.json 中的变化

compilerOptions 编译相关的选项需要设置为 Node16 或者 NodeNext

{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node16",
"esModuleInterop": true,
// ...
}
}

3、工具链的变化

由于原有开发工具链仅支持 CJS 代码,且社区的部分模块并没有做好 ESM 的支持,Midway 在 ESM 模式下,使用新的工具链。

  • 开发命令,使用 mwtsc (仅做了 tsc 必要的包裹)
  • 测试和覆盖率命令,使用 mocha + ts-node,同时测试代码和测试的配置都有所调整
  • 构建命令,使用 tsc

一些不再支持的功能

  • alias path,请用 Node.js 自带的 子路径导出 代替
  • 构建时非 js 文件的拷贝,将非代码文件放到 src 外部,或者在 build 时添加自定义命令

具体差异可以参考 脚手架 进行核对。

4、一些代码差异

下面快速列出一些开发中 ESM 和 CJS 的差异。

1、ts 中,import 的文件必须指定后缀名,且后缀名为 js。

import { helper } from "./foo.js"; // works in ESM & CJS

2、你不能再使用 module.exports 或者 exports. 来导出。

// ./foo.ts
export function helper() {
// ...
}
// ./bar.ts
import { helper } from "./foo"; // only works in CJS

3、你不能在代码中使用 require

只能使用 import 关键字。

4、你不能在代码中使用 __dirname__filename 等和路径相关关键字

// ESM solution
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(fileURLToPath(import.meta.url))

所有配置的部分,必须使用对象模式。

import { Configuration } from '@midwayjs/core';
import DefulatConfig from './config/config.default.js';
import UnittestConfig from './config/config.unittest.js';

@Configuration({
importConfigs: [
{
default: DefulatConfig,
unittest: UnittestConfig,
},
],
})
export class MainConfiguration {
// ...
}