2、Webpack核心配置:理解entry、output、chunk、bundle的概念,搭建基础分割环境
好,咱们正式开始动手了。
这一节,我会带你搞清楚 Webpack 里四个最基础、也最容易混淆的概念:entry、output、chunk、bundle。说白了,它们是整个代码分割体系的基石。你不把这几个东西理清楚,后面做懒加载、做分包,很容易踩坑。
2.1 先聊聊 entry:一切打包的起点
entry 就是入口文件。Webpack 从哪个文件开始读,全靠它。
我个人习惯,单页应用通常只配一个入口:
// webpack.config.js
module.exports = {
entry: './src/index.js'
};
但如果你做多页应用,或者想把第三方库单独拎出来,就得配多个入口。比如:
module.exports = {
entry: {
main: './src/index.js',
vendor: './src/vendor.js'
}
};
这里有个细节要注意:每个 entry 最终都会生成一个独立的 chunk。chunk 是什么?别急,我马上讲。
2.2 output:打包完放哪儿?
output 就是告诉 Webpack:打包好的文件,存到哪个目录、叫什么名字。
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
}
};
这里 [name] 对应 entry 的 key 名,[contenthash] 是根据文件内容生成的哈希值。为什么要加哈希?因为浏览器缓存。文件内容变了,哈希就变,用户就能拿到新版本。
嗯,这里要注意:output 只决定了最终文件的输出位置和命名,它不决定怎么分割代码。分割逻辑,得靠 optimization 和动态导入。
2.3 chunk vs bundle:别再傻傻分不清
这两个词,我见过太多人混着用了。其实它们有本质区别:
| 概念 | 含义 | 存在阶段 |
|---|---|---|
| chunk | Webpack 打包过程中的代码块 | 构建过程中 |
| bundle | 最终输出的文件 | 构建完成后 |
说白了:chunk 是中间产物,bundle 是最终结果。
举个例子:你写了一个动态导入 import('./module.js'),Webpack 在构建时就会为它生成一个单独的 chunk。这个 chunk 经过处理、压缩后,最终输出成一个 bundle 文件。
核心理解:
- 一个 entry 对应一个或多个 chunk
- 一个 chunk 最终输出成一个 bundle
- 代码分割的本质,就是控制 chunk 的生成方式
2.4 搭建基础分割环境
好,理论讲完了,咱们动手搭个环境。我会带你配一个最简单的多入口分割。
先装依赖:
npm init -y
npm install webpack webpack-cli --save-dev
然后创建项目结构:
my-app/
├── src/
│ ├── index.js
│ └── another.js
├── dist/
├── webpack.config.js
└── package.json
写两个入口文件:
// src/index.js
console.log('这是主入口');
// src/another.js
console.log('这是另一个入口');
配置 webpack.config.js:
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js',
another: './src/another.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js'
}
};
运行 npx webpack,你会看到 dist 目录下生成了两个文件:
main.bundle.jsanother.bundle.js
这就是最基础的分割。每个入口独立打包,互不干扰。
SplitChunksPlugin 把公共依赖提取出来。这个咱们后面章节会详细讲。
2.5 动态导入:真正的懒加载起点
多入口分割虽然简单,但不够灵活。真正做懒加载,靠的是动态导入。
Webpack 原生支持 import() 语法。你写一个动态导入,Webpack 就会自动为它生成一个单独的 chunk。
举个例子:
// src/index.js
function loadModule() {
import('./module.js').then(module => {
module.default();
});
}
document.getElementById('btn').addEventListener('click', loadModule);
这里 import('./module.js') 就是一个动态导入。Webpack 会把它拆成一个独立的 chunk,只有点击按钮时才会加载。
配置上,你只需要在 output 里加一个 chunkFilename:
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
chunkFilename: '[name].chunk.js' // 动态导入生成的 chunk 命名
}
};
运行打包,你会看到 dist 里多了一个类似 src_module_js.chunk.js 的文件。这就是动态导入生成的 bundle。
/* webpackChunkName: "my-chunk" */ 魔法注释来命名:
import(/* webpackChunkName: "my-chunk" */ './module.js')
这样生成的 chunk 就会叫 my-chunk.chunk.js,调试时一眼就能认出来。
2.6 本章小结
这一节,我们搞清楚了:
- entry 是打包的起点,一个入口对应一个或多个 chunk
- output 控制最终文件的输出位置和命名
- chunk 是构建过程中的代码块,bundle 是最终输出的文件
- 多入口分割和动态导入,是两种最基础的分割方式
下一节,我们会深入 SplitChunksPlugin,看看怎么把公共依赖提取出来,避免重复打包。你想想看,如果每个页面都引了 React,那得浪费多少带宽?
好,先到这。动手试试上面的配置,有问题咱们下节聊。