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

React TS应用按环境变量条件导入JSON文件报错排查

问题根因说明

三类报错的核心原因

  • Import in body of module; reorder to top import/first:该报错来自ES模块规范的原生限制。ES6的import是编译时静态加载的语法,必须写在模块最顶层,不能嵌入条件判断、变量赋值等逻辑块,也不支持传入变量作为导入路径,因此这类写法从规范层面就不被允许。
  • Cannot use keyword 'await' outside an async function:该报错来自项目编译配置限制。React 18默认的脚手架配置(未手动改造webpack/babel配置的前提下)默认不支持顶层await语法,await关键字只能在被async标记的函数内部使用,直接在模块顶层调用await import()会触发语法解析错误。
  • Cannot find module '../main.json':这是最典型的打包工具静态分析问题。React项目默认基于webpack做依赖收集,webpack在编译阶段只会扫描代码中以字符串常量形式写死的路径,将对应文件加入打包产物。当你把完整路径存入变量再传给require()时,webpack编译阶段无法从变量推断出要引入的具体文件,不会把目标JSON加入打包依赖,运行时自然找不到模块。而你直接写import data from '../main.json'时,路径是明确的字符串常量,webpack能直接定位文件完成打包,因此可以正常运行。
可行实现方案

根据你的场景(无React组件的Context定义文件、TS编译目标ES2018),以下三种方案均可正常运行,按需选择即可:

方案1:静态导入所有可选JSON,条件判断取值(最推荐,零配置)

如果需要切换的JSON文件数量不多,这是最稳妥、无任何兼容问题的方案,完全符合ES模块规范,TS类型也能自动推导:

// src/contexts/world.tsx
import mainData from '../main.json';
// 导入其他WORLD环境变量取值对应的JSON文件
import devData from '../dev.json';

const data = process.env.WORLD === 'main' ? mainData : devData;

// 后续直接使用data编写Context逻辑即可

优势:不需要修改任何编译配置,打包工具能正常完成静态分析,不会出现路径解析问题,也没有异步加载的时序问题。

方案2:require保留静态路径前缀,仅可变部分使用变量

如果可选JSON文件较多,不想一次性静态导入所有文件,可以利用webpack的上下文模块机制:给require()传入至少一段固定的静态路径前缀,让webpack知道要扫描哪个目录下的对应类型文件,仅把可变的文件名/子路径部分用变量传入:

// src/contexts/world.tsx
// 仅把可变的文件名存在变量里,路径前缀写死
const fileName = process.env.WORLD === 'main' ? 'main.json' : 'dev.json';
// 注意相对路径必须是当前文件到目标目录的正确静态路径
const data = require(`../${fileName}`);

// 后续直接使用data即可

注意:该写法会让webpack把src目录下所有.json后缀的文件都加入打包依赖,如果目录下JSON文件数量极多,会小幅增加包体积,适合中等数量可选文件的场景。

方案3:封装异步逻辑使用动态import,无需顶层await

如果JSON文件体积大,想做按需加载(仅加载当前环境对应文件,减少主包体积),可以把动态import逻辑封装在async函数里,避开顶层await的限制。
如果你的文件里没有React组件,可以用立即执行函数初始化数据:

// src/contexts/world.tsx
import { createContext } from 'react';

// 先给Context设置初始值
export const WorldContext = createContext<any>(null);
let worldData: any = null;

// 用立即执行async函数包裹动态加载逻辑
(async function initData() {
  const dataModule = process.env.WORLD === 'main'
    ? await import('../main.json')
    : await import('../dev.json');
  worldData = dataModule.default;
})();

export { worldData };

注意:该写法下worldData初始值为null,文件加载完成后才会被赋值,业务侧使用时需要做好加载态判断,避免拿到空值。

避坑提醒:任何场景下都不要把完整文件路径作为纯变量传给import或require,打包工具的静态分析机制无法识别纯变量路径,必然会出现运行时找不到模块的问题。

内容的提问来源于stack exchange,提问作者gameveloster

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:42:17