编程进阶网 编程进阶网
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

  • iOS开发和进阶

  • Web开发和进阶

    • README
    • HTML工具手册

    • CSS样式与布局

    • JavaScript核心

    • TypeScript入门

    • Vue高级进阶

    • Web工程化实践

      • 前端工程化概述
      • Webpack构建实战
        • 1. 案例引入:一个 Vue 项目为什么需要 Webpack?
        • 2. Webpack 核心概念
          • 2.1 依赖图——一切从这里开始
          • 2.2 四大核心配置
        • 3. Loader 深入
          • 3.1 链式调用原理
          • 3.2 常用 Loader 速查
          • 3.3 核心实战配置
        • 4. Plugin 深入
          • 4.1 常用 Plugin 速查
          • 4.2 核心配置实战
        • 5. 代码分割(Code Splitting)
          • 5.1 三种分割方式
        • 6. HMR 热更新原理
          • 6.1 工作原理
          • 6.2 配置
        • 7. Tree Shaking 与打包优化
          • 7.1 Tree Shaking 原理
          • 7.2 完整优化配置
        • 8. 缓存策略:让二次构建飞起来
        • 9. 速查表
      • Vite构建实战
      • 代码规范与质量
      • 前端性能优化
  • Linux应用开发

  • IoT智能硬件开发

  • Apps
  • Web开发和进阶
  • Web工程化实践
杨充
2026-06-23
目录

Webpack构建实战

# 02.Webpack构建实战

掌握 Webpack 的核心心智模型——从"依赖图"到"产物",理解 Loader 和 Plugin 的设计思想与 HMR 原理。

# 1. 案例引入:一个 Vue 项目为什么需要 Webpack?

src/
  main.ts              # 入口
  App.vue              # Vue 组件
  components/
    BaseButton.vue
    UserCard.vue
  styles/
    global.scss         # SCSS 预处理器
  assets/
    logo.svg            # SVG 图标
    bg.png              # 大图

# 浏览器能运行这些吗?
# main.ts           → 需要编译 TS
# *.vue             → 需要编译 SFC(单文件组件)
# global.scss       → 需要编译 SCSS → CSS
# logo.svg / bg.png → 需要转为 URL 或 base64
# import { ref }    → 需要解析 vue 模块路径

Webpack 的职责:将 100+ 个异构文件,构建为浏览器能完美运行的 3~5 个静态文件。


# 2. Webpack 核心概念

# 2.1 依赖图——一切从这里开始

Webpack 从 Entry 开始,递归构建模块依赖关系:

    main.ts ─┬── App.vue ─┬── BaseButton.vue
             │            ├── UserCard.vue
             │            └── global.scss → _variables.scss
             ├── vue (node_modules)
             ├── vue-router (node_modules)
             └── utils/format.ts → dayjs (node_modules)

这张"依赖图"告诉 Webpack:
  - 哪些模块需要被打包(所有被引用的模块)
  - 模块顺序是什么(入口→第一层→第二层→...)
  - 哪些可以拆分成单独文件(代码分割)

# 2.2 四大核心配置

// webpack.config.js
module.exports = {
    // 1. Entry:告诉 Webpack 从哪里开始构建
    entry: './src/main.ts',

    // 2. Output:产物输出到哪里
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'js/[name].[contenthash:8].js',  // 文件名 + 哈希
        clean: true                                 // 清除上次构建
    },

    // 3. Loader:处理非 JS 文件(TS/Vue/SCSS/图片)
    module: {
        rules: [
            { test: /\.ts$/,  use: 'ts-loader' },           // TS → JS
            { test: /\.vue$/, use: 'vue-loader' },          // Vue SFC
            { test: /\.scss$/, use: ['style-loader','css-loader','sass-loader'] },
            { test: /\.(png|svg)$/, type: 'asset' },        // 图片资源
        ]
    },

    // 4. Plugin:扩展 Webpack 构建能力(压缩/提取CSS/生成HTML/热更新)
    plugins: [
        new HtmlWebpackPlugin({ template: './index.html' }),
        new MiniCssExtractPlugin({ filename: 'css/[name].[hash].css' })
    ]
};

一张图看懂 Loader vs Plugin:

Loader:转换器(一对一或链式)
  输入 A 类型文件 → Loader 转换 → 输出 B 类型文件
  例:scss → sass-loader → css-loader → style-loader → DOM <style>

Plugin:增强器(全局)
  在构建各阶段注入逻辑——开始、结束、编译中、输出前……
  例:压缩 JS、生成 HTML、提取 CSS、复制静态资源

# 3. Loader 深入

# 3.1 链式调用原理

.scss 文件处理流程:

1. sass-loader     → 将 SCSS 编译为 CSS 字符串
2. css-loader      → 解析 CSS 中的 @import / url(),返回 CSS 模块
3. style-loader    → 将 CSS 注入 DOM(<style> 标签)
   或 MiniCssExtractPlugin.loader → 提取为独立 .css 文件

链式规则:从后往前执行(右→左,或下→上)
use: ['style-loader', 'css-loader', 'sass-loader']
     ↑ 最后执行       ↑             ↑ 先执行

# 3.2 常用 Loader 速查

Loader 作用 配置示例
ts-loader TS→JS(使用 tsc 编译) use: 'ts-loader'
babel-loader JS 语法降级(不检查类型) use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } }
vue-loader Vue SFC 编译 配合 VueLoaderPlugin
css-loader 解析 CSS import/url options: { modules: true } 开启 CSS Modules
sass-loader SCSS/SASS → CSS 需要 dart-sass 或 node-sass
postcss-loader Autoprefixer/Tailwind 等 postcss.config.js
asset(内置) 图片/字体复制或内联 type: 'asset', parser: { dataUrlCondition: { maxSize: 8*1024 } }

# 3.3 核心实战配置

// 完整的 module.rules 配置
module: {
    rules: [
        // TypeScript
        {
            test: /\.tsx?$/,
            exclude: /node_modules/,
            use: {
                loader: 'ts-loader',
                options: {
                    transpileOnly: true,      // 仅转译不检查(快),配合 fork-ts-checker-plugin
                    appendTsSuffixTo: [/\.vue$/]
                }
            }
        },
        // Vue SFC
        {
            test: /\.vue$/,
            use: 'vue-loader'
        },
        // SCSS
        {
            test: /\.scss$/,
            use: [
                isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
                'css-loader',
                {
                    loader: 'sass-loader',
                    options: {
                        additionalData: `@import "@/styles/variables.scss";`
                    }
                }
            ]
        },
        // 图片处理
        {
            test: /\.(png|jpe?g|gif|svg|webp)$/i,
            type: 'asset',          // Webpack 5 内置 Asset Module
            parser: {
                dataUrlCondition: {
                    maxSize: 8 * 1024   // < 8KB → base64 内联
                }
            }
        }
    ]
}

# 4. Plugin 深入

# 4.1 常用 Plugin 速查

Plugin 作用
HtmlWebpackPlugin 生成 HTML,自动注入打包后的 JS/CSS
MiniCssExtractPlugin 提取 CSS 为独立文件
DefinePlugin 注入编译时常量(如 process.env.NODE_ENV)
CopyWebpackPlugin 复制静态资源到 dist
ForkTsCheckerWebpackPlugin 独立进程做 TS 类型检查(不阻塞构建)
TerserPlugin JS 压缩(Webpack 5 内置)
CssMinimizerPlugin CSS 压缩

# 4.2 核心配置实战

plugins: [
    // 生成 HTML
    new HtmlWebpackPlugin({
        template: 'public/index.html',
        favicon: 'public/favicon.ico',
        inject: true                       // 自动注入 script/css
    }),

    // CSS 提取
    new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:8].css',
        chunkFilename: 'css/[id].[contenthash:8].css'
    }),

    // 编译时环境变量
    new webpack.DefinePlugin({
        __VUE_OPTIONS_API__: JSON.stringify(true),
        __VUE_PROD_DEVTOOLS__: JSON.stringify(false)
    })
]

# 5. 代码分割(Code Splitting)

# 5.1 三种分割方式

optimization: {
    splitChunks: {
        chunks: 'all',          // 所有类型的 chunk 都优化
        cacheGroups: {
            // 方式 1:Vue 全家桶独立 chunk
            vueVendor: {
                test: /[\\/]node_modules[\\/](vue|vue-router|pinia)[\\/]/,
                name: 'vue-vendor',
                priority: 10
            },
            // 方式 2:其他第三方库
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name: 'vendor',
                priority: 5
            },
            // 方式 3:公共模块(被 3+ chunks 引用的模块提取)
            common: {
                minChunks: 3,
                name: 'common',
                priority: 1,
                reuseExistingChunk: true
            }
        }
    }
}

