「 面试三板斧 」之 代码分割(上)

「 面试三板斧 」之 代码分割(上)_第1张图片
译:https://medium.com/dailyjs/we...

背景

代码分割是前端性能优化中十分常见的优化手段。

提到代码分割, 往往离不开webpack中的一项配置, 它就是 splitChunks

现在比较多的项目用的都是webpack4, webpack 4 舍弃了之前的 commonChunkPlugin,增加了 SplitChunksPlugin

对于这个插件,它的 option 选项有:

  1. initial
  2. async
  3. all

三个值。

对于这三个值, 哪怕是工作多年的老司机, 能记得清, 区分的清的恐怕不是很多。

我最近也在做性能优化, 通过简单的几行配置, 白屏时间就缩短了将近 600 ms, 十分喜人。

before :

「 面试三板斧 」之 代码分割(上)_第2张图片

after:

「 面试三板斧 」之 代码分割(上)_第3张图片

Load 时长由2.3s 降低至1.57s, 还是不错的。

具体的分析过程以及优化方法我将在下一篇实战篇中介绍。

回归正题,我们先了解一下基础原理。

正文部分翻译自Medium, 原文地址:

https://medium.com/dailyjs/we...

正文

这是我的一个粗略尝试,通过一个常见的例子来理解和帮助你使用 SplitChunksPlugin选项。

作为早期的爱好者,我试图理解代码分割 (Code-Spliting) 背后的魔法。

文档说 splitChucnks 可以接受三个合法的值, 它们分别是:

  • initial
  • async
  • all

我有点困惑,更加提高了我的好奇心。

我深入研究了文档的 Github 历史记录和 WebpackOptions 概要,并发现:

“There are 3 values possible ”initial”, ”async” and ”all”. When configured the optimization only selects initial chunks, on-demand chunks or all chunks.” — Github History

“Select chunks for determining shared modules (defaults to “async”, “initial” and “all” requires adding these chunks to the HTML) ”
— WebpackOptions Schema

这里的想法是有 a.js 和 b.js 两个入口文件,然后引用相同的 node_modules

其中的一些 module 会被动态引入,用来检验代码分割(Code-Spliting)的行为

我们使用 Webpack Bundle Analyzer Plugin 来帮助我们理解我们的 node_modules 是如何被分割的。

a.js:

只有 lodash 是动态引入的

「 面试三板斧 」之 代码分割(上)_第4张图片

b.js:

「 面试三板斧 」之 代码分割(上)_第5张图片

我选这样的配置的主要原因是为了理解当存在公共库时,Webpack 配置的表现是如何的:

  • 在一个入口文件动态引入,另一个则不是 - React
  • 在两个入口文件都动态引入 - lodash
  • 在两个入口文件中都不动态引入 - jquery

我们将保持这些文件不变,并通过 chunks 的值来更改 webpack 的配置。

1. chunks : async — Optimization over async module

「 面试三板斧 」之 代码分割(上)_第6张图片

打包之后的结构:

「 面试三板斧 」之 代码分割(上)_第7张图片

chunks: async 告诉 webpack:

”hey, webpack!我只关心动态导入的模块的优化。你可以保留非动态模块“

现在,让我们一步一步看看发生了什么:

webpack 会从 b.js 提取出 react,并移动到一个新文件,但保持 a.js 中的 react 不动。

这个优化只会作用到动态模块。

import('react') 声明会产生独立的文件

import 'react' 则不会。

webpack 从 a.js 中提取 lodash,并移动到一个新文件,该文件也被 b.js 引用了。

这里不会对 jquery 进行优化,尽管 a.js 和 b.js 都引用了。

2. chunks : initial — Optimization over Sync Module

「 面试三板斧 」之 代码分割(上)_第8张图片

打包之后:

「 面试三板斧 」之 代码分割(上)_第9张图片

chunks: initial 告诉 webpack:

hey, webpack!我不关心动态引入的模块,你可以为每一个模块分别创建文件。但是,我希望将所有非动态引入的模块放在一个 bundle 中,尽管它们还需要引入其他的非动态引入的木块,我准备与其他文件共享和分块我的非动态导入模块。

现在,让我们一步一步看看发生了什么:

  • a.js 中的 react 会被移动到node_vendors~a.bundle.js
  • b.js 中的 react 会被移动到0.bundle.js
  • a.js 和 b.js 中的 lodash 会被移动到1.bundle.js

为什么?

因为这是一个动态引入的模块。

jquery 是一个非动态导入的公共模块,会移动到 node_vendorsab.bundle.js,被 a.js 和 b.js 共享

3. chunks : all — Optimization over Async and Sync Module

「 面试三板斧 」之 代码分割(上)_第10张图片

打包之后:

「 面试三板斧 」之 代码分割(上)_第11张图片

chunks: all 告诉 webpack:

hey, webpack!我不关心这是一个动态还是非动态引入的模块。都对它们进行优化。但要确保......你足够聪明这样做。

现在,让我们一步一步看看发生了什么:

  • react 在 a.js 中是非动态引入的模块,在 b.js 中是动态引入的。因此,它转到单个文件 0.bundle.js,它将由两者引用。
  • lodash 在两个文件中都是动态引入的,所以它显然得到一个单独的文件1.bundle.js
  • jquery 是非动态导入的,因此它转到公共共享模块 node_vendorsab.bundle.js,并将由两者引用。

由此可见, 选用不同的值, 将直接影响 webpack 的打包行为, 打来带来不同的结果。

今天在看这部分的文档, 发现有这样一句描述:

Providing all can be particularly powerful, because it means that chunks can be shared even between async and non-async chunks.

「 面试三板斧 」之 代码分割(上)_第12张图片

官方明示的简直不要太明显。

但如何选用不同的值,来实现最优效果呢?

这点我们将在下一篇详细分析。

今天这篇就先到这, 希望对大家有所帮助, 谢谢大家。


如果你觉得这篇内容对你挺有启发,可以:

  1. 点个「在看」,让更多的人也能看到这篇内容。
  2. 关注公众号「前端e进阶」,掌握前端面试重难点,公众号后台回复「加群」和小伙伴们畅聊技术。

「 面试三板斧 」之 代码分割(上)_第13张图片

更多精彩:

「 面试三板斧 」之 HTTP (下)

「 面试三板斧 」之 HTTP (上)

「 面试三板斧 」之缓存 (下)

「面试三板斧」之缓存 (上)

「 面试三板斧 」之框架

「 面试三板斧 」之  this

你可能感兴趣的:(javascript,前端,vue.js,react.js,webpack)