代码压缩是在不改变代码功能的情况下,尽可能的减少代码体积的过程,在
web
场景下可以有效减少网络传输流量,降低网络时延,提升页面启动速度的一种应用优化方案。
代码压缩原理
代码压缩旨意用最小的代码量实现原有的功能,代码量指的就是代码的字符数,其实它并没有多么神奇,举一个最简单的一个就是注释。
注释对于代码运行没有任何用处,我定义一个变量,写了一个注释,结果注释的字符数量比代码字符的数量都多:
// 这是一个啥啥啥的标识,用来干啥啥啥的 const flag = false;
这里注释有21
个字符,代码有19
个字符,如果我删掉注释,这就是对代码进行压缩了,说的好听一点就是减少的字符超过50%
。
当然这不够,进一步压缩,const
???我使用let
好像也OK吧,flag
这么长有啥用,我一个计算机需要它这么长吗,直接变成f
,=
前后还有空格?干掉,false
直接用数字0
代替,分号还是要的,压缩完毕,19
变成8
,算上之前的注释,减少的字符高达80%
let f=0;
上面这些只是代码压缩的冰山一角,代码压缩的代码是给机器执行的,不再是给人看的,所以不会在乎可读性,甚至可能会丢失一部分性能,当然这里的性能一般是忽略不计的,来达到节省代码字符的目的。
使用 TerserWebpackPlugin 压缩 JS
首先webpack
已经内置了terser,使用这个玩意也很简单,第一种就是将mode
属性值设置为production
,webpack
在生产环境下,默认optimization.minimize
值为true
,第二种就是将刚说到的这个属性值手动设置为true
,如下:
module.exports = { mode: "production", optimization: { minimize: true } }
不过webpack
还提供了一个属性optimization.minimizer
,能让你手动使用其他代码压缩插件,我们这里就使用TerserWebpackPlugin
:
- 安装
npm i -D terser-webpack-plugin
- 配置:
const TerserWebpackPlugin = require('terser-webpack-plugin') module.exports = { optimization: { minimize: true, minimizer: [ new TerserWebpackPlugin() ] } }
optimization.minimizer
属性值必须是一个数组,数组项可以为[TerserPlugin]
或[function (compiler)]
,或者'...'
来访问默认值,参考:optimization.inimizer
TerserWebpackPlugin
初始化时可以传一些配置项来帮助你实现细粒度更高的代码压缩配置,下面的配置表是搬运,参见TerserWebpackPlugin:
选项名 | 类型 | 默认值 | 说明 |
test |
String|RegExp|Array<String|RegExp> |
/\.m?js(\?.*)?$/i |
用来匹配需要压缩的文件。 |
include |
同上 | undefined |
匹配参与压缩的文件。 |
exclude |
同上 | undefined |
匹配不需要压缩的文件。 |
parallel |
Boolean|Number |
true |
匹配不需要压缩的文件。 |
parallel |
Boolean|Number |
true |
Number : 使用多进程并发运行以提高构建速度。 并发运行的默认数量: os.cpus().length - 1 。 Boolean : 启用/禁用多进程并发运行功能。 |
minify |
Function |
TerserPlugin.terserMinify |
允许你自定义压缩函数。 默认情况下,插件使用terser库。 对于使用和测试未发布的版本或 fork 的代码很帮助。 |
terserOptions |
Object |
terser默认 | terser配置项 |
extractComments |
Boolean|String|RegExp|Function<(node, comment) -> Boolean|Object>|Object |
true |
是否将注释剥离到单独的文件中 |
使用 CssMinimizerWebpackPlugin 压缩 CSS
css
压缩的规则也差不多是删除注释,属性简写,如色彩值为#ffffff
简写就是#fff
,长度为0
可不带单位,例如0%
、0px
、0em
等都简写为0
,属性合并,例如margin: 10px 10px
合并为margin: 10px
等等等很多,就不一一列举了。
webpack
不认识css
文件,所以没有内置的对css
文件压缩的工具,这里使用的css-minimizer-webpack-plugin
。
- 安装:
npm i -D css-minimizer-webpack-plugin
- 配置:
const path = require('path'); const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { mode: "development", entry: './main.js', output: { path: path.resolve(__dirname, './dist'), filename: "[name].js" }, module: { rules: [ { test: /.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader'] } ] }, optimization: { minimize: true, minimizer: [ '...', // Webpack5 之后,约定使用 `'...'` 字面量保留默认 `minimizer` 配置 new CssMinimizerWebpackPlugin(), ] }, plugins: [ // 需要使用 mini-css-extract-plugin 生成单独的css文件才能启用压缩 new MiniCssExtractPlugin() ] }
- 一定是要有单独的
css
文件才能压缩,所以需要是用mini-css-extract-plugin
来配合。minimizer
如果不配置'...'
那么会覆盖默认的配置,导致js
无法被压缩。
使用 HtmlMinifierTerser 压缩 HTML
现在web
开发场景下被React
、Vue
等MVVM
框架支配,已经不再怎么使用html
了,使用html
也只是一个节点挂载的作用(<div id="app"></div>
)。
那么html
的压缩点在什么地方呢?例如<div [这里是空格,很多个] id="app"></div>
,然后就成这样了<div id="app"></div>
,还有<br></br>
变成<br>
,还有其他自闭合标签等等等。
这里使用到的插件是html-minifier-terser
:
- 安装依赖:
npm i -D html-minifier-terser
- 配置:
const HtmlWebpackPlugin = require("html-webpack-plugin"); const HtmlMinimizerPlugin = require("html-minimizer-webpack-plugin"); module.exports = { optimization: { minimize: true, minimizer: [ '...', new HtmlMinimizerPlugin() ] }, plugins: [ new MiniCssExtractPlugin(), new HtmlWebpackPlugin({ template: "./index.html" }) ] }
我新建了一个index.html
,内容如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Webpack App</title> <meta name="viewport" content="width=device-width,initial-scale=1"> </head> <body> <!-- 这是注释 --> <div class="abc"></div> <input /> <br></br> </body> </html>
其实这里对
html
的压缩效果并没有那么显著,因为很多默认配置都是关闭状态,咱这一点点东西其实看不出来什么,只知道是被压缩了,不过也够用了。
总结
代码压缩主要是用于线上环境,减少代码体积,保持原有的功能不发生改变,原理并不复杂,社区有很多现成的工具,这里的插件都是带webpack
的,也是被官方支持的,还有很多其他的压缩工具,效率各异,我们使用官方的就直接接入就好了,方便又简洁,瑞思拜。