为什么写这篇:Webpack 4 在 2018-02 正式发布(zero-config 概念),5 在 2018 之后逐步成为标准。即使 2024 年 Vite/Rspack 已经在性能上超越 Webpack,老项目的维护、monorepo 工具链、底层 loader 插件开发仍离不开它。理解 Webpack 的"打包图"思想,是所有前端工程化工具的根。
适用读者:刚开始接触前端构建工具的同学;想从零跑通"写 ES6 → 浏览器能跑"全流程的初学者。
前置知识:会写
npm install、了解package.json、写过简单 HTML/JS。
目录
- 什么是 Webpack
- 最小可跑 demo
- Babel:让"新语法"跑到"老浏览器"
- 为什么需要 –save 和 –save-dev
- 常见 loader / plugin 一览
- 从 Webpack 1 到 5:核心演进
- 常见问题与排错
1. 什么是 Webpack
Webpack 是一个静态模块打包器(static module bundler)。它从入口文件(entry)出发,递归解析所有 import/require,把 JS、CSS、图片、字体等所有静态资源当作"模块"处理,最终输出浏览器能直接加载的静态文件(bundle)。
核心思想:一切皆模块。
import './style.css'在 Webpack 眼里和import './utils.js'一样——只是需要不同的 loader 来"翻译"。
Webpack 4 大核心概念:
| 概念 | 一句话 |
|---|---|
| Entry | 入口,Webpack 从哪个文件开始构建依赖图 |
| Output | 打包后的文件输出到哪里 |
| Loader | 让 Webpack 能处理非 JS 文件(CSS/图片/TS/Vue 等) |
| Plugin | 解决 loader 之外的所有事(压缩、热更新、清理 dist、环境变量注入…) |
2. 最小可跑 demo
| |
跑完会生成 dist/main.js。完整目录:
| |
src/index.js:
| |
跑 npx webpack 时,Webpack 会自动:
- 把
src/index.js当作入口 - 解析
import _ from 'lodash'→ 把 lodash 整包也打进来 - 把
dist/main.js作为默认输出
默认约定:Webpack 4+ 引入 zero-config 概念,不写
webpack.config.js也能跑——entry 默认为src/index.js,output 默认为dist/main.js,mode 默认为production。
3. Babel:让"新语法"跑到"老浏览器"
Babel 是一个 JavaScript 编译器(准确说叫"转译器" transpiler):
- 输入:用下一代 JavaScript 语法(ES2015+、JSX、TypeScript)写的代码
- 输出:浏览器能兼容的 JavaScript 代码
| |
Why:浏览器的 JavaScript 引擎对新语法的支持永远滞后于规范。2015 年 ES2015 发布时,主流浏览器(IE11、UC、老 Safari)都不支持
const/ 箭头函数 /class。Babel 让开发者能写"未来语法",由它编译到"老语法"。
3.1 Webpack 集成 Babel 7
| |
webpack.config.js:
| |
@babel/preset-env 是"智能预设"——你告诉它目标浏览器范围(browserslist 配置),它自动决定要转译哪些语法。
package.json 加上 browserslist:
| |
小贴士:现代项目(Chrome 90+、Node 18+)可以直接在 browserslist 里写
"defaults, not IE 11",Babel 就只对真正需要的目标做 polyfill,bundle 体积能少 30%+。
4. 为什么需要 –save 和 –save-dev
这是新人最容易搞混的概念:
| 命令 | 写入 package.json 哪个字段 | 含义 |
|---|---|---|
npm install --save(-S) | dependencies | 生产环境需要的包(运行时被打进 bundle) |
npm install --save-dev(-D) | devDependencies | 开发环境才需要的包(构建、测试、代码检查) |
| |
执行 npm install(不带包名)时,npm 会同时安装 dependencies 和 devDependencies 中的所有模块。生产环境(npm install --production 或 NODE_ENV=production)只装 dependencies。
小贴士:Vue/React 框架本身(
vue、react、react-dom)要--save,而vue-loader、@babel/preset-env、webpack、eslint都要--save-dev。
5. 常见 loader / plugin 一览
| 类别 | 名称 | 用途 |
|---|---|---|
| JS | babel-loader | 配合 Babel 转译 JS/JSX/TS |
ts-loader | 直接用 TypeScript 编译器 | |
| CSS | css-loader | 把 CSS 变成 JS 模块(import './style.css') |
style-loader | 把 CSS 注入到 <style> 标签 | |
postcss-loader | 自动加浏览器前缀、CSS 嵌套等 | |
sass-loader / less-loader | 编译 SCSS / Less | |
| 图片/字体 | asset/resource (Webpack 5 内置) | 输出文件,导出 URL |
asset/inline (Webpack 5 内置) | 内联为 base64(小图) | |
| 框架 | vue-loader | 解析 .vue 单文件组件 |
| 文件 | file-loader(已废弃) | 旧版输出文件(Webpack 5 用 asset/resource) |
| 压缩 | terser-webpack-plugin(Webpack 5 默认) | 压缩 JS |
css-minimizer-webpack-plugin | 压缩 CSS | |
compression-webpack-plugin | 生成 .gz 文件 | |
| 其他 | html-webpack-plugin | 自动生成 HTML 并注入 bundle |
clean-webpack-plugin / output.clean | 每次构建清空 dist | |
mini-css-extract-plugin | CSS 抽离成独立文件(不再内联到 JS) | |
webpack-dev-server | 启动开发服务器 + HMR 热更新 | |
webpack-bundle-analyzer | 可视化分析 bundle 体积 |
Webpack 5 重要变化:
- 资源模块(Asset Modules) 内置了 4 种类型(
asset/resource/asset/inline/asset/source/asset),不再需要file-loader/url-loader- 持久化缓存 默认开启,构建速度提升 5-10 倍
- Module Federation 微前端方案正式 GA
- Tree Shaking 加强,对 CommonJS、
sideEffects字段支持更好
6. 从 Webpack 1 到 5:核心演进
| 版本 | 年份 | 关键特性 |
|---|---|---|
| 1.x | 2014 | 第一版,配置繁琐但改变前端 |
| 2.x | 2017 | 引入 tree shaking、scope hosting |
| 3.x | 2017 | Scope Hoisting、魔法注释 /* webpackChunkName */ |
| 4.x | 2018-02 | zero-config(默认 entry/output)、mode、sideEffects |
| 5.x | 2020-10 | 资源模块、持久化缓存、Module Federation、长期缓存 |
大版本迁移痛点:Webpack 4 → 5 主要是
file-loader/url-loader/raw-loader替换为 asset modules,以及node-polyfill-webpack-plugin处理内置模块的 polyfill(如crypto、buffer)。
7. 常见问题与排错
7.1 报错 “Module not found”
99% 是路径写错。Webpack 5 默认不允许绝对路径,必须写相对路径或配 resolve.alias。
| |
7.2 报错 “Can’t resolve ‘vue’ in …”
依赖没装对版本,或在 vue.config.js 配了 externals 但忘记在 HTML 里用 CDN 引。先 rm -rf node_modules && npm install 排除 80% 情况。
7.3 构建慢 / 体积大
| 优化项 | 作用 |
|---|---|
mode: 'production' | 自动启用 tree shaking + 压缩 |
optimization.splitChunks | 把 node_modules 抽成 vendor,浏览器缓存更久 |
externals: { vue: 'Vue' } | 通过 CDN 引入 Vue/React,业务 bundle 体积减半 |
productionSourceMap: false | 不生成 .map 文件(生产环境不需要) |
terser-webpack-plugin 配 parallel: true | 多进程压缩 |
| 升级到 Webpack 5 | 持久化缓存,开机慢、增量快 |
7.4 浏览器缓存命中低
| |
contenthash 是内容哈希——文件没变,文件名不变,浏览器强缓存命中;文件改了,文件名变,强制刷新。
小结:Webpack 学习路线
- 会用:跑通
npx webpack跑一个 demo → 配webpack.config.js加上 babel/css-loader - 会配:理解 entry/output/loader/plugin/mode 五大件
- 会调:会用
splitChunks/contenthash/analyzer优化产物体积 - 会写 loader/plugin:读懂 Webpack 的 tapable 钩子系统,写一个自定义插件
- 会迁移:Webpack 4 → 5,老项目升级
下一步:2024 年起,更多新项目直接用 Vite(开发时按需 ESM、生产时 Rollup 打包),启动速度比 Webpack 快 10-100 倍。但 Vite 的生产构建底层还是 Rollup,且大量 Vite 插件的接口与 Webpack 兼容。本文讲的 loader/plugin 思想 100% 适用。
