# HTTP 资源优化
在开篇中提到涉及网络层的有:
- DNS 解析
- TCP 连接
- HTTP 请求/响应
对于 DNS 解析和 TCP 连接两个步骤,前端可以做的努力相对有限,下面直接从 HTTP 开始:
HTTP 优化有两个大的方向: 1、减少请求次数和 2、减少单次请求所花费的时间
# 1、减少请求次数
# 1.1 资源合并
# 雪碧图
雪碧图是将多个小图标合并在一张图中,从而减少图片资源请求数量的一种优化方案。
# 1.2 图片 Base64
Base64 是一种用于传输 8Bit 字节码的编码方式,通过对图片进行 Base64 编码,我们可以直接将编码结果写入 HTML 或者写入 CSS,从而减少 HTTP 请求的次数。
# 1.3 按需加载
引用 webpack 对按需加载的解释 (opens new window):
按需加载或者懒加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。
总结一下常见的按需加载场景有如下几种:
- 框架中的懒加载
- vue 的异步组件
- vue 路由懒加载
- react 中的
import()
、React.lazy
、基于路由的代码分割等
- webpack 的按需加载
- 图片懒加载
详情请看专题:按需加载
# 2、减少单次请求所花费的时间
# 2.1 压缩代码:
Tree-Shaking
,uglifyjs-webpack-plugin
/terser-webpack-plugin
压缩,Gzip 压缩,
# Tree-Shaking
tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和 export。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup。
新的 webpack 4 正式版本,扩展了这个检测能力,通过 package.json 的 "sideEffects" 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 "pure(纯的 ES2015 模块)",由此可以安全地删除文件中未使用的部分。
webpack 打包过程中,对 ES2015 模块代码能够进行 tree-shaking
,减少无用代码缩小项目体积大小,起到优化项目的作用。
专题:tree-shaking
# uglifyjs-webpack-plugin/terser-webpack-plugin
uglifyjs-webpack-plugin
使用 uglify-js
来压缩 JavaScript.
http://lisperator.net/uglifyjs/
UglifyJS
是用 JavaScript 编写的 JavaScript 压缩器。 它还包含一些可以利用 JavaScript 代码做一些自动化工作的工具:
parser
:代码解析器,从 JavaScript 代码生成抽象语法树(AST)的解析器。code generator
:代码生成器,从 AST 输出 JavaScript 代码的代码生成器,也提供了获取source map
的选项。compressor (optimizer)
:代码压缩工具(优化工具),它使用transformer API
将 AST 优化为更小的 AST。mangler
:混淆器,将局部变量的名称(通常地)简化为单个字母。scope analyzer
:作用域解析,通过变量在何处被引用或定义等信息来增强 AST 的工具。tree walker
:一个简单的 API,允许您在 AST 中的每个节点上执行操作.tree transformer
:另一个用于转换树的 API。
webpack 在 v4.26.0
将默认的压缩插件从 uglifyjs-webpack-plugin
改成 teaser-webpack-plugin
。
https://github.com/webpack/webpack/releases?after=v4.26.1 (opens new window)
原因是:uglifyjs-webpack-plugin
使用的 uglify-es
已经不再被维护而且 uglify-js
不支持 ES6+
,取而代之的是一个名为 terser
的分支。terser
分支大部分地保持了 uglify-es
和 uglify-js@3
的 API 和 CLI 的兼容性。所以 webpack 官方放弃了使用 uglifyjs-webpack-plugin
,建议使用 terser-webpack-plugin
。
https://github.com/terser-js/terser (opens new window)
# 2.2 抽离公共代码:CommonsChunkPlugin/SplitChunksPlugin
webpack 的 CommonsChunkPlugin
插件:通过将公共模块拆出来,最终合成的文件能够在最开始的时候加载一次,以便存到缓存中供后续使用。这样后续新加载的页面也使用到公共模块时可以直接从缓存中读取,反之,新的文件本身也要包含所需要的公共模块的代码,体积变大。因此使用 CommonsChunkPlugin
,对于新页面来说可以减小体积,请求时也就减少请求的时间了。
最初,chunks(及其内部导入的模块)是通过内部的 Webpack 依赖图中的父子关系连接的。 CommonsChunkPlugin
用于避免重复的依赖关系,但是无法进行进一步的优化。
从 webpack v4
开始,CommonsChunkPlugin
被删除,转而使用了 optimization.splitChunks
。
optimization.splitChunks 默认配置
开箱即用的SplitChunksPlugin
应该适合大多数用户。
默认情况下,它仅影响按需加载的 chunks,因为更改初始 chunks 会影响运行项目的 HTML 文件应包含的 script。
webpack 将根据以下条件自动分割 chunks:
- 可以共享新的 chunks,或者来自
node_modules
文件夹的模块- 新的 chunks 将大于 30kb(在
min+gz
之前)- 按需加载 chunks 时的并行请求的最大数量将小于或等于 5
- 初始页面加载时并行请求的最大数量将小于或等于 3
当试图满足最后两个条件时,最好使用较大的 chunks。