3、核心配置之Entry:单入口与多入口配置、动态入口、entry的context选项、依赖图与chunk概念
好,咱们今天来聊聊 Webpack 的入口配置。说真的,Entry 是整个打包流程的起点,你告诉 Webpack 从哪个文件开始干活,它就顺着依赖关系一路找下去。我见过不少新手,上来就复制粘贴配置,结果项目一复杂就崩了。嗯,咱们今天把这几个核心概念彻底讲透。
3.1 单入口配置:最基础的玩法
单入口,说白了就是一个项目只有一个 HTML 页面,所有 JS 都从 index.js 开始。我个人习惯用这种配置做小型项目或者后台管理系统。
// webpack.config.js
module.exports = {
entry: './src/index.js'
};
这种写法最简洁。Webpack 会自动把 index.js 以及它引用的所有模块打包成一个 bundle.js。我在项目中遇到过,有人把入口写成 entry: ['./src/index.js', './src/utils.js'],以为这样能打两个包。其实不是,这样写是把多个文件合并成一个入口,最终还是一个 bundle。
[name].js,默认的 name 就是 main。如果你想要自定义,可以写成 entry: { main: './src/index.js' }。
3.2 多入口配置:多页面应用的标配
多入口就更有意思了。你想想看,一个电商网站,首页、商品详情页、购物车,每个页面都有自己的 JS 逻辑。如果全塞到一个 bundle 里,首屏加载会慢得离谱。这时候就需要多入口。
module.exports = {
entry: {
home: './src/home.js',
product: './src/product.js',
cart: './src/cart.js'
}
};
每个入口都会生成一个独立的 chunk。我记得有一次做重构,老项目有 20 多个页面,我全部改成了多入口配置。配合 HtmlWebpackPlugin,每个页面只加载自己的 JS,性能提升非常明显。
[name].bundle.js,否则会报错。因为 Webpack 不知道多个入口该用哪个名字输出。
3.3 动态入口:灵活应对复杂场景
动态入口,这个是我觉得最酷的功能。有时候入口文件不是写死的,而是根据环境变量或者文件系统动态生成的。比如,你有一个插件系统,每个插件都有自己的入口。
// 动态入口示例
const fs = require('fs');
const path = require('path');
function getEntries() {
const entries = {};
const pages = fs.readdirSync('./src/pages');
pages.forEach(page => {
const entryPath = path.join('./src/pages', page, 'index.js');
if (fs.existsSync(entryPath)) {
entries[page] = entryPath;
}
});
return entries;
}
module.exports = {
entry: getEntries()
};
我曾经在一个 CMS 项目里用过这个技巧。每次新增一个页面模块,只需要在 pages 目录下新建文件夹,Webpack 自动识别并生成对应的入口。省去了手动修改配置的麻烦。
3.4 entry 的 context 选项:路径的根目录
context 这个选项,说实话很多人容易忽略。它决定了 Webpack 解析入口文件时的根目录。默认是 process.cwd(),也就是你运行 webpack 命令的目录。
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: './index.js' // 实际指向 src/index.js
};
为什么要用 context?我遇到过最坑的情况:团队里有人用 Windows,有人用 Mac,路径分隔符不一样。设置 context 后,所有入口路径都基于这个根目录,跨平台兼容性会好很多。
context: __dirname,问题就解决了。
3.5 依赖图与 chunk 概念:Webpack 的核心思维
依赖图,这是 Webpack 最核心的概念。你想想看,Webpack 从入口开始,遇到 import 或 require 就继续往下找,最终形成一张巨大的依赖关系网。这张网就是依赖图。
而 chunk,就是依赖图被切割后的产物。每个入口对应一个 chunk,但 chunk 不一定是入口。比如,你用 SplitChunksPlugin 抽离公共代码,那些公共模块也会形成独立的 chunk。
// 依赖图示例
// index.js
import { format } from './utils';
import './style.css';
// utils.js
import { add } from 'lodash';
export function format() { ... }
// 依赖图:
// index.js → utils.js → lodash
// → style.css
我刚开始学 Webpack 时,一直搞不清 chunk 和 bundle 的区别。后来才明白:chunk 是 Webpack 内部的概念,是代码分割后的逻辑单元;bundle 是最终输出的文件。一个 chunk 可能对应一个 bundle,也可能被拆成多个(比如异步加载)。
| 概念 | 说明 | 例子 |
|---|---|---|
| Entry | 打包的起点 | ./src/index.js |
| Module | 每个被引用的文件 | utils.js, lodash |
| Chunk | 代码分割后的代码块 | main.chunk.js, vendors.chunk.js |
| Bundle | 最终输出的文件 | main.bundle.js |
为什么会这样设计?说白了,就是为了性能。如果所有代码打成一个包,首屏加载会慢。通过 chunk 拆分,你可以实现按需加载、并行加载、缓存复用。我建议你在做大型项目时,一定要理解 chunk 的概念,否则优化无从下手。
嗯,关于 Entry 的核心配置,今天就聊这么多。记住一句话:入口决定了起点,依赖图决定了路径,chunk 决定了输出。下一章咱们聊聊 Output,看看打包出来的文件怎么命名、怎么存放。