edi*_*y17 1 javascript lazy-loading reactjs webpack
webpack 中的异步块可以通过使用动态导入(例如import('./ModuleA.js');)创建,现在如果动态块无法加载,那么我想重试从其他位置加载它们。在思考了很多问题并探索了 babel 和 webpack 之后,我编写了一个 babel 插件,将 catch 子句附加到每个动态导入和内部 catches 子句中,我尝试从其他位置加载块(例如,如果第一个块加载失败来自 CDN,然后我会尝试在 catch 子句中从服务器加载它)。
要从服务器加载块,我更改__webpack_public_path__为服务器域,然后调用
__webpack_chunk_load__(chunkId);
,chunkId 在动态导入拒绝时在错误对象中可用。
现在,如果我正在使用动态导入路由,则会出现问题
React.lazy(() => import(/* webpackChunkName: "ModuleA" */ './ModuleA'));
React.lazy()预计要返回阵营组件的默认出口__webpack_chunk_load__(chunkId),负载块通过动态注入脚本标签,但它不会加载模块,并返回module.exports其被需要React.lazy()。
在内部,
React.lazy(() => import(/* webpackChunkName: "ModuleA" */ './ModuleA'));
将被 webpack 转换为以下代码,
react__WEBPACK_IMPORTED_MODULE_5___default.a.lazy(function () {
return Promise.resolve(__webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./ModuleA */ "./src/ModuleA.js")))
});
现在,如您所见__webpack_require__.bind(null, /*! ./ModuleA */ "./src/ModuleA.js"),返回 module.exports。
我能够实现,使用 加载 webpack 异步块__webpack_chunk_load__(chunkId);,但不能调用 __webpack_require__.bind(null, /*! ./ModuleA */ "./src/ModuleA.js"),因为__webpack_require__需要 moduleId 这在此处不可用。
有没有办法在 webpack 中手动加载动态块?或者我怎么能moduleId打电话__webpack_require__.bind(null, /*! ./ModuleA */ "./src/ModuleA.js")
此外,这是实现它的正确方法,很高兴看到任何其他方法。
我在 catch 子句中使用以下代码,
filePath = error.request;
var chunkId = error.message.substring(error.message.indexOf('chunk') + 6 , error.message.indexOf('failed.') - 1);
return Promise.resolve(window.chunkLoad(chunkId)).then(window.webpackRequire.bind(null, window.dynamicModule));
您可以在最终失败之前编辑 5 次重试的默认值。
function retry(fn, retriesLeft = 5, interval = 1000) {
return new Promise((resolve, reject) => {
fn()
.then(resolve)
.catch((error) => {
setTimeout(() => {
if (retriesLeft === 1) {
// reject('maximum retries exceeded');
reject(error);
return;
}
// Passing on "reject" is the important part
retry(fn, retriesLeft - 1, interval).then(resolve, reject);
}, interval);
});
});
}
Run Code Online (Sandbox Code Playgroud)
现在使用这个函数如下:
// Code split without retry
React.lazy(() => import("./ModuleA"));
// Code split with retry
React.lazy(() => retry(() => import("./ModuleA")));
Run Code Online (Sandbox Code Playgroud)
这个插件唯一的警告是它将重试次数限制为 1。但它节省了开发人员在每次动态导入时进行更改的时间。
希望这可以帮助。