Featured image of post 前端工程化基石:Webpack 5 与 Babel 编译

前端工程化基石:Webpack 5 与 Babel 编译

从 Webpack 1.x 时代走过来的前端工程师,几乎都从 npm init + webpack 起步。本文用最小 demo 跑通 Webpack 打包流程,再用最简方式解释 Babel 是什么、为什么需要它,以及 Webpack 4/5 的常见配置点。

为什么写这篇:Webpack 4 在 2018-02 正式发布(zero-config 概念),5 在 2018 之后逐步成为标准。即使 2024 年 Vite/Rspack 已经在性能上超越 Webpack,老项目的维护、monorepo 工具链、底层 loader 插件开发仍离不开它。理解 Webpack 的"打包图"思想,是所有前端工程化工具的根。

适用读者:刚开始接触前端构建工具的同学;想从零跑通"写 ES6 → 浏览器能跑"全流程的初学者。

前置知识:会写 npm install、了解 package.json、写过简单 HTML/JS。

目录

  1. 什么是 Webpack
  2. 最小可跑 demo
  3. Babel:让"新语法"跑到"老浏览器"
  4. 为什么需要 –save 和 –save-dev
  5. 常见 loader / plugin 一览
  6. 从 Webpack 1 到 5:核心演进
  7. 常见问题与排错

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

1
2
3
4
5
mkdir webpack-demo1 && cd webpack-demo1
npm init -y
npm install webpack webpack-cli --save-dev
npm install --save lodash
npx webpack

跑完会生成 dist/main.js。完整目录:

1
2
3
4
5
6
7
8
webpack-demo1/
├── dist/
│   └── main.js              # 打包后的产物
├── node_modules/
├── package.json
├── package-lock.json
└── src/
    └── index.js             # 你的入口文件

src/index.js

1
2
3
4
5
6
7
8
9
import _ from 'lodash'

function component() {
  const element = document.createElement('div')
  element.innerHTML = _.join(['Hello', 'webpack'], ' ')
  return element
}

document.body.appendChild(component())

npx webpack 时,Webpack 会自动:

  1. src/index.js 当作入口
  2. 解析 import _ from 'lodash' → 把 lodash 整包也打进来
  3. 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 代码
1
2
3
4
5
6
7
// 输入(你写的)
const greet = (name) => `Hello, ${name}!`

// 输出(babel 编译后)
var greet = function greet(name) {
  return 'Hello, ' + name + '!'
}

Why:浏览器的 JavaScript 引擎对新语法的支持永远滞后于规范。2015 年 ES2015 发布时,主流浏览器(IE11、UC、老 Safari)都不支持 const / 箭头函数 / class。Babel 让开发者能写"未来语法",由它编译到"老语法"。

3.1 Webpack 集成 Babel 7

1
npm install -D babel-loader @babel/core @babel/preset-env

webpack.config.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
}

@babel/preset-env 是"智能预设"——你告诉它目标浏览器范围(browserslist 配置),它自动决定要转译哪些语法。

package.json 加上 browserslist:

1
2
3
4
5
6
7
8
{
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead",
    "ie >= 11"
  ]
}

小贴士:现代项目(Chrome 90+、Node 18+)可以直接在 browserslist 里写 "defaults, not IE 11",Babel 就只对真正需要的目标做 polyfill,bundle 体积能少 30%+。


4. 为什么需要 –save 和 –save-dev

这是新人最容易搞混的概念:

命令写入 package.json 哪个字段含义
npm install --save-Sdependencies生产环境需要的包(运行时被打进 bundle)
npm install --save-dev-DdevDependencies开发环境才需要的包(构建、测试、代码检查)
1
2
npm install webpack webpack-cli --save-dev   # 构建工具,上线不需要
npm install lodash --save                    # 运行时要用 lodash

执行 npm install(不带包名)时,npm 会同时安装 dependenciesdevDependencies 中的所有模块。生产环境(npm install --productionNODE_ENV=production)只装 dependencies

小贴士:Vue/React 框架本身(vuereactreact-dom)要 --save,而 vue-loader@babel/preset-envwebpackeslint 都要 --save-dev


5. 常见 loader / plugin 一览

类别名称用途
JSbabel-loader配合 Babel 转译 JS/JSX/TS
ts-loader直接用 TypeScript 编译器
CSScss-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-pluginCSS 抽离成独立文件(不再内联到 JS)
webpack-dev-server启动开发服务器 + HMR 热更新
webpack-bundle-analyzer可视化分析 bundle 体积

Webpack 5 重要变化

  1. 资源模块(Asset Modules) 内置了 4 种类型(asset/resource / asset/inline / asset/source / asset),不再需要 file-loader / url-loader
  2. 持久化缓存 默认开启,构建速度提升 5-10 倍
  3. Module Federation 微前端方案正式 GA
  4. Tree Shaking 加强,对 CommonJS、sideEffects 字段支持更好

6. 从 Webpack 1 到 5:核心演进

版本年份关键特性
1.x2014第一版,配置繁琐但改变前端
2.x2017引入 tree shaking、scope hosting
3.x2017Scope Hoisting、魔法注释 /* webpackChunkName */
4.x2018-02zero-config(默认 entry/output)、mode、sideEffects
5.x2020-10资源模块、持久化缓存、Module Federation、长期缓存

大版本迁移痛点:Webpack 4 → 5 主要是 file-loader/url-loader/raw-loader 替换为 asset modules,以及 node-polyfill-webpack-plugin 处理内置模块的 polyfill(如 cryptobuffer)。


7. 常见问题与排错

7.1 报错 “Module not found”

99% 是路径写错。Webpack 5 默认不允许绝对路径,必须写相对路径或配 resolve.alias

1
2
3
4
5
6
// webpack.config.js
resolve: {
  alias: {
    '@': path.resolve(__dirname, 'src')
  }
}

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-pluginparallel: true多进程压缩
升级到 Webpack 5持久化缓存,开机慢、增量快

7.4 浏览器缓存命中低

1
2
3
4
output: {
  filename: '[name].[contenthash:8].js',
  chunkFilename: '[name].[contenthash:8].chunk.js'
}

contenthash 是内容哈希——文件没变,文件名不变,浏览器强缓存命中;文件改了,文件名变,强制刷新。


小结:Webpack 学习路线

  1. 会用:跑通 npx webpack 跑一个 demo → 配 webpack.config.js 加上 babel/css-loader
  2. 会配:理解 entry/output/loader/plugin/mode 五大件
  3. 会调:会用 splitChunks / contenthash / analyzer 优化产物体积
  4. 会写 loader/plugin:读懂 Webpack 的 tapable 钩子系统,写一个自定义插件
  5. 会迁移:Webpack 4 → 5,老项目升级

下一步:2024 年起,更多新项目直接用 Vite(开发时按需 ESM、生产时 Rollup 打包),启动速度比 Webpack 快 10-100 倍。但 Vite 的生产构建底层还是 Rollup,且大量 Vite 插件的接口与 Webpack 兼容。本文讲的 loader/plugin 思想 100% 适用。

参考资料

使用 Hugo 构建
主题 StackJimmy 设计