You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NestJS项目中正确导入map-obj库?

NestJS+TypeScript兼容ESM库map-obj的解决方案

问题背景

项目使用commonjs模块配置,导入纯ESM的map-obj库时触发以下错误:

/Users/alexs/Documents/projects/xml-controller-test/dist/app.controller.js:20
const map_obj_1 = require("map-obj");
                  ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/alexs/Documents/projects/xml-controller-test/node_modules/map-obj/index.js from /Users/alexs/Documents/projects/xml-controller-test/dist/app.controller.js not supported.
Instead change the require of index.js in /Users/alexs/Documents/projects/xml-controller-test/dist/app.controller.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/Users/alexs/Documents/projects/xml-controller-test/dist/app.controller.js:20:19)

尝试在package.json添加"type": "module"后,又出现CommonJS兼容错误:

ReferenceError: exports is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/Users/alexs/Documents/projects/xml-controller-test/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.

解决方案

第一步:移除package.json中的"type": "module"

该配置会将项目所有.js文件视为ESM模块,但NestJS编译后的代码为CommonJS格式,使用了exports语法,因此会引发冲突,必须移除。

方案一:异步动态导入(无配置修改)

在需要使用map-obj的异步上下文(如生命周期钩子、请求处理方法)中使用动态导入,确保在调用前完成模块加载:

在服务中预加载模块

import { Injectable, OnModuleInit } from '@nestjs/common';

@Injectable()
export class AppService implements OnModuleInit {
  private mapObject: typeof import('map-obj').default;
  private mapObjectSkip: typeof import('map-obj').mapObjectSkip;

  async onModuleInit() {
    const mapObjModule = await import('map-obj');
    this.mapObject = mapObjModule.default;
    this.mapObjectSkip = mapObjModule.mapObjectSkip;
  }

  transformData(input: Record<string, any>) {
    return this.mapObject(input, (key, value) => {
      if (value === undefined) {
        return [key, this.mapObjectSkip];
      }
      return [key.toLocaleUpperCase(), value];
    });
  }
}

在控制器方法中直接导入

import { Controller, Post, Body } from '@nestjs/common';

@Controller('data')
export class DataController {
  @Post('transform')
  async transform(@Body() input: Record<string, any>) {
    const { default: mapObject, mapObjectSkip } = await import('map-obj');
    return mapObject(input, (key, value) => {
      return value === null ? [key, mapObjectSkip] : [key, value * 2];
    });
  }
}

方案二:调整TypeScript配置(自动兼容ESM)

修改tsconfig.json的模块配置,让TypeScript自动处理CommonJS与ESM的交互:

{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    // 保留原有配置,如target、outDir、strict等
  }
}

此配置下,TypeScript会根据模块的类型自动生成对应的导入代码(ESM模块用动态import()),无需手动修改导入语句,原import mapObject, { mapObjectSkip } from 'map-obj';可正常使用。

注意:需确保NestJS版本在9.x及以上,该版本已支持NodeNext模块配置。

内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 01:49:54