按需加载
把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件.
代码配置
//定义了一个异步函数,由于函数不调用不执行,所有,一开始时,并不会引入该组件,只有路由跳转时才会调用该函数。
const router = () => import('@/pages/router');
webpack.config.js
output: {
path: path.join(__dirname, '/../dist'),
filename: 'app.js',
publicPath: defaultSettings.publicPath,
// 指定 chunkFilename
chunkFilename: '[name].[chunkhash:5].chunk.js',
},
原理
这是一个异步的方法,webpack 在打包时,OComponent 会被单独打成一个文件,只有在我们跳转 O 这个路由的时候,这个异步方法的回调才会生效,才会真正地去获取 OComponent 的内容。这就是按需加载。
CDN加速-externals
externals配置在Webpack要构建的代码中使用了哪些不用被打包的模块,在运行时再去从外部获取这些扩展依赖,从而减少打包时间并减小包的体积。把我们的依赖资源声明为一个外部依赖,然后通过script外链脚本引入。
代码配置
webpack.config.js
module.exports = {
externals: {
// 拒绝jQuery被打包进来
jquery: 'jQuery'
}
}
index.html
<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script>
GZIP压缩
Gzip压缩是在一个文本文件中找出类似的字符串, 并临时替换他们,使整个文件变小。这种形式的压缩对Web来说非常适合, 因为HTML和CSS文件通常包含大量的重复的字符串,例如空格,标签。(图片不建议采取gzip压缩,因为会图片本身就压缩过的,再采用 gzip只会适得其反,图片体积反增不减!)
代码配置
npm install compression-webpack-plugin --save-dev
//vue.config.js
const CompressionPlugin = require("compression-webpack-plugin");
// 开启gzip压缩 在webpack的plugins里配置
config.plugins.push(
new CompressionPlugin({
filename: '[path].gz[query]', // 使得多个.gz文件合并成一个文件,这种方式压缩后的文件少
algorithm: 'gzip', // 使用gzip压缩
test: /\.js$|\.html$|\.css$/, // 匹配文件名 这里对js、html、css文件进行了压缩处理
// threshold: 10240, // 对超过10k的数据进行压缩
threshold: 5120, // 对超过5k的数据进行压缩
minRatio: 0.8, 压缩率小于1才会压缩
cache: true, // 是否需要缓存
deleteOriginalAssets:false // true删除源文件(不建议);false不删除源文件
}
))
//运行打包命令 npm run build
文件加内出现.gz文件就代表打包成功
原理
gzip(核心是Deflate) 对于要压缩的文件,首先使用 lz77 算法进行压缩,对得到的结果再使用 huffman 编码的方法进行压缩(gzip根据实际情况选择静态或动态huffman编码)。所以我们分别对 lz77 和 huffman 编码的原理进行说明。
- LZ77 算法
lz77 的核心思路是如果一个串中有两个重复的串,那么只需要知道第一个串的内容和后面串相对于第一个串起始位置的距离 + 串的长度。
- 例子
下面我们来举一个例子,有一个文件的内容如下:
自贡富顺的著名小吃是自贡富顺豆花
其中有些部分的内容,前面已经出现过了,下面用 () 括起来的部分就是相同的部分。
自贡富顺的著名小吃是(自贡富顺)豆花
我们使用 (两者之间的距离,相同内容的长度) 这样一对信息,来替换后一块内容。
自贡富顺的著名小吃是(11,4)豆花
(11,4)中,10为相同内容块与当前位置之间的距离,4为相同内容的长度。
由于(两者之间的距离,相同内容的长度)这一对信息的大小,小于被替换内容的大小,所以文件得到了压缩。
lz77采用滑动窗口实现,具体可参考lz77压缩算法详解
解压:观察压缩后的整个串,每个小串前都有一个标识要标记是原始串还是替换“串”,通过这个标识就能以 O(1)的复杂度直接读完并且替换完替换“串”。
- Huffman编码
通过构造 Huffman Tree 的方式给字符重新编码(核心是避免一个叶子的路径是另外一个叶子路径的前缀),以保证出现频路越高的字符占用的字节越少。
具体可参考Huffman算法详解
Tree Shaking
实际情况中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过 Tree-Shaking,将没有使用的模块摇掉,这样来达到删除无用代码的目的。
代码配置
配置webpack.config.js
module.exports = {
// ...
mode: 'development',
optimization: {
usedExports: true,
}
};
//tree Shaking机制发现我们引入了样式文件之后并没有“使用”它,所以不会将该样式文件导入,但是事实上我们是需要这个样式文件的,所以需要设置他。
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
sideEffects: true
//sideEffects一般用于npm包标记是否有副作用。有副作用则不能去移除,移除了可能会出现bug.
}
]
},
};
配置package.json
//根据环境的不同进行配置以后,还可以在 package.json 中,添加字段,告诉 Webpack 哪些代码可以处理
"sideEffects": ["@babel/poly-fill","*.css","*.scss",...]
原理
- ES6 Module引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
- 静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码
注意:Tree Shaking 只支持 ESM 的引入方式,不支持 Common JS 的引入方式
yes: ESM: export + import
no:Common JS: module.exports + require
小延伸:rollup和webpack中对tree-shaking的层度不同,例如对babel转译后的class,如果babel的转译是宽松模式下的话(也就是loose为true),webpack依旧会认为它有副作用不会tree-shaking掉,而rollup会。这是因为rollup有程序流分析的功能,可以更好的判断代码是否真正会产生副作用。