kangyana / daily-question

When your heart is set on something, you get closer to your goal with each passing day.
https://www.webpack.top
MIT License
3 stars 0 forks source link

【Q106】webpack 中的 code spliting 是如何动态加载 chunk 的? #106

Open kangyana opened 1 year ago

kangyana commented 1 year ago

1. 一个 webpack 的运行时,包括最重要的两个数据结构:

2. code spliting

在 webpack 中,通过 import() 可实现 code spliting。 假设我们有以下文件:

index.js

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

sum

const sum = (x, y) => x + y;
export default sum;

我们将使用以下简单的 webpack 配置进行打包,具体示例可参考 node-examples:code-spliting(opens new window)

{
  entry: './index.js',
  mode: 'none',
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: 'chunk.[name].[id].[contenthash].js',
    path: path.resolve(__dirname, 'dist/deterministic'),
    clean: true
  },
  optimization: {
    moduleIds: 'deterministic',
    chunkIds: 'deterministic'
  }
}

3. 运行时解析

通过观察打包后的文件 dist/deterministic/main.xxxxxx.js,可以发现: 使用 import() 加载数据时,以上代码将被 webpack 编译为以下代码:

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

此时 644 为 chunkId,观察 chunk.sum.xxxx.js 文件,以下为 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;

      /***/
    },
  },
]);

以下两个数据结构是加载 chunk 的关键:

实际上,在 webpack 中可配置 output.chunkLoading 来选择加载 chunk 的方式,比如选择通过 import()的方式进行加载。 (由于在生产环境需要考虑 import 的兼容性,目前还是 JSONP 方式较多)

{
  entry: './index.js',
  mode: 'none',
  output: {
    filename: 'main.[contenthash].js',
    chunkFilename: '[name].chunk.[chunkhash].js',
    path: path.resolve(__dirname, 'dist/import'),
    clean: true,
    // 默认为 `jsonp`
    chunkLoading: 'import'
  }
})

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