浅析webpack里module/chunk/bundle区别、filename/chunkFilename区别、webpackChunkName作用、webpackPrefetch预拉取/webpackPreloa预加载作用与区别
一、module
,chunk
和 bundle
的区别
看 webpack 文档的时候,对这 3 个名词云里雾里的,感觉他们都在说打包文件,但是一会儿 chunk 一会儿 bundle 的,逐渐就迷失在细节里了,所以我们要跳出来,从宏观的角度来看这几个名词。
webpack 官网对 chunk 和 bundle 做出了解释,说实话太抽象了,我这里举个例子,给大家形象化的解释一下。
首先我们在 src 目录下写我们的业务代码,引入 index.js、utils.js、common.js 和 index.css 这 4 个文件,目录结构如下
src/
├── index.css
├── index.html # 这个是 HTML 模板代码
├── index.js
├── common.js
└── utils.js
// index.css 写一点儿简单的样式:
body {
background-color: red;
}
// utils.js 文件写个求平方的工具函数:
export function square(x) {
return x * x;
}
// common.js 文件写个 log 工具函数:
module.exports = {
log: (msg) => {
console.log('hello ', msg)
}
}
// index.js 文件做一些简单的修改,引入 css 文件和 common.js:
import './index.css';
const { log } = require('./common');
log('webpack');
webpack 的配置如下:
{
entry: {
index: "../src/index.js",
utils: '../src/utils.js',
},
output: {
filename: "[name].bundle.js", // 输出 index.js 和 utils.js
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 创建一个 link 标签
'css-loader', // css-loader 负责解析 CSS 代码, 处理 CSS 中的依赖
],
},
]
}
plugins: [
// 用 MiniCssExtractPlugin 抽离出 css 文件,以 link 标签的形式引入样式文件
new MiniCssExtractPlugin({
filename: 'index.bundle.css' // 输出的 css 文件名为 index.css
}),
]
}
我们运行一下 webpack,看一下打包的结果,可以看出:
(1)index.css 和 common.js 在 index.js 中被引入,打包生成的 index.bundle.css 和 index.bundle.js 都属于 chunk 0
(2)utils.js 因为是独立打包的,它生成的 utils.bundle.js 属于 chunk 1
1、具体解释:
对于一份同逻辑的代码,当我们手写下一个一个的文件,它们无论是 ESM 还是 commonJS 或是 AMD,他们都是 module ;
当我们写的 module 源文件传到 webpack 进行打包时,webpack 会根据文件引用关系生成 chunk 文件,webpack 会对这个 chunk 文件进行一些操作;
webpack 处理好 chunk 文件后,最后会输出 bundle 文件,这个 bundle 文件包含了经过加载和编译的最终源文件,所以它可以直接在浏览器中运行。
2、一般来说一个 chunk 对应一个 bundle,比如上图中的 utils.js -> chunks 1 -> utils.bundle.js
;但也有例外,比如说上图中,我就用 MiniCssExtractPlugin
从 chunks 0 中抽离出了 index.bundle.css
文件。
3、小结:
module
,chunk
和 bundle
其实就是同一份逻辑代码在不同转换场景下的取了三个名字:我们直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。
二、filename
和 chunkFilename
的区别
1、filename 是一个很常见的配置,就是对应于 entry
里面的输入文件,经过webpack 打包后输出文件的文件名。比如说经过下面的配置,生成出来的文件名为 index.min.js
。
{
entry: {
index: "../src/index.js"
},
output: {
filename: "[name].min.js", // index.min.js
}
}
2、chunkFilename
指未被列在 entry
中,却又需要被打包出来的 chunk
文件的名称。一般来说,这个 chunk
文件指的就是要懒加载的代码。比如说我们业务代码中写了一份懒加载 lodash
的代码:
// 文件:index.js
// 创建一个 button
let btn = document.createElement("button");
btn.innerHTML = "click me";
document.body.appendChild(btn);
// 异步加载代码
async function getAsyncComponent() {
var element = document.createElement('div');
const { default: _ } = await import('lodash');
element.innerHTML = _.join(['Hello!', 'dynamic', 'imports', 'async'], ' ');
return element;
}
// 点击 button 时,懒加载 lodash,在网页上显示 Hello! dynamic imports async
btn.addEventListener('click', () => {
getAsyncComponent().then(component => {
document.body.appendChild(component);
})
})
我们的 webpack
不做任何配置,还是原来的配置代码。
{
entry: {
index: "../src/index.js"
},
output: {
filename: "[name].min.js",
}
}
这时候的打包结果会多出一个 1.min.js, 这个1.min.js就是异步加载的 chunk
文件。文档里这么解释:
output.chunkFilename
默认使用[id].js
或从output.filename
中推断出的值([name]
会被预先替换为[id]
或[id].
)
文档写的太抽象,我们不如结合上面的例子来看:
(1)output.filename
的输出文件名是 [name].min.js
,[name]
根据 entry
的配置推断为 index
,所以输出为 index.min.js
;
(2)由于 output.chunkFilename
没有显示指定,就会把 [name]
替换为 chunk
文件的 id
号,这里文件的 id
号是 1,所以文件名就是 1.min.js
。
如果我们显式配置 chunkFilename
,就会按配置的名字生成文件:
{
entry: {
index: "../src/index.js"
},
output: {
filename: "[name].min.js", // index.min.js
chunkFilename: 'bundle.js', // bundle.js
}
}
3、小结
filename
指列在 entry
中,打包后输出的文件的名称。
chunkFilename
指未列在 entry
中,却又需要被打包出来的文件的名称。
三、webpackPrefetch
、webpackPreload
和 webpackChunkName
是干什么的?
1、webpackChunkName
前面举了个异步加载 lodash
的例子,我们最后把 output.chunkFilename
写死成 bundle.js
。在我们的业务代码中,不可能只异步加载一个文件,所以写死肯定是不行的,但是写成 [name].bundle.js
时,打包的文件又是意义不明、辨识度不高的 chunk id
{
entry: {
index: "../src/index.js"
},
output: {
filename: "[name].min.js", // index.min.js
chunkFilename: '[name].bundle.js', // 1.bundle.js,chunk id 为 1,辨识度不高
}
}
这时候 webpackChunkName
就可以派上用场了。我们可以在 import
文件时,在 import
里以注释的形式为 chunk 文件取别名
async function getAsyncComponent() {
var element = document.createElement('div');
// 在 import 的括号里 加注释 /* webpackChunkName: "lodash" */ ,为引入的文件取别名
const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash');
element.innerHTML = _.join(['Hello!', 'dynamic', 'imports', 'async'], ' ');
return element;
}
2、webpackPrefetch 和 webpackPreload
这两个配置一个叫预拉取(Prefetch),一个叫预加载(Preload),两者有些细微的不同。
(1)我们先说说 webpackPrefetch
。在上面的懒加载代码里,我们是点击按钮时,才会触发异步加载 lodash
的动作,这时候会动态的生成一个 script
标签,加载到 head
头里。
如果我们 import
的时候添加 webpackPrefetch
:
const { default: _ } = await import(/* webpackChunkName: "lodash" */ /* webpackPrefetch: true */ 'lodash');
就会以 <link rel="prefetch" as="script">
的形式预拉取 lodash 代码,这个异步加载的代码不需要手动点击 button 触发,webpack 会在父 chunk 完成加载后,闲时加载 lodash
文件。
(2)webpackPreload
是预加载当前导航下可能需要资源,他和 webpackPrefetch
的主要区别是:
preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻
预拉取:父chunk结束后加载;闲时加载,优先级低;未来时刻。
预加载:父chunk加载时并行加载;立即加载,中等优先级;当下时刻。
3、小结:
webpackChunkName
是为预加载的文件取别名,webpackPrefetch
会在浏览器闲置下载文件,webpackPreload
会在父 chunk 加载时并行下载文件。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2017-06-20 浅析如何让css元素左侧自动溢出(即 ... 溢出在左侧):direction 属性
2017-06-20 小知识随手记:验证文件名、hover用法、雪碧图,获取上传图片尺寸大小、js去除富文本里的标签和空格、getComputedStyle与currentStyle获取样式(style/class)