3、基础配置入门:mode模式、entry入口、output输出与第一个Hello World构建
好,咱们正式开始动手配置了。
这一章是地基中的地基。你想想看,不管多复杂的构建流程,最后都绕不开这三个核心概念:mode、entry、output。说白了,就是告诉 Webpack「用什么模式干活、从哪开始、干完活放哪」。
我个人习惯,每学一个新工具,先跑通一个 Hello World。这比看十遍文档都管用。咱们今天就干这件事。
3.1 mode 模式:开发、生产、还是裸奔?
mode 是 Webpack 4 之后引入的。它的作用很简单——一键切换内置优化。
有三种可选值:
| 模式 | 值 | 特点 |
|---|---|---|
| 开发模式 | development |
速度快,保留源码映射,方便调试 |
| 生产模式 | production |
自动压缩、Tree Shaking,体积最小化 |
| 无模式 | none |
啥优化都不做,裸奔状态 |
核心区别:production 模式下,Webpack 会自动启用 DefinePlugin 设置 process.env.NODE_ENV 为 'production',并开启代码压缩。而 development 模式则默认关闭压缩,并启用 NamedModulesPlugin 方便你看到模块名。
我在项目中遇到过一个问题:有同事把 mode 设成了 none,结果上线后代码体积大了三倍。嗯,这就是忘了告诉 Webpack「该干活了」。
我的建议:日常开发用 development,打包上线用 production。none 模式我几乎不用,除非你要做极细粒度的自定义优化。
配置方式很简单,在 webpack.config.js 里写:
module.exports = {
mode: 'development', // 或者 'production' / 'none'
};
3.2 entry 入口配置:单入口 vs 多入口
entry 就是 Webpack 的起点。它告诉打包工具:「从哪个文件开始找依赖」。
3.2.1 单入口配置
大部分项目都是单入口。比如一个 Vue 或 React 项目,通常只有一个 main.js 或 index.js。
module.exports = {
entry: './src/index.js',
};
这种写法最简洁。Webpack 会从 index.js 开始,递归解析所有 import 和 require,最终打包成一个文件。
3.2.2 多入口配置
什么时候用多入口?举个例子:你有一个后台管理系统和一个前台展示页面,它们共用一些组件,但业务逻辑完全独立。这时候用多入口,可以分别打包出两个 HTML 文件。
module.exports = {
entry: {
admin: './src/admin.js',
frontend: './src/frontend.js',
},
};
注意,这里的 admin 和 frontend 是入口名称。它们会直接影响后面的 output 文件名。
我曾经踩过的坑:多入口时,如果两个入口文件引用了同一个第三方库(比如 lodash),Webpack 默认会把 lodash 分别打包进两个文件里。结果就是代码重复,体积翻倍。解决办法是用 SplitChunksPlugin 提取公共模块。这个后面会细讲,你先留个印象。
3.3 output 输出配置:path、filename、publicPath
output 告诉 Webpack:「打包好的文件放哪、叫什么名字、资源路径怎么处理」。
3.3.1 path:输出目录
path 指定打包后的文件存放的绝对路径。通常我们会用 Node.js 的 path 模块来拼接:
const path = require('path');
module.exports = {
output: {
path: path.resolve(__dirname, 'dist'),
},
};
这样打包后的文件就会全部放到项目根目录下的 dist 文件夹里。
3.3.2 filename:输出文件名
filename 控制打包后的 JS 文件名。单入口时很简单:
output: {
filename: 'bundle.js',
}
多入口时,你需要用占位符 [name] 来动态生成文件名:
output: {
filename: '[name].bundle.js',
}
这样,admin 入口会生成 admin.bundle.js,frontend 入口会生成 frontend.bundle.js。
常用的占位符还有:
[hash]:整个构建过程的唯一 hash[chunkhash]:每个 chunk 的唯一 hash,用于缓存控制[contenthash]:根据文件内容生成的 hash,更精确
我个人习惯:生产环境用 [contenthash],开发环境用 [name]。因为开发时频繁改代码,hash 变化会导致浏览器缓存失效,调试起来很烦。
3.3.3 publicPath:资源公共路径
这个配置容易让人迷糊。我换个说法:publicPath 决定了打包后的 JS、CSS、图片等资源在 HTML 中引用时的前缀路径。
举个例子:
output: {
publicPath: '/assets/',
}
那么打包后的 bundle.js 在 HTML 中会被引用为 /assets/bundle.js。
如果你把静态资源部署到 CDN,可以这样写:
output: {
publicPath: 'https://cdn.example.com/',
}
这样所有资源都会指向 CDN 地址。
我曾经犯过的错:有次把项目部署到子目录 /admin/ 下,但忘了改 publicPath。结果所有资源都去根目录找,页面白屏。排查了半天才发现是路径问题。所以记住:publicPath 是给浏览器看的,不是给 Webpack 看的。
3.4 第一个 Hello World 构建
理论说完了,咱们动手跑一个。
先创建项目结构:
my-webpack-demo/
├── src/
│ └── index.js
├── dist/
├── package.json
└── webpack.config.js
第一步:初始化项目
npm init -y
npm install webpack webpack-cli --save-dev
第二步:写源码
src/index.js:
function hello() {
console.log('Hello, Webpack!');
}
hello();
第三步:配置 webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/',
},
};
第四步:在 package.json 中添加脚本
"scripts": {
"build": "webpack"
}
第五步:运行
npm run build
你会看到终端输出类似这样的信息:
asset bundle.js 4.21 KiB [emitted] (name: main)
runtime modules 670 bytes 3 modules
./src/index.js 57 bytes [built] [code generated]
打开 dist/bundle.js,你会看到 Webpack 打包后的代码。虽然比源码多了很多「包装代码」,但核心逻辑还在。
恭喜你!你已经完成了第一个 Webpack 构建。虽然只是打印了一行 Hello World,但整个流程——从配置到打包——你已经走通了。后面的所有内容,都是在这个基础上做加法。
嗯,这一章就到这。下一章我们会聊聊 loader,看看 Webpack 是怎么处理 CSS、图片这些非 JS 文件的。