应将配置加载从顶层IIFE改为可调度的运行时触发点,封装为loadConfig()函数由主应用主动调用,配合注册预加载、路由守卫等业务时机注入,并做好超时降级与兜底处理。

直接用 async IIFE 在模块加载前注入全局配置,行不通——它无法真正“提前”执行,也不符合模块加载时序。真正的做法是:把配置加载逻辑从“顶层立即执行”转向“可调度、可等待、可降级”的运行时触发点,让异步配置成为模块初始化的前置依赖,而非试图在 import 之前“抢跑”。
配置加载必须脱离模块顶层执行
ES 模块规范规定:所有 import 语句(包括动态 import)都必须在模块执行上下文中调用,不能出现在模块顶层的同步代码中。所谓“加载前夜”本质是误解——没有真正的“前夜”,只有“首次业务触发时刻”。因此:
- 禁止写
(async () => { await fetchConf(); })()在模块顶层,会报 SyntaxError 或被构建工具忽略 - 配置加载应封装为函数(如
loadConfig()),由主应用在明确时机(如路由就绪、App 初始化完成)主动调用 - 该函数返回 Promise,后续模块可通过
await loadConfig()确保配置就绪后再执行自身逻辑
用注册+预加载机制替代硬编码 IIFE
不靠匿名函数抢跑,而是用可管理的注册机制让配置“静默就位”:
- 定义一个
ConfigRegistry,支持register('theme', () => import('./conf/theme.js')) - 主入口不立即执行,而是调用
registry.loadAll()—— 它并发发起所有配置请求,但不阻塞主流程 - 配合 webpack 的
/* webpackPrefetch: true */注释,让浏览器在空闲时预加载配置模块,真正需要时已缓存就绪 - 组件或模块内部通过
useConfig().theme.color访问,背后是响应式 store 或 Context,自动等待配置 resolve
关键节点注入:路由守卫 / 组件挂载 / 权限校验后
所谓“动态注入”,实际发生在真实业务上下文里:
- Vue Router 中:
router.beforeEach(async (to) => { await loadTenantConfig(to.meta.tenantId); }) - React 中:
useEffect(() => { loadUserPrefs().then(setPrefs); }, []); - 小程序 App.onLaunch 内:
this.configPromise = loadGlobalConf();,页面 onLoad 里await app.configPromise - 所有加载都包裹
try/catch+ 超时控制(如Promise.race([load(), timeout(2000)])),失败则 fallback 到 base 配置,不中断渲染
模块内按需消费配置,不强耦合加载时机
业务模块不该自己拉配置,而应假设配置已就绪或提供 fallback:
- 埋点模块导出
init({ config }),由宿主传入已 resolve 的配置对象 - UI 组件用
const { theme } = useConfig() || { theme: { primary: '#333' } },避免因配置未到白屏或报错 - 构建时用
import(/* webpackMode: "eager" */ './base.conf.js')加载兜底配置,确保即使异步失败也有可用值
不复杂但容易忽略:所谓“动态注入”,不是靠函数名唬人,而是把加载时机从“静态声明”移到“业务驱动”,把错误处理从“抛异常”换成“静默降级”,把依赖关系从“隐式等待”变成“显式 await”。

















