如何通过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
相关产品推荐
相关产品推荐

