Webpack 中文文档(v4.15.1) 目录

webpack 代码拆分(Code Splitting)

T> 本指南继续沿用起步和管理输出中的代码示例。。请确保你至少已熟悉其中提供的示例。

代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。

有三种常用的代码分离方法:

  • 入口起点:使用 entry 配置手动地分离代码。
  • 防止重复:使用 CommonsChunkPlugin 去重和分离 chunk。
  • 动态导入:通过模块的内联函数调用来分离代码。

入口起点(entry points)

这是迄今为止最简单、最直观的分离代码的方式。不过,这种方式手动配置较多,并有一些陷阱,我们将会解决这些问题。先来看看如何从 main bundle 中分离另一个模块:

project

------------
-- ------------
-- -----------------
-- -----
-- ----
  -- --------
- -- -----------------
-- -------------

another-module.js

------ - ---- --------

------------
  ------------------ --------- ----------- - --
-

webpack.config.js

----- ---- - ---------------
----- ----------------- - ------------------------------

-------------- - -
  ------ -
    ------ -----------------
    -------- -------------------------
  --
  -------- -
    --- -------------------
      ------ ----- ----------
    --
  --
  ------- -
    --------- -------------------
    ----- ----------------------- -------
  -
-

这将生成如下构建结果:

----- --------------------
-------- ------- -----
----- -----
            -----    ----  ------                    ----- -----
  ---------------  --- --       -  ---------  -----  -----
-----------------  --- --       -  ---------  -----  -------
   --- -------------------- --- -- --- --- -------
   --- --------------------------- --- ----- --- --- -------
   --- --------------------------- --- ----- --- --- -------
   --- ----------------------- -- ----- --- -------
   --- -------------- --- ----- --- -------

正如前面提到的,这种方法存在一些问题:

  • 如果入口 chunks 之间包含重复的模块,那些重复模块都会被引入到各个 bundle 中。
  • 这种方法不够灵活,并且不能将核心应用程序逻辑进行动态拆分代码。

以上两点中,第一点对我们的示例来说无疑是个问题,因为之前我们在 ./src/index.js 中也引入过 lodash,这样就在两个 bundle 中造成重复引用。接着,我们通过使用 CommonsChunkPlugin 来移除重复的模块。

防止重复(prevent duplication)

CommonsChunkPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。让我们使用这个插件,将之前的示例中重复的 lodash 模块去除:

webpack.config.js

  ----- ---- - ---------------
- ----- ------- - ------------------
  ----- ----------------- - ------------------------------

  -------------- - -
    ------ -
      ------ -----------------
      -------- -------------------------
    --
    -------- -
      --- -------------------
        ------ ----- ----------
-     --
-     ---
-     --- -------------------------------------
-       ----- -------- -- ---- ------ ----
-     --
    --
    ------- -
      --------- -------------------
      ----- ----------------------- -------
    -
  -

这里我们使用 CommonsChunkPlugin 之后,现在应该可以看出,index.bundle.js 中已经移除了重复的依赖模块。需要注意的是,CommonsChunkPlugin 插件将 lodash 分离到单独的 chunk,并且将其从 main bundle 中移除,减轻了大小。执行 npm run build 查看效果:

----- --------------------
-------- ------- -----
----- -----
            -----       ----  ------                    ----- -----
  ---------------  --- -----       -  ---------         -----
-----------------  --- -----       -  ---------         -------
 ----------------     --- --       -  ---------  -----  ------
   --- -------------------- --- -- --- -------
   --- --------------------------- --- ----- --- -------
   --- --------------------------- --- ----- --- -------
   --- ----------------------- -- ----- --- -------
   --- -------------- --- ----- --- -------

以下是由社区提供的,一些对于代码分离很有帮助的插件和 loaders:

  • ExtractTextPlugin: 用于将 CSS 从主应用程序中分离。
  • bundle-loader: 用于分离代码和延迟加载生成的 bundle。
  • promise-loader: 类似于 bundle-loader ,但是使用的是 promises。

CommonsChunkPlugin 插件还可以通过使用显式的 vendor chunks 功能,从应用程序代码中分离 vendor 模块。

动态导入(dynamic imports)

当涉及到动态代码拆分时,webpack 提供了两个类似的技术。对于动态导入,第一种,也是优先选择的方式是,使用符合 ECMAScript 提案import() 语法。第二种,则是使用 webpack 特定的 require.ensure。让我们先尝试使用第一种……

