Webpack-CodeSplit(按需加载)

Webpack-CodeSplit(动态文件篇)

在静态文件处理代码切割时,我们提到了如何处理vendor以及manifest的分离,那么抛开这两点,如果在业务逻辑中,我们如何做到代码最小加载,让浏览器加载效率提速呢,这里我们就利用了webpack codesplit的另一个特性,代码按需加载打包实践方案,webpack真的是太牛逼了,推荐各位看看原码,看看打包思路以及代码实现方式。

常规实践

import foo from './foo';
import bar from './bar';

我们要使用foo,或者bar时候。我们通常按照上述方式引用,构建的效果(没有manifest)

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([
  ["app"],
  {
    /*foo*/ CKuZ: function (module, __webpack_exports__, __webpack_require__) {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      __webpack_exports__["default"] = {
        test: "111",
      };
    },
    /*入口文件*/ fhko: function (module, __webpack_exports__, __webpack_require__) {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      var _foo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("CKuZ");
      var _bar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("tRux");
    },
    /*bar*/ tRux: function (module, __webpack_exports__, __webpack_require__) {
      "use strict";
      __webpack_require__.r(__webpack_exports__);
      __webpack_exports__["default"] = function () {
        console.log("this is bar");
      };
    },
  },
  [["fhko", "manifest"]],
]);

三个文件分配了三个名称,入口文件以webpack规则"webpack_require_"模块加载bar跟foo,从bundle中很清晰的看到三个文件彼此的规则,至于怎么调用的,就看manifest输出文件吧,简单来讲,就是遍历 window["webpackJsonp"] ,然后挨个记录到modules中,并执行。重点来了,我们不一定非要引入foo,跟bar呢,按需求引入呢,比如一个button触发的回调函数,比如路由的正则匹配路径渲染呢。还需要浏览器一并加载吗?并不是,写法如下。

import("./foo")
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e);
  });

setTimeout(function () {
  import("./bar")
    .then((res) => {
      console.log(res);
    })
    .catch((e) => {
      console.log(e);
    });
}, 3000);

采用动态加载的方式,按需引入目标组件。我们看下效果

 三秒之后出现

达到了我们的目的。这样做可以减少浏览器加载js的体积,从而提升页面效率。

bundle.js

(window["webpackJsonp"] = window["webpackJsonp"] || []).push([["app"],{
 "fhko": (function(module, exports, __webpack_require__) {
__webpack_require__.e(/*! import() */ 1).then(__webpack_require__.bind(null, /*! ./foo */ "CKuZ"))
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e);
  });
setTimeout(function () {
  __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./bar */ "tRux"))
    .then((res) => {
      console.log(res);
    })
    .catch((e) => {
      console.log(e);
    });
}, 3000);
/***/ })
},[["fhko","manifest"]]]);

通过webpackRequire加载动态文件。

webpackRequire实现方式,这里做了一个简化版

__webpack_require__.e = function requireEnsure(chunkId) {
    var promises = [];
    var promise = new Promise(function (resolve, reject) {
      installedChunkData = installedChunks[chunkId] = [resolve, reject];
    });
    promises.push((installedChunkData[2] = promise));
    var script = document.createElement("script");
    var onScriptComplete;

    script.charset = "utf-8";
    script.timeout = 120;
    if (__webpack_require__.nc) {
      script.setAttribute("nonce", __webpack_require__.nc);
    }
    script.src = jsonpScriptSrc(chunkId);
    document.head.appendChild(script);
    return Promise.all(promises);
  }; 

加载的目标文件写入head,浏览器引入目标文件,然后返回promise数组。还是很容易理解的。

webpack输出文件列表

 看上去有点迷~如何改进下,至少让我们知道哪个文件是哪个啊,不能阿拉伯数字啊,改进如下

import(/* webpackChunkName: "foo" */ "./foo")
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e);
  });

setTimeout(function () {
  import(/* webpackChunkName: "bar" */ "./bar")
    .then((res) => {
      console.log(res);
    })
    .catch((e) => {
      console.log(e);
    });
}, 3000);

输入文件列表

这回清晰了很多。

除了import可以实现动态加载,常用的方式还有require.ensure方式。有兴趣的可以自己实践一下。

此特性好处

按需加载,提高浏览器加载脚本文件速度,减少一次性加载的体积。

此特性优化场景

  • 微前端架构设计,工程级别懒加载

  • 模块路由按需加载

  • 页面业务需求按需加载

好处还是大大滴,希望有性趣的可以自己实践一下,毕竟优化才是王道啊。

 

 

 

原文地址:https://www.cnblogs.com/moran1992/p/12882623.html