????????默认情况下,Webpack 会将所有代码构建成一个单独的包,这在小型项目通常不会有明显的性能问题,但伴随着项目的推进,包体积逐步增长可能会导致应用的响应耗时越来越长。归根结底这种将所有资源打包成一个文件的方式存在两个弊端:
????????这些问题都可以通过代码分离解决,例如?node_modules
?中的资源通常变动较少,可以抽成一个独立的包,那么业务代码的频繁变动不会导致这部分第三方库资源被无意义地重复加载。
const path = require('path');
module.exports = {
entry: {
main: './src/main.js', // 第一个入口起点
app: './src/app.js' // 第二个入口起点
},
output: {
filename: '[name].bundle.js', // 使用[name]占位符将生成的文件名与入口起点名称对应
path: path.resolve(__dirname, 'build')
} ,
};
const path = require('path');
module.exports = {
entry: {
main: { import: './src/main.js', dependOn: 'shared' }, // 第一个入口起点
app: { import: './src/app.js', dependOn: 'shared' }, // 第二个入口起点
shared: ['dayjs', 'lodash'] // 共享的库
},
output: {
filename: '[name].bundle.js', // 使用[name]占位符将生成的文件名与入口起点名称对应
path: path.resolve(__dirname, 'dist') }
};
Webpack 提供了?SplitChunkPlugin?进行分包优化。SplitChunksPlugin 插件可以将应用程序中共享的代码拆分成单独的块,以便将其从应用程序代码中分离出来,从而提高性能和加载速度。它的优化原理如下:
SplitChunksPlugin 会分析模块之间的依赖关系,并根据这些关系确定哪些模块可以组成一个共享块。这样可以确保代码被正确地分离,而不会出现意外的行为。
SplitChunksPlugin 根据配置项生成共享块。配置项包括?minSize
(指定共享块的最小大小)、maxSize
(指定共享块的最大大小)、minChunks
(指定一个模块至少被使用的次数才会被拆分成共享块)等。
在分析和生成共享块后,SplitChunksPlugin 会将共享块提取出来,并创建新的?chunk
(即打包后的文件),将这些共享块放入新的 chunk 中。这样,每个共享块只需被下载一次,而不必重复下载多次,从而提高了应用程序的加载速度。
为了进一步提高性能,SplitChunksPlugin 会将共享块缓存起来,并在后续的构建中重复使用它们。这样,如果某个共享块已经存在于缓存中,就不必再重新生成它,从而节省了构建时间。
????????当代码中存在不确定会被使用的模块时,最佳做法是将其分离为一个独立的 JavaScript 文件。
实现动态导入的方式是使用ES6的import()
语法来完成。
动态导入最常见的使用场景就是路由懒加载
// main.js文件中
const homeBtn = document.createElement('button')
const aboutBtn = document.createElement('button')
homeBtn.textContent = '加载home文件'
aboutBtn.textContent = '加载about文件'
document.body.appendChild(homeBtn)
document.body.appendChild(aboutBtn)
homeBtn.addEventListener('click', () => {
import('./views/home.js')
})
aboutBtn.addEventListener('click', () => {
import('./views/about.js')
})
打包之后的资源:?
但是我们会发现一个问题,从包名中无法区分是哪个文件构建后的包,我们可以通过以下方式修改打包之后的文件名:
output.chunkFilename
const { resolve } = require('path');
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: resolve(__dirname, 'build'),
chunkFilename: 'chunk_[name]_[id].js',
},
};
默认情况下我们获取到的 [name] 和 [id] 的名称保持一致的,如果我们希望修改name的值,可以通过magic comments(魔法注释)的方式;
// main.js
homeBtn.addEventListener('click', () => {
import(/* webpackChunkName: "home" */'./views/home.js') // 让webpack读取的魔法注释,固定写法
})
aboutBtn.addEventListener('click', () => {
import(/* webpackChunkName: "about" */'./views/about.js')
})
打包之后的资源,可以从名称看出原始文件是哪一个?
参考: