前端工程化概述
# 01.前端工程化概述
从手写 script 标签到现代化构建体系——理解前端工程化的演进脉络、核心问题与解决范式。
# 1. 案例引入:当项目从 10 个文件变成 1000 个
# 2015 年,一个"小项目"的文件数量:
js/
jquery.min.js # 第三方库
app.js # 主逻辑(800行)
utils.js # 工具函数(200行)
# 2023 年,同样业务的项目:
src/
components/BaseButton.vue
components/UserCard.vue
...(还有 80+ 个组件)
composables/useAuth.ts
stores/user.ts
...(还有 30+ 个模块)
# 问题来了:
# 1. 这些文件之间的依赖关系怎么管理?
# 2. CSS/图片/字体/TS 文件怎么"打包"到一起?
# 3. 开发时怎么做到修改代码后 0.3 秒就看到效果?
# 4. 生产环境怎么压缩到 200KB 以内?
前端工程化要解决的就是这四个核心问题。本文提供全景概览,后续各篇深入展开。
# 2. 前端工程化的四个核心维度
┌──────────────────────┐
│ 前端工程化 │
└──────────┬───────────┘
┌─────────┬───────┼───────┬─────────┐
▼ ▼ ▼ ▼ ▼
┌─────────┐ ┌──────┐ ┌───────┐ ┌──────┐ ┌──────┐
│ 模块化 │ │构建 │ │ 规范 │ │ 测试 │ │ 部署 │
│ CJS/ESM │ │打包 │ │Lint │ │Jest │ │CI/CD │
│ TS集成 │ │编译 │ │Format │ │E2E │ │容器化│
│ 依赖 │ │优化 │ │GitHook│ │ │ │监控 │
└─────────┘ └──────┘ └───────┘ └──────┘ └──────┘
# 3. 模块化:从全局变量到 ESM
# 3.1 蛮荒时期:全局变量与命名空间
// 2005 年——所有脚本挂 window
// <script src="jquery.js"></script>
// <script src="app.js"></script>
// <script src="utils.js"></script>
window.$ = jQuery; // 全局污染
window.MY_APP = {}; // 手动"命名空间"
window.MY_APP.utils = {}; // 嵌套命名空间——但本质还是全局变量
问题:依赖顺序必须手动管理,变量名冲突,无法 Tree Shaking。
# 3.2 CommonJS:Node.js 的模块化
// a.js
module.exports = { foo: 1 };
// b.js
const a = require('./a');
console.log(a.foo); // 1
特点:同步加载(适合 Node),动态 require,运行时解析;不能在浏览器中直接使用。
# 3.3 AMD:浏览器端的异步模块
// RequireJS 时代
define(['jquery', 'utils'], function($, utils) {
return { init: function() {} };
});
特点:异步加载,但语法冗长,依赖前置声明。
# 3.4 ES Module:标准答案
// 静态导入——编译时确定依赖关系
import { ref, computed } from 'vue';
import type { User } from './types';
// 动态导入——运行时按需加载
const module = await import('./heavy-component.vue');
// 静态结构 → Tree Shaking 成为可能
// 编译时分析 → 构建工具可以精确定位依赖
# 3.5 各方案对比
| 方案 | 加载方式 | TreeShaking | 浏览器 | Node | 现状 |
|---|---|---|---|---|---|
| 全局变量 | 手动 | ❌ | ✅ | ✅ | 被淘汰 |
| CommonJS | 同步 require | ❌ | ❌ | ✅ | Node 传统 |
| AMD | 异步 define | ❌ | ✅ | ❌ | 被淘汰 |
| ES Module | 静态 import | ✅ | ✅ | ✅ | 标准 |
# 4. 构建工具:为什么需要"打包"?
# 4.1 一段没有构建工具的"现代"代码
<!-- 浏览器无法直接识别这些文件 -->
<script type="module">
import { ref } from 'vue'; // ❌ 找不到模块
import style from './app.css'; // ❌ 浏览器不支持 CSS import
import logo from './logo.png'; // ❌ 浏览器不支持图片 import
import { fetchUser } from '@/api/user'; // ❌ 路径别名浏览器不理解
</script>
# 4.2 构建工具做什么
源码(开发者写的)→ 构建工具 → 产物(浏览器能运行的)
转换内容:
.vue/.tsx → .js 语法转换
.scss → .css 样式编译
@/api/user → ./src/api/user 路径解析
import() → 代码分割 按需加载
console.log → (移除) 压缩优化
图片 > 8KB → base64 / URL 资源处理
构建结果(dist/):
index.html 入口 HTML
assets/index-[hash].js 主 JS bundle
assets/vendor-[hash].js 第三方库 bundle
assets/index-[hash].css 样式文件
assets/logo.[hash].png 图片资源
# 4.3 三大构建工具演进
2012 Grunt ─→ 任务运行器(手动配置每个转换步骤)
2014 Gulp ─→ 流式构建(比 Grunt 快)
2014 Webpack ─→ bundler 时代(一切皆模块,loader/plugin 生态)
2020 Vite ─→ ESM 原生支持(开发环境 0 打包,毫秒级启动)
Webpack 的核心贡献:提出 "一切皆模块" 的理念,通过 Loader 处理非 JS 文件,Plugin 扩展构建流程。
Vite 的核心创新:开发环境不打包,利用浏览器原生 ESM;生产环境用 Rollup 打包。
# 5. 包管理器:npm / yarn / pnpm
# 5.1 npm 的依赖地狱
项目 A 依赖 lodash@4.17.0
项目 A 同时依赖 dep-b,而 dep-b 依赖 lodash@3.10.0
npm v2:
node_modules/
A/
node_modules/lodash@4.17.0 ← 嵌套,目录超深
dep-b/
node_modules/lodash@3.10.0 ← 嵌套,重复安装
npm v3+:
node_modules/
lodash@4.17.0 ← 扁平化(提升到顶层)
dep-b/
node_modules/lodash@3.10.0 ← 版本冲突时保留嵌套
# 5.2 锁文件:确保团队环境一致
package.json → "lodash": "^4.17.0" 语义化范围
package-lock.json → "lodash": "4.17.21" 精确版本(提交到 Git)
# 为什么需要锁文件?
# A 电脑安装时为 4.17.21
# 一周后 ^4.17.0 可能已经更新到 4.17.25
# B 电脑安装时会安装 4.17.25——团队不一致!
# 锁文件确保:所有人安装相同的依赖树
# 5.3 pnpm:更快更省空间
npm/yarn:每个项目独立安装 node_modules(100 个项目 → 100 份依赖副本)
pnpm: 全局存储 + 硬链接(100 个项目 → 1 份存储 + 硬链接)
优势:
1. 磁盘节省 50%+
2. node_modules 非扁平化(更严格——防止幽灵依赖)
3. 安装速度更快
# 5.4 依赖类型速查
{
"dependencies": {
"vue": "^3.4.0" // 生产需要
},
"devDependencies": {
"vite": "^5.0.0", // 仅开发需要
"typescript": "^5.3.0",
"eslint": "^8.0.0"
},
"peerDependencies": {
"vue": "^3.0.0" // 宿主项目需要安装(插件库常用)
}
}
# 6. 工程化工具链全景
开发阶段 构建阶段 部署阶段
┌──────────┐ ┌──────────┐ ┌──────────┐
│ ESLint │ │ Webpack │ │ Docker │
│ Prettier │───→│ / Vite │───→│ / Nginx │
│ TS Check │ │ 编译打包 │ │ CDN/OSS │
└──────────┘ └──────────┘ └──────────┘
│ │ │
│ └─ 代码分割 └─ 静态资源
│ TreeShaking Gzip 压缩
│ CSS 提取 缓存策略
│ JS 压缩
│ SourceMap
│
└─ Git Hooks (Husky)
提交前 Lint (lint-staged)
Commit Message (Commitlint)
# 7. 速查表
| 维度 | 工具 | 一句话 |
|---|---|---|
| 模块化 | ESM (import/export) | 标准答案,浏览器+Node 通用 |
| 构建 | Vite (新) / Webpack | Vite 开发快,Webpack 生态全 |
| 包管理 | pnpm | 最快最省空间,严格依赖 |
| 代码规范 | ESLint + Prettier | 查错 + 格式化 |
| Git | Husky + lint-staged | 提交前自动检查 |
| CI/CD | GitHub Actions / Jenkins | 自动化测试和部署 |
工程化的本质:不是某个工具,而是一套从源码到生产环境的可控、可复现、可优化的流程体系。
下一篇:02.Webpack构建实战
上次更新: 2026/06/24, 14:17:21