Webpack 4动态导入JSON模块找不到问题求助
问题本质
你遇到的核心问题是Webpack 4对动态require的静态分析限制。当你用require(@res/level/${this.level}.json)这种写法时,Webpack在静态构建阶段没法把别名@res和动态变量this.level结合起来,正确识别到src/res/level目录下的JSON文件范围。而watch模式下修改代码会触发增量构建,Webpack会重新扫描目录,意外补上了静态分析阶段漏掉的文件,所以临时能正常加载。
具体解决方案
1. 用require.context预加载目标目录(最推荐)
这是Webpack官方推荐的批量处理动态模块的方案,提前告诉Webpack要扫描的目录和文件规则,构建时会把所有匹配的文件打包进去,运行时就能动态获取:
// 在需要加载JSON的文件顶部,创建一个上下文 const levelFiles = require.context('@res/level', false, /\.json$/); // 之后动态获取对应文件 const currentLevelData = levelFiles(`./${this.level}.json`);
参数说明:
- 第一个参数:要扫描的目录(这里用别名
@res/level没问题,Webpack能正确解析) - 第二个参数:是否递归扫描子目录(你的文件都在level根目录,设为
false即可) - 第三个参数:匹配文件的正则表达式(这里匹配所有
.json文件)
这种方式能彻底解决静态分析的问题,不管是正常构建还是watch模式都能稳定运行。
2. 静态指定目录范围,只动态替换文件名
如果你不想用require.context,可以把目录部分静态写死,只让变量替换文件名,让Webpack能静态识别到要扫描的目录:
// 确保目录部分是静态的,只动态替换文件名 require(`@res/level/${this.level}.json`);
不过这种写法依赖Webpack对别名的静态解析,有时候可能还是会出问题,不如require.context可靠。如果还是不行,可以换成相对路径:
// 用相对路径代替别名,让Webpack直接识别到目录 require(`../res/level/${this.level}.json`);
3. 优化Webpack别名与模块搜索配置
虽然你已经配置了别名,但可以补充modules配置,让Webpack优先搜索src目录,辅助静态分析:
resolve: { extensions: [".ts", ".js", ".glsl", ".json"], modules: [path.join(__dirname, 'src'), 'node_modules'], // 添加src到模块搜索路径 alias: { "@res": path.join(__dirname, "src/res"), "@lib": path.join(__dirname, "src/lib"), "@shader": path.join(__dirname, "src/shader"), "@control": path.join(__dirname, "src/control"), "@scene": path.join(__dirname, "src/scene"), "@util": path.join(__dirname, "src/util"), } }
为什么watch模式下能正常加载?
watch模式下,当你修改代码触发增量构建时,Webpack会重新扫描相关目录的文件变化,这时候它会把之前静态分析阶段没识别到的JSON文件加入到模块集合中,所以临时能加载成功,但这只是增量构建的“副作用”,正常构建时静态分析阶段没包含这些文件,就会抛出找不到模块的错误。
内容的提问来源于stack exchange,提问作者laptou

