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

MERN项目CommonJS适配query-string的报错解决方法

问题描述

遇到 ERR_REQUIRE_ESM 错误,提示无法使用 require() 导入ES模块 query-string,需要改为动态 import()。

错误信息

C:\Users\MRPla\Downloads\CourseGuccho\edemy\server\controllers\instructor.js:1
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\MRPla\Downloads\CourseGuccho\edemy\server\node_modules\query-string\index.js not supported.
Instead change the require of index.js in null to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (C:\Users\MRPla\Downloads\CourseGuccho\edemy\server\controllers\instructor.js:2:21)
    at Generator.next (<anonymous>)
    at Object.<anonymous> (C:\Users\MRPla\Downloads\CourseGuccho\edemy\server\routes\instructor.js:1)
    at Generator.next (<anonymous>)
    at C:\Users\MRPla\Downloads\CourseGuccho\edemy\server\server.js:33:52
    at Array.map (<anonymous>)
    at Object.<anonymous> (C:\Users\MRPla\Downloads\CourseGuccho\edemy\server\server.js:33:25)
    at Generator.next (<anonymous>) {
  code: 'ERR_REQUIRE_ESM'
}
[nodemon] app crashed - waiting for file changes before starting...

相关代码文件

server>controllers>instructor.js

import User from "../models/user";
import stripe from "stripe";
import queryString from "query-string";

export const makeInstructor = async (req, res) => {
  try {
    // 1. find user from db
    const user = await User.findById(req.user._id).exec();
    // 2. if user dont have stripe_account_id yet, then create new
    if (!user.stripe_account_id) {
      const account = await stripe.accounts.create({ type: "express" });
      // console.log('ACCOUNT => ', account.id)
      user.stripe_account_id = account.id;
      user.save();
    }
    // 3. create account link based on account id (for frontend to complete onboarding)
    const accountLink = await stripe.accountLinks.create({
      account: user.stripe_account_id,
      refresh_url: process.env.STRIPE_REDIRECT_URL,
      return_url: process.env.STRIPE_REDIRECT_URL,
      type: "account_onboarding",
    });
    //   console.log(accountLink)
    // 4. pre-fill any info such as email (optional), then send url resposne to frontend
    accountLink = Object.assign(accountLink, {
      "stripe_user[email]": user.email,
    });
    // 5. then send the account link as response to fronend
    res.send(`${accountLink.url}?${queryString.stringify(accountLink)}`);
  } catch (err) {
    console.log("MAKE INSTRUCTOR ERR ", err);
  }
};

server>routes>instructor.js

import express from "express";

const router = express.Router();

// middleware
import { requireSignin } from "../middlewares";

// controllers
import { makeInstructor } from "../controllers/instructor";

router.post("/make-instructor", requireSignin, makeInstructor);

module.exports = router;

server>server.js

import express from "express";
import cors from "cors";
import { readdirSync } from "fs";
import mongoose from "mongoose";
import csrf from "csurf";
import cookieParser from "cookie-parser";
const morgan = require("morgan");
require("dotenv").config();

const csrfProtection = csrf({ cookie: true });

// create express app
const app = express();

// db
mongoose
  .connect(process.env.DATABASE, {
    useNewUrlParser: true,
    useFindAndModify: false,
    useUnifiedTopology: true,
    useCreateIndex: true,
  })
  .then(() => console.log("**DB CONNECTED**"))
  .catch((err) => console.log("DB CONNECTION ERR => ", err));

// apply middlewares
app.use(cors());
app.use(express.json());
app.use(cookieParser());
app.use(morgan("dev"));

// route
readdirSync("./routes").map((r) => app.use("/api", require(`./routes/${r}`)));
// csrf
app.use(csrfProtection);

app.get("/api/csrf-token", (req, res) => {
  res.json({ csrfToken: req.csrfToken() });
});

// port
const port = process.env.PORT || 8000;

app.listen(port, () => console.log(`Server is running on port ${port}`));

服务端package.JSON文件

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon -r esm server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "aws-sdk": "^2.1285.0",
    "bcrypt": "^5.1.0",
    "cookie-parser": "^1.4.6",
    "cors": "^2.8.5",
    "csurf": "^1.11.0",
    "dotenv": "^8.6.0",
    "esm": "^3.2.25",
    "express": "^4.18.2",
    "express-jwt": "^8.2.1",
    "jsonwebtoken": "^8.5.1",
    "mongoose": "^5.13.15",
    "morgan": "^1.10.0",
    "nodemon": "^2.0.20",
    "query-string": "^8.1.0",
    "shortid": "^2.2.16",
    "stripe": "^11.5.0"
  }
}

提问

若需将index.js的require改为所有CommonJS模块都支持的动态import(),请问具体该如何操作实现?


解决方案

方案一:使用动态import()替换静态导入

query-string@8.x是纯ES模块,无法在CommonJS环境下用静态import或require()导入,需要在使用它的函数内部动态导入:

修改server>controllers>instructor.js:

import User from "../models/user";
import stripe from "stripe";

// 移除顶部的静态import queryString from "query-string"

export const makeInstructor = async (req, res) => {
  try {
    // 动态导入query-string模块
    const queryStringModule = await import("query-string");
    // 注意:ES模块的默认导出需要通过.default获取
    const queryString = queryStringModule.default;
    
    // 1. 查询数据库中的用户
    const user = await User.findById(req.user._id).exec();
    // 2. 如果用户没有stripe_account_id,创建新账户
    if (!user.stripe_account_id) {
      const account = await stripe.accounts.create({ type: "express" });
      user.stripe_account_id = account.id;
      await user.save(); // 添加await确保数据保存完成
    }
    // 3. 创建账户链接供前端完成开户流程
    const accountLink = await stripe.accountLinks.create({
      account: user.stripe_account_id,
      refresh_url: process.env.STRIPE_REDIRECT_URL,
      return_url: process.env.STRIPE_REDIRECT_URL,
      type: "account_onboarding",
    });
    // 4. 预填用户邮箱信息(可选)
    const modifiedAccountLink = Object.assign({}, accountLink, {
      "stripe_user[email]": user.email,
    });
    // 5. 拼接链接并返回给前端
    res.send(`${modifiedAccountLink.url}?${queryString.stringify(modifiedAccountLink)}`);
  } catch (err) {
    console.log("MAKE INSTRUCTOR ERR ", err);
  }
};

方案二:降级query-string到CommonJS兼容版本

query-string@7.x及以下版本支持CommonJS语法,无需修改代码,直接降级安装:

npm uninstall query-string
npm install query-string@7.1.1

方案三:统一项目为ES模块系统

修改package.json添加"type": "module",让Node.js将所有.js文件当作ES模块处理,即可正常使用静态import:

{
  "name": "server",
  "version": "1.0.0",
  "type": "module",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon server.js" // 移除esm,Node.js原生支持ES模块
  },
  // 其他依赖保持不变
}

同时修改以下文件的CommonJS语法:

  1. server.js:
// 替换const morgan = require("morgan");
import morgan from "morgan";
// 替换require("dotenv").config();
import dotenv from "dotenv";
dotenv.config();

// 替换路由中的require
readdirSync("./routes").map(async (r) => {
  const routeModule = await import(`./routes/${r}`);
  app.use("/api", routeModule.default);
});
  1. routes/instructor.js:
// 替换module.exports = router;
export default router;

内容的提问来源于stack exchange,提问作者Sadi Mohammad Kabbo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 23:00:54