多页面打包抽离公共代码
本节来学习一下webpack常用的一个功能,抽取公共代码。
公共代码肯定是在有多个页面中,然后有公共的部分,才需要抽取出来。
所以需要配置一个多入口,这两个入口中,有公用的代码。
如果不抽离出来,那么相同的代码会被打包成多份,整体打包体积就变大了。
抽离自定义的公共代码
引出问题
假如有a.js和b.js,还有index.js和other.js,index.js和other.js都需要使用a和b,那么只需要将a和b抽离出去,单独用一个包,那么当index使用a,b时,先生成一个包,然后other再使用a,b时,就直接从已经加载好的包里取,就实现了一个缓存的效果。这就是提取公共代码的好处。
新建a.js
// webpack-optimize\src\a.js
console.log('a~~~~~~~~~~~~~');
新建b.js
// webpack-optimize\src\b.js
console.log('b~~~~~~~~~~~~~');
新建index.js
// webpack-optimize\src\index.js
import './a.js'
import './b.js'
console.log('index.js');
新建other.js
// webpack-optimize\src\other.js
import './a.js'
import './b.js'
console.log('other.js');
修改配置文件
// webpack-optimize\webpack.config.js
let path = require('path')
// 插件 用来复制html入口模板,到打包后的目录,并把打包后的js文件,以script标签的形式塞到模板文件里
let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development', // 模式,默认两种模式 production 和 development
entry: {
index: './src/index.js',
other: './src/other.js',
}, // 多入口
devServer: { // 开发服务器的配置
port: 3000, // 默认端口是8080,这里可以改
progress: true, // 打包时候的进度条
contentBase: './dist', // 以哪个文件夹作为服务的根目录 ,如果有就直接使用,没有的话就使用内存中的
open: true, // 服务启动完毕后,直接打开浏览器
compress: true, // 启动gzip压缩
},
// 打包后的输出路径
output: {
filename: '[name].js', // 打包后的文件名
path: path.resolve(__dirname, 'dist'), // 打包后输出的路径
},
// 配置一些loader
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
// 配置一些它的选项
options: {
// 配置预设,有多个
presets: [
'@babel/preset-env', // 用来解析es6
'@babel/preset-react', // 用来解析react语法,jsx
]
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
]
},
// 注册插件
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html', // 模板的位置
}),
]
}
打包,查看结果
果然不出所料,最后两个入口,各自打包了一份a.js和b.js的代码
优化,开始抽离
修改配置文件
// webpack-optimize\webpack.config.js
let path = require('path')
// 插件 用来复制html入口模板,到打包后的目录,并把打包后的js文件,以script标签的形式塞到模板文件里
let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development', // 模式,默认两种模式 production 和 development
// 抽离多入口引用的公共代码
optimization: {
splitChunks: { // 分割代码块
cacheGroups: { // 缓存组
common: { // 公共模块
chunks: 'initial', // 从入口文件就开始抽离了(暂时没有考虑异步模块)
minSize: 0, // 只要代码大于0个字节,就抽离出来
minChunks: 2, // 代码被引用多少次,才抽离
}
// 上面的解释,刚开始从入口就开始抽离common,只要大于0个字节,被引用2次,就抽离
}
}
},
entry: {
index: './src/index.js',
other: './src/other.js',
}, // 多入口
devServer: { // 开发服务器的配置
port: 3000, // 默认端口是8080,这里可以改
progress: true, // 打包时候的进度条
contentBase: './dist', // 以哪个文件夹作为服务的根目录 ,如果有就直接使用,没有的话就使用内存中的
open: true, // 服务启动完毕后,直接打开浏览器
compress: true, // 启动gzip压缩
},
// 打包后的输出路径
output: {
filename: '[name].js', // 打包后的文件名
path: path.resolve(__dirname, 'dist'), // 打包后输出的路径
},
// 配置一些loader
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
// 配置一些它的选项
options: {
// 配置预设,有多个
presets: [
'@babel/preset-env', // 用来解析es6
'@babel/preset-react', // 用来解析react语法,jsx
]
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
]
},
// 注册插件
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html', // 模板的位置
}),
]
}
打包,查看结果,抽离成功
这样公共的代码就抽离到了一个文件中。
抽离第三方模块
引出问题
有时候,我们会在多个模块中同时引用多次第三方模块,比如jquery
修改index.js
// webpack-optimize\src\index.js
import './a.js'
import './b.js'
console.log('index.js');
// 引用第三方模块
import $ from 'jquery'
console.log($);
修改other.js
// webpack-optimize\src\other.js
import './a.js'
import './b.js'
console.log('other.js');
// 引用第三方模块
import $ from 'jquery'
console.log($);
这时候,我们想把第三方模块单独的抽离成一个文件,但是如果还使用上面的方法,会将jquery的代码和我们自定义的模块代码抽离到同一个文件中。显然这不是我们想要的。
我们可以看一下,打包
一下300多k,显然jquery也打包到这个文件里了。我们想把公用的第三方模块单独拎出来怎么办?
修改,开始抽离
修改配置文件
// webpack-optimize\webpack.config.js
let path = require('path')
// 插件 用来复制html入口模板,到打包后的目录,并把打包后的js文件,以script标签的形式塞到模板文件里
let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development', // 模式,默认两种模式 production 和 development
// 抽离多入口引用的公共代码
optimization: {
splitChunks: { // 分割代码块
cacheGroups: { // 缓存组
common: { // 公共模块
chunks: 'initial', // 从入口文件就开始抽离了(暂时没有考虑异步模块)
minSize: 0, // 只要代码大于0个字节,就抽离出来
minChunks: 2, // 代码被引用多少次,才抽离
},
// 上面的解释,刚开始从入口就开始抽离common,只要大于0个字节,被引用2次,就抽离
vendor: { // 第三方模块
test: /node_modules/, // 如果 是从node_modules中引入的模块,就抽离出来
chunks: 'initial', // 从入口文件就开始抽离了(暂时没有考虑异步模块)
minSize: 0, // 只要代码大于0个字节,就抽离出来
minChunks: 2, // 代码被引用多少次,才抽离
priority: 1, // 权重高一些,先抽离第三方模块,再去抽离别的
},
// 注意:抽离模块的代码 是从上向下执行的
// 当走 common 的抽离配置时,会直接将jquery也匹配到,抽离出来
// 所以就导致了,第三方模块的代码 仍旧和自定义模块代码在一个文件中
// 解决办法是 先抽离第三方模块,再去抽离别的代码
// 给 vendor 配置 增加一个权重 priority: 1
}
}
},
entry: {
index: './src/index.js',
other: './src/other.js',
}, // 多入口
devServer: { // 开发服务器的配置
port: 3000, // 默认端口是8080,这里可以改
progress: true, // 打包时候的进度条
contentBase: './dist', // 以哪个文件夹作为服务的根目录 ,如果有就直接使用,没有的话就使用内存中的
open: true, // 服务启动完毕后,直接打开浏览器
compress: true, // 启动gzip压缩
},
// 打包后的输出路径
output: {
filename: '[name].js', // 打包后的文件名
path: path.resolve(__dirname, 'dist'), // 打包后输出的路径
},
// 配置一些loader
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
// 配置一些它的选项
options: {
// 配置预设,有多个
presets: [
'@babel/preset-env', // 用来解析es6
'@babel/preset-react', // 用来解析react语法,jsx
]
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
]
},
// 注册插件
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html', // 模板的位置
}),
]
}
测试一下,打包看下结果,已经抽离出来了
这时候的vendor里放的就是jquery,common放的我自定义的模块代码。他们都被引用了两次以上,抽离出来就减小的代码体积。
总结
多页面打包时,可能会有公共代码,打包的时候,相同的代码会被打包两次,很浪费性能,webpack可以将公用的代码抽离出来,变成单独的文件,然后引用的地方就会引这个抽离出来的代码。
抽离自定义模块
抽离第三方模块(从node_modules中引入的)
js// 抽离多入口引用的公共代码 optimization: { splitChunks: { // 分割代码块 cacheGroups: { // 缓存组 common: { // 公共模块 chunks: 'initial', // 从入口文件就开始抽离了(暂时没有考虑异步模块) minSize: 0, // 只要代码大于0个字节,就抽离出来 minChunks: 2, // 代码被引用多少次,才抽离 }, // 上面的解释,刚开始从入口就开始抽离common,只要大于0个字节,被引用2次,就抽离 vendor: { // 第三方模块 test: /node_modules/, // 如果 是从node_modules中引入的模块,就抽离出来 chunks: 'initial', // 从入口文件就开始抽离了(暂时没有考虑异步模块) minSize: 0, // 只要代码大于0个字节,就抽离出来 minChunks: 2, // 代码被引用多少次,才抽离 priority: 1, // 权重高一些,先抽离第三方模块,再去抽离别的 }, // 注意:抽离模块的代码 是从上向下执行的 // 当走 common 的抽离配置时,会直接将jquery也匹配到,抽离出来 // 所以就导致了,第三方模块的代码 仍旧和自定义模块代码在一个文件中 // 解决办法是 先抽离第三方模块,再去抽离别的代码 // 给 vendor 配置 增加一个权重 priority: 1 } } },
参考
https://www.bilibili.com/video/BV1a4411e7Bz?p=25&spm_id_from=pageDriver