我们在打包时,可以采用各种压缩方式,就提高性能。比如Tree Shaking、Http压缩等等。本篇详细介绍各种压缩方式。
Terser
当我们在生产模式打包后,代码会被丑化压缩。
我们知道这是因为当mode:production时,默认就开启了很多配置,其中就包括丑化压缩代码。
在实际开发中虽然我们很少去配置怎么去丑化压缩代码,但是我们也可以学习了解下webpack是用什么工具帮我们实现的。
Webpack 在production模式下,webpack默认会使用很多插件来丑化压缩我们的代码,其中最主要的就是TerserPlugin。
如果我们想配置自己的terser去覆盖默认的,可以参考如下配置:(在实际开发中,webpack默认开启Terser,一般无需手动配置)
//webpack.config.js
//无需手动npm安装,webpack默认安装好了
const TerserPlugin = require('terser-webpack-plugin');
optimization: {
//minimize设置为true,开启minimizer
minimize: true,
minimizer: [
new TerserPlugin({
//parallel:默认为true,使用多线程并发运行提高构建速度(充分利用多核cpu性能)
parallel: true,
//extractComments:默认true,将注释单独抽到一个文件
extractComments: false,
//设置terser相关配置
terserOptions: {
compress: {
arguments: false,
dead_code: true
},
mangle: true,
toplevel: true,
keep_classnames: true,
keep_fnames: true
}
})
]
},
关于terser更多的配置规则可参考文档:
https://github.com/terser/terser#compress-options
CSS压缩
在之前学习代码分离中,学习了css代码的分离。我们也可以对分离出来的代码进行压缩。
CSS压缩通常是去除无用的空格等,因为很难去修改选择器、属性的名称、值等;
CSS的压缩我们可以使用另外一个插件:css-minimizer-webpack-plugin;
这个插件的使用非常简单,只需要安装然后直接使用即可。
安装:
npm install css-minimizer-webpack-plugin -D
使用:
//webpack.config.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
plugins: [
new CssMinimizerPlugin(),
]
Scope Hoisting(作用域提升)
什么是Scope Hoisting?
我们在之前学习webpack实现模块化原理时,就发现了webpack打包时会写很多闭包对我们的代码进行很多额外的函数作用域封装。
Webpack想要拿到某个函数,可能需要经过很多层的闭包才能拿到。
所以在生产模式下,就可以使用Scope Hoisting进行作用域提升,让webpack打包后的代码更小、运行速度更快。
使用:
在production模式下,Scope Hoisting是默认开启的。
如果想要在development模式下开启,需要我们手动配置。配置如下:
//webpack.config.js
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
Tree Shaking
什么是Tree Shaking?
Tree Shaking的作用就是消除无用代码(dead_code)。
如果一段代码,它既没有副作用又没有被我们使用到,那么这段代码就是dead_code(无用代码)。
我们可以利用Tree Shaking删除掉这些无用代码,来提高我们的性能。
Tree Shaking依赖于ES Module的静态语法分析(不执行任何的代码,就可以明确知道模块的依赖关系)。
而webpack5中,也提供了对部分CommonJS的tree shaking的支持;
实现Tree Shaking的两种方案:
usedExports:通过标记某些函数是否被使用,之后通过Terser来进行优化的;
sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用;
useExports
在前面学习Terser时,我们知道了Terser就是一个对代码进行丑化压缩的工具。
而这里的useExports,就是告诉Terser哪些代码是dead_code,你帮我删掉这些代码。
usedExports会对未使用的代码添加注释(unused harmony export mul),terser根据注释删除代码;
在生产模式下,useExports默认就为true。实际开发中无需手动配置。
//webpack.config.js
optimization: {
// usedExports: 对未使用的代码添加注释(unused harmony export mul),terser根据注释删除代码;
usedExports: true,
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
extractComments: false,
terserOptions: {
compress: {
arguments: false,
dead_code: true
},
mangle: true,
toplevel: true,
keep_classnames: true,
keep_fnames: true
}
})
]
},
sideEffects(副作用)
sideEffects用于告知webpack compiler哪些模块时有副作用的。
通过sideEffects实现的Tree Shaking更彻底。
useExports只删除没有用到的代码。而sideEffects会删除未用到的代码及其模块化导入的相关代码等。
(在前面学习webpack实现模块化原理时,webpack会将模块化导入导出的方法转化为浏览器认识的代码)
使用:
在package.json文件中,配置sideEffects。
如果我们将sideEffects默认值为false,就是告知webpack可以安全的删除未用到的exports。
如果我们有想要保留的未用到的代码,可以把sideEffects的值写成数组,数组里的文件,声明下这些文件有副作用不要删掉。
//package.json
"name": "your-project",
//false:全部都没有副作用,都可以删除
"sideEffects": false
//数组内声明的有副作用,其他的都可以删除
"sideEffects": [
"./src/some-side-effectful-file.js"
]
实际开发中,我们一般会直接设置package.json里的sideEffects:false;
然后专门针对css文件声明下有副作用,Tree Shaking不要删掉。
//package.json
{
"name": "your-project",
//false:全部都没有副作用,都可以删除
"sideEffects": false
}
//webpack.config.js
module: {
rules: [
{
test: /\.css/i,
use: ["style-loader", "css-loader"],
sideEffects: true,
},
],
},
CSS实现Tree Shaking
如果我们在项目中对css代码进行了代码分离,分离出了独立的文件保存css代码,那我们也可以对css文件进行Tree Shaking。
CSS的Tree Shaking需要借助于其他的插件:PurgeCSS。(帮我们删除未使用的css代码,也支持less,因为它是对打包后的css文件进行处理)
安装:
npm install purgecss-webpack-plugin -D
使用:
//webpack.config.js
const PurgeCssPlugin = require('purgecss-webpack-plugin');
//ptah与glob在安装webpack默认安装,无需手动安装
const path = require("path");
const glob = require('glob');
plugins: [
new PurgeCssPlugin({
//paths检测哪个路径下的内容需要被分析(PurgeCssPlugin推荐使用golb这个库)
// /**/*/表示不处理文件夹
paths: glob.sync(`${path.resolve(__dirname,"./src")}/**/*`, {nodir: true}),
//由于默认删掉body与html的css代码,这里需要额外配置不删掉
safelist: function() {
return {
standard: ["body", "html"]
}
}
})
]
HTTP压缩
什么是Http压缩?
HTTP压缩是一种内置在 服务器 和 客户端 之间的,以改进传输速度和带宽利用率的方式。
Http压缩及请求流程
- 客户端使用webpack将http数据压缩完成后再发送给服务器
- 浏览器在想客户端发送http请求(http请求头里包含浏览器兼容的压缩方式Accept-Encoding)
- 服务器在知道浏览器兼容的压缩格式后,直接返回对应的压缩后的文件响应(并且响应头里包含压缩格式类型Content-Encoding)
压缩格式特别多,目前比较流行的压缩格式有哪些?
- gzip : GNU zip格式(定义于RFC 1952)(目前使用最多)
- br – 一种新的开源压缩算法,专为HTTP内容的编码而设计;(能压缩得很小,但是有些浏览器不兼容)
- deflate – 基于deflate算法(定义于RFC 1951)的压缩,使用zlib数据格式封装;
Webpack配置http压缩
我们可以在开发环境下的devServer里配置compress: true,实现了http代码压缩。
但这里主要学习在生产环境下我们使用CompressionPlugin插件进行http压缩。
安装:
npm install compression-webpack-plugin -D
使用:
实际开发中,我们一般只配置test,其它采用默认值即可
//webpack.config.js
const CompressionPlugin = require('compression-webpack-plugin');
plugins: [
new CompressionPlugin({
//哪些文件进行压缩
test: /\.(css|js)$/i,
//threshold:多大进行压缩、minRatio:压缩比例达到多少进行压缩、algorithm:压缩类型
//实际开发中,我们一般只配置test,其它采用默认值即可
threshold: 0,
minRatio: 0.8,
algorithm: "gzip",
}),
Html文件中代码的压缩
在之前的学习中,我们可以用到HtmlWebpackPlugin插件来帮我们生成build文件夹下的HTML文件。
但实际上HtmlWebpackPlugin还有一些其他配置,来帮助我们对生成的HTML文件进行代码压缩。
//webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
plugins: [
new HtmlWebpackPlugin({
template: "./index.html",
// inject: "body"
cache: true, // 当文件没有发生任何改变时, 直接使用之前的缓存
minify: isProduction ? {
removeComments: false, // 是否要移除注释
removeRedundantAttributes: false, // 是否移除多余的属性
removeEmptyAttributes: true, // 是否移除一些空属性
collapseWhitespace: false, //移除空格
removeStyleLinkTypeAttributes: true,
minifyCSS: true, //压缩html内的css
minifyJS: { //压缩html内的js
mangle: {
toplevel: true
}
}
}: false
}),
],