3、基础配置入门:mode模式、entry入口、output输出与第一个Hello World构建

好,咱们正式开始动手配置了。

这一章是地基中的地基。你想想看,不管多复杂的构建流程,最后都绕不开这三个核心概念:modeentryoutput。说白了,就是告诉 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,打包上线用 productionnone 模式我几乎不用,除非你要做极细粒度的自定义优化。

配置方式很简单,在 webpack.config.js 里写:

module.exports = {
  mode: 'development', // 或者 'production' / 'none'
};

3.2 entry 入口配置:单入口 vs 多入口

entry 就是 Webpack 的起点。它告诉打包工具:「从哪个文件开始找依赖」。

3.2.1 单入口配置

大部分项目都是单入口。比如一个 Vue 或 React 项目,通常只有一个 main.jsindex.js

module.exports = {
  entry: './src/index.js',
};

这种写法最简洁。Webpack 会从 index.js 开始,递归解析所有 importrequire,最终打包成一个文件。

3.2.2 多入口配置

什么时候用多入口?举个例子:你有一个后台管理系统和一个前台展示页面,它们共用一些组件,但业务逻辑完全独立。这时候用多入口,可以分别打包出两个 HTML 文件。

module.exports = {
  entry: {
    admin: './src/admin.js',
    frontend: './src/frontend.js',
  },
};

注意,这里的 adminfrontend 是入口名称。它们会直接影响后面的 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.jsfrontend 入口会生成 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 文件的。