webpack高级概念code splitting 和 splitChunks (系列五)
当你把所有的代码都打包到一个文件的时候,每次改一个代码都需要重新打包。且用户都要重新加载下这个js文件。但是如果你把一些公共的代码或第三方库抽离并单独打包。通过缓存加载,会加快页面的加载速度。(分割成多个文件,不必打包成一个文件,提高性能)
- 异步加载的代码,webpack会单独打包到一个js文件中
- 同步加载的代码有两种方式
入口文件index.js
引入的第三方库 import _ from 'lodash' 业务逻辑代码 console.log(666)
打包后的文件main.js:
main.js 551 KiB main [emitted] main
可以看到,webpack将业务代码跟lodash库打包到一个main.js文件了,每次更改业务代码,就要重新被打包一次,浪费性能
方法一:手动代码分割,不推荐
index.js
业务逻辑代码 console.log(666)
创建一个新文件lodsh.js入口, 将第三方的库单独抽离
import _ from 'lodash' window._ = _
将文件挂载到 window
对象上,这样其他地方就可以直接使用了。
然后在webpack配置文件中的entry增加一个入口为该文件。
module.exports = { entry: { main: './src/index.js',
//新增一个打包的文件,lodash为打包后的文件名称 ./src/lodash.js为入口文件, 映射关系 lodash:'./src/lodash.js' },
output: {
//模糊匹配entry需要打包文件名称 filename: '[name].js', path: path.resolve(__dirname, '../dist') }
打包后,打包成main,js和lodash.js两个文件,html会引入这两个文件。
当我们业务逻辑更改,webpack重新打包只需打包main.js,lodash.js会缓存在浏览器中。代码分割打包,此时提高了性能
Asset Size Chunks Chunk Names
lodash.js 551 KiB lodash [emitted] lodash
main.js 3.79 KiB main [emitted] main
方法二: webpack自动代码分割
2.1,同步引入第三方库
入口文件index.js
// 同步加载lodash import _ from 'lodash' console.log(_.join(['a','b','c','***']))
在webpack.base.js配置optimization
配置参数
optimization: { // 代码分割配置 splitChunks: { chunks: 'all' } }, output: { filename: '[name].js', path: path.resolve(__dirname, '../dist') }
module.exports = { entry: { main: './src/index.js' },
打包后的文件,webapck的optimization会自动将诸如lodash
等库抽离成单独的chunk
,还会将多个模块公用的模块抽离成单独的chunk,提高性能
2.2,异步引入代码第三方库
index.js入口文件
function getComponent() { // 异步加载lodash return import('lodash').then(({ default: _ }) => { var element = document.createElement('div'); element.innerHTML = _.join(['Dell', 'Lee'], '-'); return element; }) } getComponent().then(element => { document.body.appendChild(element); });
不需要webpack做任何配置
打包后文件, lodash第三方库自动打包成单独的0.js, vue中的路由懒加载就是这样,import函数
总结
// 代码分割,和webpack无关 // webpack中实现代码分割,两种方式 // 1. 同步代码: 只需要在webpack.common.js中做optimization的配置即可 // 2. 异步代码(import): 异步代码,无需做任何配置,会自动进行代码分割,放置到新的文件中
splitChunks
里面还可以在添加个参数cacheGroups
optimization: { splitChunks: { chunks: 'all', cacheGroups: { // 下面的意思是:将从node_modules中引入的模块统一打包到一个vendors.js文件中 vendors: { test: /[\\/]node_modules[\\/]/, priority: -10, filename: 'vendors.js' }, default: false } } }
index.js入口文件
同步加载lodash import _ from 'lodash' console.log(_.join(['a','b','c','***']))
打包加载后,cacheGroups
中vendors
配置表示将从node_modules
中引入的模块(所有引入的第三方库)统一打包到一个vendors.js文件中
如果venders的 filename: 'vendors.js',属性注释掉,那么默认会把第三方库lodash统一打包到vendors~main.js文件中(main.js为第三方库引入的文件)
splitChunks
的default
参数:
根据上下文来解释,如上配置了vendors
,打包node_modules
文件夹中的模块,
那么default
将会打包自己编写的公共方法。
添加default的配置
optimization: { splitChunks: { chunks: 'all', cacheGroups: { // 下面的意思是:将从node_modules中引入的模块统一打包到一个vendors.js文件中 vendors: { test: /[\\/]node_modules[\\/]/, priority: -10, filename: 'vendors.js' }, // 打包除上面vendors以外的公共模块 default: { priority: -20, reuseExistingChunks: true, // 如果该chunk已经被打包进其他模块了,这里就复用了,不打包进common.js了 filename: 'common.js' } } } }
新增test.js
export default { name: 'Dell Lee' }
入口文件index.js,引入test模块
import test from './test.js'; console.log(test.name);
打包后,自己编写test.js的公共模块打包成common.js文件
splitChunks: { chunk: 'all', // all(全部), async(异步的模块),initial(同步的模块) minSize: 3000, // 表示文件大于3000k的时候才对他进行打包 maxSize: 0, minChunks: 1, // 当某个模块满足minChunks引用次数时,才会被打包。例如,lodash只被一个文件import,那么lodash就不会被code splitting,lodash将会被打包进 被引入的那个文件中。如果满足minChunks引用次数,lodash会被单独抽离出来,打出一个chunk。 maxAsyncRequests: 5, // 在打包某个模块的时候,最多分成5个chunk,多余的会合到最后一个chunk中。这里分析下这个属性过大过小带来的问题。当设置的过大时,模块被拆的太细,造成并发请求太多。影响性能。当设置过小时,比如1,公共模块无法被抽离成公共的chunk。每个打包出来的模块都会有公共chunk automaticNameDelimiter: '~', // 当vendors或者default中的filename不填时,打包出来的文件名就会带~ name: true, cashGroups: {} // 如上 }
注意;chunk:'all' 默认等于下面一大窜的配置,我们一般默认all即可就行了
optimization: { // 代码分割配置 splitChunks: { chunks: 'all' } },
optimization: { splitChunks: { chunks: 'all', minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', name: true, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10, // filename: 'vendors.js', }, default: { priority: -20, reuseExistingChunk: true, filename: 'common.js' } } } },