1、为什么要进行代码拆分?
我们先引入一个应用场景,然后对这个场景进行分析,了解为什么需要拆分代码。
首先,安装第三方库 lodash,然后在 代码分割.js
中引入并编写业务代码。
// 导入第三方库
const _ = require('lodash')
// 业务逻辑代码
console.log(_.join(['a', 'b', 'c']))
接着,配置 webpack.config.js 进行打包
const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
entry: './ 代码分割.js',
output: {path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
publicPath: __dirname + '/build/', // 引用的路径或者 CDN 地址
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {loader: 'babel-loader'}
}
],
},
plugins: [new CleanWebpackPlugin() // 会删除上次构建的文件,然后重新构建
]
}
打包完后会生成一个名为 main.bundle.js 文件,我们在 index.html 中引入,打开浏览器执行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="./build/main.bundle.js"></script>
</body>
</html>
浏览器控制台会输出 a,b,c
如果我们改动 index.js 中的业务代码,改为:
// 导入第三方库
const _ = require('lodash')
// 业务逻辑代码
console.log(_.join(['a', 'b', 'c'], '***'))
控制台结果变为:a***b***c
现在我们抛出一个问题,当我们把引入的第三方库和业务代码放在一起打包,这样会有什么问题?
假设上面第三方库 lodash 大小为 1M,业务代码为 1M,假设打包后的 main.bundle.js 为 2M
浏览器每次打开 index.html 时,都需要去加载 main.bundle.js,然后执行业务代码。加载 2M 代码是很耗时的,但是浏览器有缓存机制,第二次加载同一文件时会从缓存中读取,刷新页面时网页加载速度更快。但是事与愿违,我们的业务代码更新很频繁,导致无论是首次加载还是再次加载都会很慢,那如何去解决这个问题呢?
答案很明显,第三方库 lodash 代码基本上是不会变的,如果我们能够将业务代码和第三方库代码分开加载,那么第三方库的加载就可用到缓存机制,整个页面的加载时间也会缩短。
在多个 js 文件都引入了同样的库或者代码的场景下也是可以进行拆分,避免重复加载。
在 webpack4 之前是使用 commonsChunkPlugin 来拆分公共代码,v4 之后被废弃,并使用 splitChunksPlugins
在使用 splitChunksPlugins 之前,首先要知道 splitChunksPlugins 是 webpack 主模块中的一个细分模块,无需 npm 引入,只需要配置即可。
const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
entry: './ 代码分割.js',
output: {path: path.resolve(__dirname, 'build'), // 打包文件的输出目录
filename: '[name].bundle.js', // 代码打包后的文件名
publicPath: __dirname + '/build/', // 引用的路径或者 CDN 地址
chunkFilename: '[name].js' // 代码拆分后的文件名
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {loader: 'babel-loader'}
}
]
},
// 拆分代码配置项
optimization: {
splitChunks: {chunks: 'all'}
},
plugins: [new CleanWebpackPlugin() // 会删除上次构建的文件,然后重新构建
]
}
我们使用 cnpm run dev 在开发模式下打包文件,开发模式下打包不会压缩文件,方便查看
可以看到代码拆分成了两个文件,打开 main.bundle.js 文件可以看到里卖弄存放的都是业务代码,没有 lodash 的代码
打开 vendors~main.js 文件可以看到 lodash 代码都在里面
这样就完成了代码拆分,拆分完的两个文件都要引入到 index.html 中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="./build/vendors~main.js"></script>
<script src="./build/main.bundle.js"></script>
</body>
</html>
浏览器执行 index.html 文件控制台结果:a***b***c
上面采用拆分代码的模式是 all,另外还有 async、initial,我们来了解一下
-
async
: 只优化动态加载的代码,其他类型的代码正常打包。 -
initial
: 针对原始 bundle 代码进行优化。 -
all
: 针对所有代码进行优化。 -
function(chunk)
自定义拆分函数
详情可以参考:
https://github.com/wayou/wayou.github.io/issues/40
https://medium.com/dailyjs/webpack-4-splitchunks-plugin-d9fbbe091fd0
分割出来的文件名为 vendors~main.js,怎么来的,我们来分析一下
2、如何拆分代码?
参考文章: