Skip to content

ERR_REQUIRE_ESM错误:解决ES模块导入问题

问题描述

在使用Node.js开发Discord机器人时,当你尝试通过require()方式导入node-fetch模块时,可能会遇到以下错误:

[ERR_REQUIRE_ESM]: require() of ES Module not supported

这个错误表明你正在尝试使用CommonJS的require()语法来导入一个仅支持ES模块(ECMAScript Modules)的包。

问题根源

node-fetch v3.0.0版本起,该包转变为纯ES模块包,不再支持CommonJS的require()导入方式。当你使用以下代码时会出现问题:

javascript
const fetch = require('node-fetch');

解决方案

方案一:使用ES模块导入语法(推荐)

将你的代码改为使用ES模块的import语法:

javascript
import fetch from "node-fetch";

module.exports = {
    name: 'username',
    // 其余代码保持不变
}

同时需要在package.json中添加"type": "module"字段:

json
{
    "name": "discordbot",
    "version": "1.0.0",
    "type": "module",
    "main": "main.js",
    // 其余配置保持不变
}

注意事项

  • 设置"type": "module"后,项目中所有文件都将被视为ES模块
  • 需要使用import而不是require来导入所有包
  • 文件扩展名需要明确(如.js.mjs

方案二:降级node-fetch版本

如果你希望继续使用CommonJS语法,可以将node-fetch降级到v2.x版本:

bash
npm uninstall node-fetch
npm install node-fetch@2.6.6

这样你就可以继续使用require()语法:

javascript
const fetch = require('node-fetch');

方案三:使用动态导入

另一种解决方案是使用动态导入(dynamic import),这在CommonJS模块中是可用的:

javascript
module.exports = {
    name: 'username',
    description: "this is the username command",
    async execute(message, args) {
        // 使用动态导入
        const fetch = (await import('node-fetch')).default;
        
        // 其余代码保持不变
    }
}

动态导入的优点

  • 不需要修改package.json
  • 可以在CommonJS模块中使用ES模块
  • 按需加载,可以提高性能

方案四:使用替代HTTP客户端库

你也可以选择其他支持CommonJS的HTTP客户端库:

javascript
// 使用axios
const axios = require('axios');

// 或使用got
const got = require('got');

最佳实践建议

  1. 逐步迁移到ES模块:ES模块是JavaScript的未来标准,建议新项目直接使用ES模块

  2. 统一模块系统:避免在同一项目中混用CommonJS和ES模块

  3. 检查依赖兼容性:在升级依赖包时,注意查看其变更日志,了解是否切换到了ES模块

  4. 使用TypeScript:TypeScript提供了更好的模块系统支持和类型安全

完整代码示例

以下是使用ES模块语法的完整解决方案:

javascript
import fetch from "node-fetch";

export default {
    name: 'username',
    description: "this is the username command",
    async execute(message, args) {
        if (args.length !== 1) {
            return message.channel.send("invalid username")
        }

        const ign = args[0]

        if (ign.length > 16 || ign.length < 3) {
            return message.channel.send("invalid username")
        }

        try {
            const uuidResponse = await fetch(`https://api.mojang.com/users/profiles/minecraft/${ign}`);
            const uuidData = await uuidResponse.json();
            const uuid = uuidData.id;

            if (uuid.length !== 32) {
                return message.channel.send("Invalid UUID received");
            }

            const onlineInfoResponse = await fetch(`https://api.hypixel.net/status?key=${process.env.HYPIXEL_KEY}&uuid=${uuid}`);
            const onlineInfo = await onlineInfoResponse.json();

            if (onlineInfo.success) {
                if (onlineInfo.session.online) {
                    message.channel.send("They are online")
                } else {
                    message.channel.send("They are offline")
                }
            } else {
                message.channel.send("Hypixel API error")
            }
        } catch (error) {
            message.channel.send("An error occurred while fetching data")
            console.error(error);
        }
    }
}

总结

ERR_REQUIRE_ESM错误是由于模块系统不兼容导致的。根据你的项目需求,可以选择:

  • 迁移到ES模块(推荐用于新项目)
  • 降级node-fetch版本(适用于需要保持CommonJS的现有项目)
  • 使用动态导入(提供灵活的过渡方案)
  • 切换其他HTTP客户端库

选择最适合你项目现状的解决方案,确保代码的稳定性和可维护性。