W> import() 调用会在内部用到 promises。如果在旧有版本浏览器中使用 import(),记得使用 一个 polyfill 库(例如 es6-promisepromise-polyfill),来 shim Promise

在我们开始本节之前,先从配置中移除掉多余的 entryCommonsChunkPlugin,因为接下来的演示中并不需要它们:

webpack.config.js

  ----- ---- - ---------------
- ----- ------- - ------------------
  ----- ----------------- - ------------------------------

  -------------- - -
    ------ -
-     ------ ----------------
-     ------ -----------------
-     -------- -------------------------
    --
    -------- -
      --- -------------------
        ------ ----- ----------
-     ---
-     --
-     --- -------------------------------------
-       ----- -------- -- ---- ------ ----
-     --
    --
    ------- -
      --------- -------------------
-     -------------- -------------------
      ----- ----------------------- -------
    -
  -

注意,这里使用了 chunkFilename,它决定非入口 chunk 的名称。想了解 chunkFilename 更多信息,请查看 output 相关文档。接着,更新我们的项目,移除掉那些现在不会用到的文件:

project

------------
-- ------------
-- -----------------
-- -----
-- ----
  -- --------
- -- -----------------
-- -------------

现在,我们不再使用静态导入 lodash,而是通过使用动态导入来分离一个 chunk:

src/index.js

- ------ - ---- --------
-
- -------- ----------- -
- -------- -------------- -
-   --- ------- - -----------------------------
-
-   -- ------- --- -------- -- ---- ------
-   ----------------- - ---------------- ----------- - --
-   ------ --------- ----------------- -------- -- ---------------- -- -
-     --- ------- - -----------------------------
-
-     ----------------- - ---------------- ----------- - --
-
-     ------ -------
-
-   -------------- -- --- ----- -------- ----- ------- --- -----------
  -

- --------------------------------------
- ----------------------------- -- -
-   ------------------------------------
- --

注意,在注释中使用了 webpackChunkName。这样做会导致我们的 bundle 被命名为 lodash.bundle.js ,而不是 [id].bundle.js 。想了解更多关于 webpackChunkName 和其他可用选项,请查看 import() 相关文档。让我们执行 webpack,查看 lodash 是否会分离到一个单独的 bundle:

----- --------------------
-------- ------- -----
----- -----
           -----     ----  ------                    ----- -----
----------------   --- --       -  ---------  -----  ------
 ---------------  ---- --       -  ---------         -----
   --- -------------------- --- -- --- -------
   --- -------------- --- ----- --- -------
   --- --------------------------- --- ----- --- -------
   --- --------------------------- --- ----- --- -------

由于 import() 会返回一个 promise,因此它可以和 async 函数一起使用。但是,需要使用像 Babel 这样的预处理器和Syntax Dynamic Import Babel Plugin。下面是如何通过 async 函数简化代码:

src/index.js

- -------- -------------- -
- ----- -------- -------------- -
-   ------ --------- ----------------- -------- -- ---------------- -- -
-     --- ------- - -----------------------------
-
-     ----------------- - ---------------- ----------- - --
-
-     ------ -------
-
-   -------------- -- --- ----- -------- ----- ------- --- -----------
-   --- ------- - -----------------------------
-   ----- - - ----- --------- ----------------- -------- -- ---------
-
-   ----------------- - ---------------- ----------- - --
-
-   ------ -------
  -

  ----------------------------- -- -
    ------------------------------------
  --

bundle 分析(bundle analysis)

如果我们以分离代码作为开始,那么就以检查模块作为结束,分析输出结果是很有用处的。官方分析工具 是一个好的初始选择。下面是一些社区支持(community-supported)的可选工具:

  • webpack-chart: webpack 数据交互饼图。
  • webpack-visualizer: 可视化并分析你的 bundle,检查哪些模块占用空间,哪些可能是重复使用的。
  • webpack-bundle-analyzer: 一款分析 bundle 内容的插件及 CLI 工具,以便捷的、交互式、可缩放的树状图形式展现给用户。

下一步

关于「如何在真正的应用程序和缓存中 import() 导入」以及学习「如何更加高效地分离代码」的具体示例,请查看懒加载。


上一篇:生产环境构建
下一篇:懒加载(Lazy Loading)