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

如何通过import()与Webpack获取动态导入Bundle的进度?

如何在动态导入Webpack Bundle时获取加载进度?

原生的import()语法并没有提供加载进度的监听接口,不过可以通过以下几种方案实现进度条功能:

方案一:使用XMLHttpRequest监听加载进度

通过XHR手动加载关卡bundle,利用其onprogress事件直接获取已加载字节和总字节数,加载完成后通过动态创建script标签执行bundle代码。

function loadLevelWithProgress(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.responseType = 'blob';

    // 监听进度事件
    xhr.onprogress = (event) => {
      if (event.lengthComputable) {
        const percent = Math.round((event.loaded / event.total) * 100);
        const loadedBytes = event.loaded;
        const totalBytes = event.total;
        // 这里替换成你的进度条更新逻辑
        console.log(`加载进度:${percent}% | ${loadedBytes}/${totalBytes}字节`);
      }
    };

    xhr.onload = () => {
      if (xhr.status === 200) {
        const script = document.createElement('script');
        script.src = URL.createObjectURL(xhr.response);
        script.onload = () => {
          URL.revokeObjectURL(script.src);
          // 假设Webpack打包时将模块挂载到window对象(需配置output.libraryTarget: 'window')
          resolve(window.LevelModule);
        };
        script.onerror = reject;
        document.body.appendChild(script);
      } else {
        reject(new Error(`加载失败:${xhr.statusText}`));
      }
    };

    xhr.onerror = reject;
    xhr.send();
  });
}

// 调用示例
loadLevelWithProgress('/path/level.js')
  .then((levelModule) => {
    // 渲染新关卡
    console.log('关卡加载完成', levelModule);
  })
  .catch((error) => {
    console.error('关卡加载出错', error);
  });

配套Webpack配置调整

需要在关卡模块的Webpack配置中添加如下设置,让模块挂载到全局window对象,方便加载后获取:

// webpack.config.js
module.exports = {
  output: {
    libraryTarget: 'window',
    library: 'LevelModule' // 全局变量名,需和代码中对应
  }
};

方案二:使用Fetch API结合ReadableStream监听进度

Fetch本身没有直接的进度事件,但可以通过读取响应体的流来计算加载进度:

async function loadLevelWithFetchProgress(url) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP错误:${response.status}`);

  const contentLength = response.headers.get('Content-Length');
  if (!contentLength) throw new Error('无法获取文件总大小');
  
  const totalBytes = parseInt(contentLength, 10);
  let loadedBytes = 0;
  const chunks = [];
  const reader = response.body.getReader();

  // 逐块读取响应流,计算进度
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    chunks.push(value);
    loadedBytes += value.length;
    const percent = Math.round((loadedBytes / totalBytes) * 100);
    console.log(`加载进度:${percent}% | ${loadedBytes}/${totalBytes}字节`);
  }

  // 将读取到的块拼接成Blob并执行
  const blob = new Blob(chunks);
  const script = document.createElement('script');
  script.src = URL.createObjectURL(blob);
  
  return new Promise((resolve, reject) => {
    script.onload = () => {
      URL.revokeObjectURL(script.src);
      resolve(window.LevelModule);
    };
    script.onerror = reject;
    document.body.appendChild(script);
  });
}

// 调用示例
loadLevelWithFetchProgress('/path/level.js')
  .then(module => /* 处理关卡逻辑 */)
  .catch(err => console.error(err));

注意事项

  • 安全风险:仅加载可信的关卡bundle,避免执行不可信代码导致XSS攻击。
  • 模块导出:如果关卡模块使用ES模块语法导出,必须通过Webpack配置将其暴露到全局,否则无法在脚本执行后直接获取模块内容。
  • 兼容性:上述方案在现代浏览器中均能正常运行,若需兼容旧浏览器需添加相应的polyfill。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:57:11