Express应用部署Vercel后运行异常,求ES模块兼容方案
问题:Express部署Vercel成功但无法运行,ES模块与CommonJS冲突错误
部署Express应用到Vercel时,部署流程显示完全成功,但应用无法正常访问。实时日志中出现以下错误:
[GET] / 15:20:13:01 2023-01-15T14:20:13.416Z undefined ERROR Uncaught Exception {"errorType":"ReferenceError","errorMessage":"require is not defined in ES module scope, you can use import instead\nThis file is being treated as an ES module because it has a '.js' file extension and '/var/task/package.json' contains \"type\": \"module\". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.","stack":["ReferenceError: require is not defined in ES module scope, you can use import instead","This file is being treated as an ES module because it has a '.js' file extension and '/var/task/package.json' contains \"type\": \"module\". To treat it as a CommonJS script, rename it to use the '.cjs' file extension."," at file:///var/task/___now_launcher.js:1:18"," at ModuleJob.run (node:internal/modules/esm/module_job:193:25)"," at async Promise.all (index 0)"," at async ESMLoader.import (node:internal/modules/esm/loader:530:24)"," at async _tryAwaitImport (file:///var/runtime/index.mjs:921:16)"," at async _tryRequire (file:///var/runtime/index.mjs:970:37)"," at async _loadUserApp (file:///var/runtime/index.mjs:994:16)"," at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)"," at async start (file:///var/runtime/index.mjs:1200:23)"," at async file:///var/runtime/index.mjs:1206:1"]}
项目结构
my-app/ ├─ package.json ("type": "module") ├─ vercel.json ├─ /routes ├─ /models ├─ /middleware ├─ index.js ├─ client/ │ ├─ create react app
相关代码
index.js
import express from 'express' import dotenv from "dotenv" import bodyParser from "body-parser" import cookieParser from "cookie-parser" import mongoose from "mongoose" import auth from "./routes/auth.js" import products from "./routes/products.js" import categories from "./routes/category.js" import rateLimit from 'express-rate-limit' import cart from "./routes/cart.js" import order from "./routes/order.js" import checkout from "./routes/checkout.js" import cors from "cors" import path from "path" dotenv.config(); const app = express(); const PORT = process.env.PORT || 8888; const DATABASE_URL = process.env.DATABASE_URL const limiter = rateLimit({ windowMs: 60 * 1000, max: 100, standardHeaders: true, legacyHeaders: false, }) app.use(express.static(path.resolve(process.cwd(), "client", "build"))); app.use(limiter) app.use(cors()) app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); app.use(cookieParser()); app.use("/api/", products) app.use("/api/products/", categories) app.use("/api/",auth) app.use("/api/", cart) app.use("/api/", order) app.use("/api/", checkout) app.get("*", (_, res) => { res.sendFile( path.join(process.cwd(), "./client/build/index.html"), (err) => { if(err) { console.log(err) res.status(500).send(err) } } ) }) mongoose.set('strictQuery', false) mongoose.connect(DATABASE_URL, () => { console.log("Mogoose connected") }) app.listen(PORT, () => console.log("Server is running"))
vercel.json
{ "version": 2, "builds": [ { "src": "index.js", "use": "@vercel/node" } ], "routes": [ { "src": "/(.*)", "dest": "index.js" } ] }
解决方案(无需替换import为require)
1. 调整index.js导出应用实例
Vercel的Node函数不需要手动启动服务器(app.listen()),而是需要导出Express应用实例供平台托管。修改index.js:
- 删除或注释掉
app.listen(PORT, () => console.log("Server is running")) - 在文件末尾添加
export default app;
修改后的index.js末尾部分:
mongoose.set('strictQuery', false) mongoose.connect(DATABASE_URL, () => { console.log("Mogoose connected") }) // 移除app.listen,添加导出 export default app;
2. 更新vercel.json指定ES模块兼容的运行时
在builds配置中添加config字段,指定支持ES模块的Node.js版本(如nodejs18.x及以上),确保Vercel正确处理ES模块语法:
{ "version": 2, "builds": [ { "src": "index.js", "use": "@vercel/node", "config": { "runtime": "nodejs18.x" } } ], "routes": [ { "src": "/(.*)", "dest": "index.js" } ] }
3. 验证路由文件一致性
确保所有路由、模型、中间件文件都使用import语法,且文件后缀为.js(因package.json中"type": "module"已声明.js文件为ES模块)。
原理说明
错误源于Vercel的启动器尝试用CommonJS的require加载你的ES模块代码,而package.json的"type": "module"声明导致加载冲突。通过指定兼容ES模块的Node.js运行时,并导出应用实例让Vercel托管服务,即可在保留import语法的前提下解决问题。
内容的提问来源于stack exchange,提问作者Ben Allal
相关产品推荐
相关产品推荐

