介绍
代码分离:主要是将代码分离到不同的bundle中,之后我们可以按需加载,或者并行加载这些文件。 如果没有进行代码分离,一般打包成一个js文件后,在首页进行加载时,就会加载这一个js文件,如果这个js文件过大,就会导致影响首页的加载速度。
webpack常用的代码分离有三种:
- 多入口起点:配置entry的多个打包入口。
- 动态导入:通过import函数来分离代码。
- 防止重复:入口的多份相同依赖进行抽取或者使用splitchunkPlugin分离代码。
多入口起点
配置很简单,假如src目录下面有index和main文件,配置这两个文件为打包入口
webpack.config.js配置
const path = require("path");
module.exports = {
mode: "development",
entry: {
index: "./src/index.js",
main: "./src/main.js",
},
output: {
path: path.resolve(__dirname, "./build"),
filename: "[name]bundle.js",
clean: true,
},
};
最后的打包结果,此时就会打包成两个文件
动态导入
主要使用ECMAScript中的 import() 语法来完成。 例如:当有一个foo.js的模块需要在代码运行过程中来决定是否导入它,这个代码不一定用到,所以最好将他拆分成一个独立的js文件,在需要的时候采取加载它,这个时候就可以使用动态导入。
const btn1 = document.createElement('button')
btn1.onclick = function() {
import('./foo.js')
}
只有当btn1点击之后才会会请求这个foo打包单独生成的文件
在使用import函数时,我们可以通过then拿到foo导出的内容
例如,foo.js如下
function sum(a,b){
return a+b
}
const name='zs'
export {
sum
}
export default name
btn1.onclick = function() {
import('./foo.js').then(res=>{
res.sum(1,2);
res.default()//这里拿到的是name
}
}
动态导入的打包文件命名
module.exports = {
mode: "production",
entry: "./src/main.js",
output: {
clean: true,
path: path.resolve(__dirname, "./build"),
filename: "[name]-bundle.js",
// 单独针对分包的文件进行命名
chunkFilename: "[name]_chunk.js",
}
}
打包后的文件,如图下面src_foo_js_chunkl.js就是foo.js打包后的文件
若希望修改上面[name]_chunk.js的name,可以在import函数里面修改
btn1.onclick = function() {
import(/* webpackChunkName: "bar" */'./foo.js')
}
经过上面的修改之后,打包后的文件的名字就会是这样bar_chunk.js
prefetch和preload
使用方法是在import的时候进行配置
import(
/* webpackChunkName: "foo" */
/* webpackPrefetch: true */
'./foo.js')
- prefetch(预获取):将来某些导航下可能需要的资源
- preload(预加载):当前导航下可能需要资源
prefetch和preload对比
- preload会在父 chunk 加载时,以并行方式开始加载。prefetch 会在父 chunk 加载结束后开始加载。
- preload 加载后立即下载,而prefetch chunk 在浏览器闲置时下载。
防止重复
入口重复依赖
当我们的项目使用多入口,并且每个入口都有引用axios和lodash,那么此时可以将这两份都打包成一个文件,让他们进行共享。
webpack.config.js配置如下:
entry: {
index: {
import: './src/index.js',
dependOn: 'shared'
},
main: {
import: './src/main.js',
dependOn: 'shared'
},
shared: ['axios','lodash']
},
output: {
path: path.resolve(__dirname, './build'),
filename: '[name]-bundle.js',
clean: true
},
最后打包结果如下,会将相同的部分抽离生成一个shared-bundle.js文件
SplitChunks
这种底层利用SplitChunksPlugin来实现的。该插件webpack已经默认安装和集成,所以我们并不需要单独安装和直接使用该插件。
默认配置如下:
module.exports={
entry:...
output:...
optimization:{
splitChunks:{
chunks:'async', 默认是async,表示异步的(例如import()动态导入)进行分包,而其他import axios from 'axios',不进行分包
}
}
}
我们可以进行如下自定义配置
module.export={
entry:..
output:...
optimization: {
// 分包插件: SplitChunksPlugin
splitChunks: {
//设置成all表示所有import导入的都需要分包,会生成一个个js文件
chunks: "all",
// 当一个包大于指定的大小时, 继续进行拆包
// maxSize: 20000,
// // 将包拆分成不小于minSize的包
// minSize: 10000,
minSize: 10,
}
},
}
1.如果想要进一步分包处理,比如对来自某个文件夹的包进行进一步的分包,需要如下配置
webpack.config.js
optimization: {
splitChunks: {
chunks: "all",
maxSize: 20000,
minSize: 10000,
//对某些需要拆包的内容进行分包处理
cacheGroups: {
vendors:{
test:/node_modules/,
filename:'[id]_vendors.js',
},
util: {
test: /utils/,
filename: "[name]_utils.js",
},
},
},
},
上面会对来自utils和node_modules下面的包进一步分包。
上两个就是打包后的结果
2.如果需要对js代码进行压缩或者将注释提取出来,需要先安装terser-webpack-plugin插件
webpack.config.js
const TerserPlugin = require("terser-webpack-plugin");
optimization:{
splitChunks:{},
minimize:true,//开启js压缩
minimizer:{
new TerserPlugin({
extraComments:true
})
}
}
提取的这个单独的文件通常以 .LICENSE.txt 或类似的扩展名保存,如下图
3.optimization.chunkIds配置
这个配置用于告知webpack模块的id采用什么算法生成,有三个值
- natural:按照数字的顺序使用id;
- named:development下的默认值,一个可读的名称的id。一般是路径
- deterministic:确定性的,在不同的编译中不变的短数字id