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

时间:2019-06-26 12:25:10

标签: javascript reactjs webpack lazy-loading

可以使用动态导入(例如import('./ModuleA.js');)在webpack中创建异步块,现在,如果动态块无法加载,那么我想重试从其他位置加载它们。在对问题进行了很多思考并探索了babel和webpack之后,我编写了一个babel插件,将catch子句附加到每个动态import和内部catchs子句中,然后尝试从其他位置加载块(例如,如果第一个块无法加载从CDN,然后尝试在catch子句中从服务器加载它。

要从服务器加载块,我将__webpack_public_path__更改为服务器域,然后调用 __webpack_chunk_load__(chunkId);

,只要动态导入拒绝,chunkId就会在错误对象中可用。

现在,如果我使用

,动态导入路径就会出现问题

React.lazy(() => import(/* webpackChunkName: "ModuleA" */ './ModuleA'));

React.lazy()期望返回默认的React Component导出,__webpack_chunk_load__(chunkId),通过动态注入脚本标签来加载块,但不会加载模块并返回module.exportsReact.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_chunk_load__(chunkId);来实现webpack异步块的加载,但无法调用__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));

1 个答案:

答案 0 :(得分:3)

我有两种解决方法:

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

现在按如下所示使用此功能:

// Code split without retry
React.lazy(() => import("./ModuleA"));

// Code split with retry
React.lazy(() => retry(() => import("./ModuleA")));

2。您可以使用webpack-retry-chunk-load-plugin

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

希望这会有所帮助。