当任何动态导入无法加载文件时,如何手动加载 webpack 异步块?

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));

Ayu*_*hya 9

我有两个解决方案:

1. 需要用重试函数包装块 import() 。

您可以在最终失败之前编辑 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)

2. 可以使用webpack-retry-chunk-load-plugin

这个插件唯一的警告是它将重试次数限制为 1。但它节省了开发人员在每次动态导入时进行更改的时间。

希望这可以帮助。