代码分割的效果:

原来:app.js (800KB)     ← 修改一行代码,用户重新加载 800KB

分割后:
  vendor.js     (300KB)  ← 第三方库变化少,强缓存
  vue-vendor.js (150KB)  ← Vue 版本稳定,强缓存
  common.js     (100KB)  ← 公共模块
  app.js        (250KB)  ← 业务逻辑经常变
  # 修改业务代码,用户只需重新加载 250KB

# 6. HMR 热更新原理

# 6.1 工作原理

HMR 完整流程:

1. Webpack Dev Server 启动 WebSocket 服务
2. 浏览器加载页面时,自动注入 HMR Runtime(小型 WebSocket 客户端)
3. 开发者修改代码 → Webpack 重新编译 → 计算变化文件的最小依赖图
4. WebSocket 推送变化给浏览器:
   { type: "hash", hash: "abc123" }          ← 新构建的 hash
   { type: "ok" }                             ← 构建完成
   { type: "update", modules: {...} }        ← 变化的模块
5. HMR Runtime 替换变化模块(不刷新页面)
   ├── CSS 变化 → 只替换 <style> 内容(状态保留)
   ├── JS 变化 → 替换模块 + 重新执行(Vue 组件保留状态)
   └── 无法 HM 的模块 → 降级为整页刷新

# 6.2 配置

devServer: {
    port: 3000,
    hot: true,              // 开启 HMR
    open: true,             // 自动打开浏览器
    historyApiFallback: true, // SPA History 模式兜底
    proxy: {                // API 代理
        '/api': 'http://localhost:8080'
    }
}

# 7. Tree Shaking 与打包优化

# 7.1 Tree Shaking 原理

// math.js
export const add = (a, b) => a + b;
export const sub = (a, b) => a - b;   // 未使用

// app.js
import { add } from './math';          // 只引入 add

// 构建结果:
// sub 函数不会出现在最终产物中 ← Tree Shaking 的效果

// 前提条件:
// 1. 使用 ES Module(静态导入)而非 CommonJS
// 2. 生产模式(mode: 'production')
// 3. package.json 的 sideEffects: false

# 7.2 完整优化配置

optimization: {
    minimize: true,
    minimizer: [
        new TerserPlugin({
            terserOptions: {
                compress: {
                    drop_console: true,     // 删除 console
                    drop_debugger: true     // 删除 debugger
                }
            }
        }),
        new CssMinimizerPlugin()             // CSS 压缩
    ],
    splitChunks: { /* 如上述 5.1 配置 */ },
    runtimeChunk: 'single'                   // Runtime 代码单独提取
}

# 8. 缓存策略:让二次构建飞起来

module.exports = {
    cache: {
        type: 'filesystem',    // 将缓存写入磁盘(node_modules/.cache/webpack)
        // 下次构建直接从缓存读取——大型项目构建时间减少 50%+
    },
    output: {
        filename: 'js/[name].[contenthash:8].js',  // 文件内容 hash
    }
};

// 缓存分层策略:
// 1. vendor + vue-vendor:很少变化 → 文件名带 contenthash → 用户强缓存
// 2. common chunk:较少变化 → 中等缓存时间
// 3. app chunk:每次可能不同 → 短缓存

# 9. 速查表

概念 职责 示例
Entry 入口起点 entry: './src/main.ts'
Output 输出配置 filename: '[name].[hash].js'
Loader 文件转换 ts-loader/vue-loader/css-loader
Plugin 构建增强 HtmlWebpackPlugin/MiniCssExtractPlugin
splitChunks 代码分割 vue-vendor/vendor/common
HMR 热更新 局部替换模块,保留状态
TreeShaking 摇树优化 移除未使用代码
filesystem cache 磁盘缓存 二次构建快 50%+

Webpack 一句话:从入口出发,递归解析依赖图,通过 Loader 链处理异构模块,通过 Plugin 注入构建流程,最终输出为浏览器可用的静态资源。


下一篇:03.Vite构建实战

上次更新: 2026/06/24, 14:17:21
前端工程化概述
Vite构建实战

← 前端工程化概述 Vite构建实战→

最近更新
01
CSS选择器入门
06-23
02
CSS定位与层级
06-23
03
CSS盒模型详解
06-23
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 鄂ICP备2024073355号-1 | 鄂ICP备2024073355号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式