Webpack

文章目录

  • 前言
  • 一、核心概念
    • [1.1 Entry(入口)](#1.1 Entry(入口))
    • [1.2 Output(输出)](#1.2 Output(输出))
    • [1.3 完整的构建流程](#1.3 完整的构建流程)
  • 二、Loader
    • [2.1 定义](#2.1 定义)
    • [2.2 常用 Loader](#2.2 常用 Loader)
    • [2.3 Loader 执行顺序](#2.3 Loader 执行顺序)
  • 三、Plugin
    • [3.1 定义](#3.1 定义)
    • [3.2 常用 Plugin](#3.2 常用 Plugin)
    • [3.3 Loader vs Plugin](#3.3 Loader vs Plugin)
  • [四、devServer 与 HMR](#四、devServer 与 HMR)
    • [4.1 devServer](#4.1 devServer)
    • [4.2 HMR(Hot Module Replacement)](#4.2 HMR(Hot Module Replacement))
  • [五、contenthash 缓存策略](#五、contenthash 缓存策略)
    • [5.1 三种 hash 类型](#5.1 三种 hash 类型)
    • [5.2 为什么用 contenthash](#5.2 为什么用 contenthash)
    • [5.3 最佳配置](#5.3 最佳配置)
  • 六、从入口到产出:完整链路
  • 七、易混淆点
  • 八、思考与练习

前言

Webpack 是前端工程化的核心工具,理解其工作原理对构建优化、性能调优至关重要。本篇会讲清楚:

  • Entry / Output 配置
  • Loader 与 Plugin 的区别与执行顺序
  • devServer 与 HMR(热模块替换)
  • contenthash 缓存策略

一、核心概念

1.1 Entry(入口)

javascript 复制代码
// webpack.config.js
module.exports = {
  // 单入口
  entry: './src/index.js',
  
  // 多入口(多页应用)
  entry: {
    app: './src/app.js',
    admin: './src/admin.js'
  }
}

1.2 Output(输出)

javascript 复制代码
module.exports = {
  output: {
    filename: '[name].[contenthash].js',  // 输出文件名
    path: path.resolve(__dirname, 'dist'), // 输出目录
    clean: true  // 构建前清空输出目录
  }
}

1.3 完整的构建流程

复制代码
Entry → 依赖分析 → Loader 转换 → 模块图 → 生成 Chunk → Output

二、Loader

2.1 定义

Loader 是模块转换器,将非 JS 文件(CSS、图片、TypeScript 等)转换为 Webpack 可处理的模块。

2.2 常用 Loader

javascript 复制代码
module.exports = {
  module: {
    rules: [
      // CSS 处理
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']  // 从右到左执行
      },
      // TypeScript
      {
        test: /\.tsx?$/,
        use: 'ts-loader'
      },
      // 图片
      {
        test: /\.(png|svg|jpg|gif)$/,
        type: 'asset/resource'
      },
      // Babel 转译
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
}

2.3 Loader 执行顺序

从右到左,从下到上

javascript 复制代码
use: ['style-loader', 'css-loader']
// 执行顺序:css-loader → style-loader
// 1. css-loader:解析 CSS 文件,处理 @import 和 url()
// 2. style-loader:将 CSS 注入到 DOM 的 <style> 标签

三、Plugin

3.1 定义

Plugin 是构建流程的扩展,可以在构建的各个阶段执行自定义逻辑。

3.2 常用 Plugin

javascript 复制代码
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = {
  plugins: [
    // 生成 HTML 文件
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    
    // 提取 CSS 到单独文件
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css'
    }),
    
    // 打包分析
    new BundleAnalyzerPlugin()
  ]
}

3.3 Loader vs Plugin

对比项 Loader Plugin
作用 模块转换 构建流程扩展
时机 模块加载时 构建生命周期各阶段
配置 module.rules plugins
本质 函数 类(带 apply 方法)
javascript 复制代码
// Loader 本质:一个函数
module.exports = function(source) {
  return transformedSource
}

// Plugin 本质:一个带 apply 方法的 class
class MyPlugin {
  apply(compiler) {
    compiler.hooks.done.tap('MyPlugin', (stats) => {
      console.log('构建完成!')
    })
  }
}

四、devServer 与 HMR

4.1 devServer

javascript 复制代码
module.exports = {
  devServer: {
    port: 3000,
    hot: true,          // 启用 HMR
    open: true,         // 自动打开浏览器
    proxy: {            // 代理配置
      '/api': 'http://localhost:8080'
    },
    historyApiFallback: true  // SPA 路由支持
  }
}

4.2 HMR(Hot Module Replacement)

HMR 在不刷新整个页面的情况下,替换、添加或删除模块。

javascript 复制代码
// 开启 HMR 后,Webpack 会:
// 1. 建立 WebSocket 连接
// 2. 文件变化时,通过 WebSocket 通知客户端
// 3. 客户端请求更新的模块
// 4. 替换旧模块,保持应用状态

// 手动处理 HMR(如状态管理)
if (module.hot) {
  module.hot.accept('./module', () => {
    // 模块更新后的处理逻辑
  })
}

五、contenthash 缓存策略

5.1 三种 hash 类型

javascript 复制代码
// 1. hash:每次构建都变化,所有文件共用
output: { filename: '[name].[hash].js' }

// 2. chunkhash:同一 chunk 的文件相同
output: { filename: '[name].[chunkhash].js' }

// 3. contenthash:根据文件内容变化
output: { filename: '[name].[contenthash].js' }

5.2 为什么用 contenthash

javascript 复制代码
// 假设有两个文件:app.js 和 vendor.js
// 使用 chunkhash:vendor.js 内容没变,但 app.js 变了
// 结果:vendor.js 的 hash 也变了(因为它们在同一 chunk)

// 使用 contenthash:只有内容变化的文件 hash 才变
// 结果:只有 app.js 的 hash 变化,vendor.js 保持不变

// 浏览器可以利用缓存,避免重新下载未变化的文件

5.3 最佳配置

javascript 复制代码
module.exports = {
  output: {
    filename: '[name].[contenthash:8].js',  // 8 位 hash
    chunkFilename: '[name].[contenthash:8].chunk.js'
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
}

六、从入口到产出:完整链路

复制代码
1. 读取 Entry
2. 从 Entry 开始,递归分析依赖
3. 对每个模块应用对应的 Loader 转换
4. 生成模块图(Module Graph)
5. 将模块合并为 Chunk
6. 应用 Plugin(如 HtmlWebpackPlugin)
7. 输出到 dist 目录

七、易混淆点

  1. Loader vs Plugin :Loader 是模块转换器 (处理单个文件),Plugin 是构建流程扩展(干预整个构建过程)。
  2. 执行顺序:Loader 从右到左执行;Plugin 按数组顺序执行,但会根据 hooks 类型在不同阶段触发。
  3. HMR 原理:通过 WebSocket 实现,文件变化时通知客户端请求更新的模块,替换旧模块保持应用状态。
  4. contenthash:根据文件内容计算 hash,只有内容变化时 hash 才变化,利于浏览器缓存。

八、思考与练习

1. Loader 和 Plugin 的区别是什么?

解析:

  • Loader :模块转换器,处理单个文件(如 CSS → JS),配置在 module.rules
  • Plugin :构建流程扩展,干预整个构建过程(如生成 HTML),配置在 plugins

2. Loader 的执行顺序是怎样的?

解析:从右到左 ,从下到上。例如 use: ['style-loader', 'css-loader'],先执行 css-loader,再执行 style-loader

3. HMR 是如何工作的?

解析:

  1. 建立 WebSocket 连接
  2. 文件变化时,Webpack 通过 WebSocket 通知客户端
  3. 客户端请求更新的模块
  4. 替换旧模块,保持应用状态

4. 为什么推荐使用 contenthash

解析:contenthash 根据文件内容计算 hash,只有内容变化时 hash 才变化。这使得未变化的文件可以利用浏览器缓存,避免重新下载。

5. 说一下 Webpack 从入口到产出的完整流程。

解析:

  1. 读取 Entry
  2. 递归分析依赖
  3. 对每个模块应用 Loader 转换
  4. 生成模块图
  5. 合并为 Chunk
  6. 应用 Plugin
  7. 输出到 dist 目录
相关推荐
问心无愧05131 小时前
ctf show web入门111
android·前端·笔记
唐某人丶1 小时前
模型越来越强,我们还需要 Agent 工程吗?—— 从价值重估到 Harness 实践
前端·agent·ai编程
智码看视界2 小时前
现代Web开发基础:全栈工程师的起航点
前端·后端·c5全栈
JS菌2 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
excel3 小时前
HLS TS 文件损坏的元凶:Git 提交与拉取
前端
Aphasia3113 小时前
https连接传输流程
前端·面试
徐小夕3 小时前
万字长文!千万级文档 RAG 知识库系统落地实践
前端·算法·github
threelab3 小时前
Three.js 物理模拟着色器 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器