javascript模块加载器是什么_如何动态加载依赖

JavaScript模块加载器解决import无法运行时决定路径、按需加载及兼容非ES模块的问题;现代用import()动态导入,SystemJS用于加载AMD/UMD等旧模块,RequireJS等已过时。

JavaScript 模块加载器到底在解决什么问题

它不是语法层面的必需品,而是为了解决 import 无法在运行时决定加载路径、无法按需加载、无法兼容非 ES 模块(如 AMD、CommonJS)或无模块环境的问题。现代浏览器原生支持 import() 动态导入,但模块加载器(如 RequireJS、SystemJS、甚至 Webpack 的 runtime)提供更细粒度的控制:比如加载前重写路径、注入 polyfill、处理循环依赖、支持插件化转换(如 JSON、CSS 加载)。

import() 实现最简动态加载

这是目前标准、轻量、无需额外库的方式,返回 Promise,适用于大多数现代场景:

const loadModule = async (path) => {
  try {
    const mod = await import(path);
    return mod.default || mod;
  } catch (err) {
    console.error('动态加载失败:', err);
    throw err;
  }
};

// 使用示例
loadModule('./utils/math.js').then(math => math.add(2, 3));
  • path 必须是字符串字面量或模板字符串中的静态部分(如 `./features/${feature}.js`),不能是完全运行时拼接的变量,否则打包工具(如 Vite、Webpack)无法做静态分析和代码分割
  • 不支持直接加载 CDN 上的未配置 CORS 的脚本(会触发跨域错误),需服务端代理或确保目标资源设置 Access-Control-Allow-Origin
  • 多次 import('./x.js') 同一路径,浏览器会复用已解析/执行的模块实例,不是重复请求

SystemJS:需要兼容旧模块格式时的选择

当你必须加载 AMD、UMD 或全局变量挂载型脚本(比如某些老版 Chart.js、Lodash CDN 版),import() 无能为力,SystemJS 是少数仍维护的通用加载器:


  • 需显式配置 System.config({ map, packages }) 才能处理相对路径、版本别名或包入口
  • 不推荐用于新项目 —— 它增加体积(~15KB gzip)、启动慢、与现代构建工具链割裂
  • 常见坑:System.import 不是 Promise A+ 兼容实现,某些版本 resolve 值不统一;CDN 加载的模块若依赖其他 UMD 模块,需提前 System.register 声明依赖

为什么不用 RequireJS 或 SeaJS 了

它们是 AMD 规范时代的产物,核心逻辑基于 define/require 回调,而现代开发中:

立即学习“Java免费学习笔记(深入)”;

  • ES 模块已是语言标准,import() 原生支持,无需学习新 API
  • 打包工具(Vite、Rollup、Webpack)内置代码分割,import() 能自动产出独立 chunk,RequireJS 的 require(['a','b'], cb) 在构建期无法优化
  • RequireJS 的 shim 配置容易出错:比如漏写 exports 导致模块值为 undefined,或 deps 顺序错乱引发执行时序问题
  • 几乎所有主流 UI 库(React、Vue、Svelte)及其生态都已转向 ESM 发布,RequireJS 加载它们需大量胶水代码

真正需要动态加载的复杂场景(如微前端、插件系统),通常用自定义 loader + import() 封装,而不是引入整套历史加载器。