极客时间对于推广渠道会有返利优惠,比如山月在极客时间买了一门课,再把课程分享给好友购买,这时极客时间会向山月返利20元左右。
而我现在做了一个返利平台,你可以在上边通过山月的链接购买课程,此时极客时间会向我返利。为了共同学习,而你可以添加我的微信 (shanyue94),我将把极客时间给我的返利发一个红包全部返给你

Code Spliting 往往归为两个方面:

  1. 通过 splitChunksPlugin 提取公共子模块,把第三方模块打包为 vendor.js。一般被称作 Bundle Spliting
  2. 通过 import() 动态加载模块,进行按需加载。一般被称作 Code Spliting

Code Spliting 可显著提升首页性能:

  1. 在单页应用中,你只需加载当前路由的 chunk (及运行时代码),当进行路由跳转时,再对其它路由页面的 chunk 进行按需加载。
  2. 在加载 jspdfecharts 等较大体积库时,可使用 Code Spliting 进行懒加载,显著减小首页打包体积。

那在打包工具的视角,import() 的懒加载是如何做到的呢?请往下看。

# Code Spliting

webpack 下,当使用动态 import() 时,会生成一个 chunk,被成为 code spliting

import('./sum').then(m => {
  m.default(3, 4)
})

// 以下为 sum.js 内容
const sum = (x, y) => x + y
export default sum

以上代码在 webpack 中会被编译为:

__webpack_require__.e(/* import() | sum */ 644).then(__webpack_require__.bind(__webpack_require__, 709)).then(m => {
  m.default(3, 4)
})

而每一个 chunk 的代码如下,以下为 sum 函数所构建而成的 chunk:

"use strict";
(self["webpackChunk"] = self["webpackChunk"] || []).push([[644],{

/***/ 709:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

        __webpack_require__.r(__webpack_exports__);
        /* harmony export */ __webpack_require__.d(__webpack_exports__, {
        /* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)
        /* harmony export */ });
        const sum = (x, y) => x + y

/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (sum);


/***/ })

}]);
  1. __webpack_require__.e: 加载 chunk,此处加载 644 的 chunk
  2. self["webpackChunk"].push: JSONP callback,用以收集 modules,如此处收集的 moduleId 为709

# __webpack_require__.e: webpack 如何加载一个 chunk?

// 当前已加载的 chunk
const installedChunks = {
  // 标明 chunk 108 已加载成功
  108: 0
}

__webpack_require.e = chunkId => {
  return __webpack_require__.f.j(chunkId)
}

// JSONP chunk loading for javascript
__webpack_require__.f.j = chunkId => {
  let installedChunkData = []
  installChunks[chunkId] = installedChunkData

  const promise = new Promise((resolve, reject) => installedChunkData = [resolve, reject])
  installedChunkData.push(promise)

  const url = __webpack_require__.p + __webpack_require__.u(chunkid)
  const done = (error) => { installedChunkData[1](error) }
  __webpack_requie__.l(url, done, key, chunkId)
}

__webpack_require__.u = (chunkId) => {
  return "" + chunkId + "." + {"40":"e82f3a1c151a3561fcf2","644":"6dd015eb5522909537df"}[chunkId] + ".chunk.js";
}

__webpack_require__.l = (url, done, key, chunkId) => {
  const script = document.createElement('script')
  script.src = url
  script.onload = () => done()
  script.onerror = (error) => done(error)
}

# __webpac_require__.push: webpack 如何收集 chunk 的依赖?

// install a JSONP callback for chunk loading
__webpack_require__.push = function webpackJsonpCallback (data) {
  const [chunkIds, moreModules] = data;
  if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
	for(moduleId of Object.keys(moreModules)) {
    __webpack_require__.m[moduleId] = moreModules[moduleId]
	}
  for(let i = 0; i < chunkIds.length; i++) {
    chunkId = chunkIds[i]

    // 当执行万 JSONP callback 后,进行 resolve,表示 chunk 已加载完成
    installedChunks[chunkId][0]()
    // 赋值为 0,标明当前 chunk 已加载
    installedChunks[chunkId]] = 0
  }
}
}

可在 webpack 运行时代码 (opens new window) 中查看加载一个 chunk 的实现。

关于山月

我的项目:
我的微信:shanyue94,欢迎交流
Last Updated: 7/21/2019, 11:25:08 AM