Next.js集成Sequelize时出现Webpack依赖报错问题
问题场景
在Next.js项目的pages/api/submitAllegationApi.js文件中引入Sequelize数据模型,执行新数据条目创建操作时存在如下异常:
- 单独调用
api/submitAllegationApi接口无任何报错 - 先调用其他API路由,再调用该接口时抛出两类错误:
- Webpack警告:
Critical dependency: the request of a dependency is an expression,指向./models/index.js - 运行时错误:
MODULE_NOT_FOUND,提示找不到.next/server/pages/api/pdfcreate.js文件
- Webpack警告:
完整错误栈:
error - Error: Cannot find module '/Users/Desktop/.../.next/server/pages/api/pdfcreate.js' at webpackEmptyContext (/Users/Desktop/.../.next/server/pages/api/submitAllegationApi.js:22:10) at eval (webpack-internal:///(api)/./models/index.js:18:65) at Array.forEach () at eval (webpack-internal:///(api)/./models/index.js:17:4) at Object.(api)/./models/index.js (/Users/.../.next/server/pages/api/submitAllegationApi.js:84:1) at webpack_require (/Users/.../.next/server/webpack-api-runtime.js:33:42) at eval (webpack-internal:///(api)/./pages/api/submitAllegationApi.js:6:24) at Object.(api)/./pages/api/submitAllegationApi.js (/Users/.../.next/server/pages/api/submitAllegationApi.js:95:1) at webpack_require (/Users/.../.next/server/webpack-api-runtime.js:33:42) at webpack_exec (/Users/.../.next/server/pages/api/submitAllegationApi.js:116:39) { code: 'MODULE_NOT_FOUND' }
涉及的原始代码:
submitAllegationApi.js
const db = require('../../models/index'); const { DataTypes } = require("sequelize"); const Allegations=require("../../models/Allegations")(db.sequelize, db.Sequelize.DataTypes); export default async function handler(req, res){ var data= req.body; Allegations.create({ faculty: data.Faculty // 其余业务字段省略 }) console.log("received: "+data); res.status(200).send(data); };
Allegations模型文件
'use strict'; const { Model } = require('sequelize'); module.exports = (sequelize, DataTypes) => { class Allegations extends Model { static associate(models) { // 关联关系定义省略 } } Allegations.init({ faculty: DataTypes.STRING // 其余模型字段省略 }, { sequelize, modelName: 'Allegations', }); return Allegations; };
models/index.js
'use strict'; const fs = require('fs'); const path = require('path'); const Sequelize = require('sequelize'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; const config = require(__dirname + '/../config/config.json')[env]; const db = {}; let sequelize; if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); } else { sequelize = new Sequelize(config.database, config.username, config.password, config); } fs .readdirSync(__dirname) .filter(file => { return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); }) .forEach(file => { const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); db[model.name] = model; }); Object.keys(db).forEach(modelName => { if (db[modelName].associate) { db[modelName].associate(db); } }); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
根因定位
- 核心问题出在
models/index.js的动态加载逻辑:Sequelize CLI默认生成的代码用fs.readdirSync遍历目录+path.join拼接路径做动态require,这种写法在Node.js原生环境可以正常运行,但Next.js会用Webpack对API路由代码做静态打包,Webpack无法解析表达式形式的动态依赖路径,因此抛出关键依赖警告。 - 动态
require会让Webpack错误地将依赖解析上下文匹配到pages/api目录,当其他API路由(比如pdfcreate.js)被调用后,Webpack的上下文缓存被污染,遍历加载模型时会尝试去API目录下找文件,最终抛出模块找不到的错误。 - 额外问题:
submitAllegationApi.js中重复引入并初始化了Allegations模型,和models/index.js中已经加载的模型实例冲突,会进一步放大打包后的路径解析异常。
修复方案
1. 修改models/index.js,替换动态遍历为静态显式引入
去掉fs遍历和动态require的逻辑,手动逐个引入所有模型,让Webpack可以正常静态解析依赖路径,修改后代码如下:
'use strict'; const Sequelize = require('sequelize'); const env = process.env.NODE_ENV || 'development'; const config = require(__dirname + '/../config/config.json')[env]; const db = {}; let sequelize; if (config.use_env_variable) { sequelize = new Sequelize(process.env[config.use_env_variable], config); } else { sequelize = new Sequelize(config.database, config.username, config.password, config); } // 静态引入所有模型,替代原动态遍历逻辑 db.Allegations = require('./Allegations')(sequelize, Sequelize.DataTypes); // 其余模型按相同格式在此处引入即可 // db.XXXModel = require('./XXXModel')(sequelize, Sequelize.DataTypes); // 执行模型关联 Object.keys(db).forEach(modelName => { if (db[modelName].associate) { db[modelName].associate(db); } }); db.sequelize = sequelize; db.Sequelize = Sequelize; module.exports = db;
2. 修改submitAllegationApi.js,移除重复的模型初始化
直接从db对象中取已经初始化完成的模型实例,不要单独重复引入模型文件,修改后代码如下:
const db = require('../../models/index'); export default async function handler(req, res){ const data = req.body; // 直接使用预加载的模型,注意异步操作加await避免未捕获异常 await db.Allegations.create({ faculty: data.Faculty // 其余业务字段和原逻辑一致 }) console.log("received: ", data); res.status(200).send(data); };
可选优化(模型数量较多场景)
如果项目模型数量多,不想逐个手动写引入,可以在next.config.js中配置将models目录标记为服务端外部依赖,不经过Webpack打包处理,配置示例:
/** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config, { isServer }) => { if (isServer) { config.externals.push(function ({ request }, callback) { if (request && request.includes('/models/')) { return callback(null, 'commonjs ' + request); } callback(); }); } return config; }, } module.exports = nextConfig;
注意:该配置需要配合Next.js版本适配,显式静态引入是兼容性最稳定的方案。
内容的提问来源于stack exchange,提问作者shardul
相关产品推荐
相关产品推荐

