Skip to content

Webpack 面试题汇总(2026 版)

涵盖 Webpack 5 核心概念、构建原理、性能优化、Loader/Plugin 开发

概述

Webpack 是现代前端工程化的核心工具,本文汇总了 2026 年 Webpack 面试中的高频问题,包括:

  • 基础概念:Entry、Output、Loader、Plugin、Mode
  • 核心原理:构建流程、模块解析、依赖图、打包机制
  • 性能优化:Tree Shaking、Code Splitting、缓存策略、构建速度优化
  • 工程实践:多页应用配置、环境区分、Source Map、HMR
  • 高级特性:Module Federation、Persistent Cache、Asset Modules

一、基础概念

1. 什么是 Webpack?它解决了什么问题?

答案

Webpack 是一个模块打包工具,它将项目中的各种资源(JS、CSS、图片等)视为模块,通过分析模块间的依赖关系,最终打包成浏览器可识别的静态资源。

解决的问题

  1. 模块化:支持 ES Module、CommonJS、AMD 等多种模块规范
  2. 资源管理:统一处理 JS、CSS、图片、字体等各类资源
  3. 代码转换:通过 Loader 转换 TypeScript、Sass、Less 等
  4. 性能优化:代码分割、Tree Shaking、压缩混淆
  5. 开发体验:HMR 热更新、Source Map 调试

示例

javascript
// webpack.config.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}

2. Webpack 的核心概念有哪些?

答案

五大核心概念

  1. Entry(入口)
    • 指示 Webpack 从哪个文件开始构建依赖图
    • 支持单入口和多入口
javascript
// 单入口
entry: './src/index.js'

// 多入口
entry: {
  app: './src/app.js',
  admin: './src/admin.js'
}
  1. Output(输出)
    • 指定打包后的文件输出位置和命名规则
javascript
output: {
  filename: '[name].[contenthash].js',
  path: path.resolve(__dirname, 'dist'),
  clean: true // Webpack 5 自动清理
}
  1. Loader(加载器)
    • 转换非 JavaScript 文件(CSS、图片、TypeScript 等)
    • 从右到左、从下到上执行
javascript
module: {
  rules: [
    {
      test: /\.tsx?$/,
      use: 'ts-loader',
      exclude: /node_modules/
    }
  ]
}
  1. Plugin(插件)
    • 执行更广泛的任务(打包优化、资源管理、环境变量注入等)
javascript
plugins: [
  new HtmlWebpackPlugin({
    template: './src/index.html'
  }),
  new MiniCssExtractPlugin({
    filename: '[name].[contenthash].css'
  })
]
  1. Mode(模式)
    • development:开发模式,启用 SourceMap、HMR
    • production:生产模式,启用压缩、Tree Shaking
    • none:不使用任何默认优化
javascript
mode: 'production'

3. Loader 和 Plugin 有什么区别?

答案

特性LoaderPlugin
作用转换文件内容执行更广泛的任务
执行时机模块加载时整个构建生命周期
配置位置module.rulesplugins 数组
输入输出接收源文件,返回转换后内容通过钩子访问 compilation 对象
示例babel-loader、css-loaderHtmlWebpackPlugin、MiniCssExtractPlugin

Loader 示例

javascript
// 处理 CSS 文件
{
  test: /\.css$/,
  use: [
    'style-loader',  // 将 CSS 注入 DOM
    'css-loader',    // 解析 CSS 文件
    'postcss-loader' // 添加浏览器前缀
  ]
}

Plugin 示例

javascript
// 生成 HTML 文件
new HtmlWebpackPlugin({
  template: './src/index.html',
  filename: 'index.html',
  chunks: ['app']
})

核心区别

  • Loader 是文件转换器,专注于单个文件的处理
  • Plugin 是功能扩展器,可以介入整个构建流程

4. 常用的 Loader 有哪些?

答案

样式处理

javascript
// CSS
{
  test: /\.css$/,
  use: ['style-loader', 'css-loader']
}

// Sass/SCSS
{
  test: /\.s[ac]ss$/,
  use: ['style-loader', 'css-loader', 'sass-loader']
}

// Less
{
  test: /\.less$/,
  use: ['style-loader', 'css-loader', 'less-loader']
}

// PostCSS(自动添加前缀)
{
  test: /\.css$/,
  use: ['style-loader', 'css-loader', 'postcss-loader']
}

JavaScript 转换

javascript
// Babel(ES6+ → ES5)
{
  test: /\.js$/,
  use: 'babel-loader',
  exclude: /node_modules/
}

// TypeScript
{
  test: /\.tsx?$/,
  use: 'ts-loader'
}

资源处理

javascript
// 图片(Webpack 5 内置)
{
  test: /\.(png|jpg|gif|svg)$/,
  type: 'asset/resource'
}

// 字体
{
  test: /\.(woff|woff2|eot|ttf|otf)$/,
  type: 'asset/resource'
}

// 小图片转 base64
{
  test: /\.(png|jpg|gif)$/,
  type: 'asset',
  parser: {
    dataUrlCondition: {
      maxSize: 8 * 1024 // 8kb
    }
  }
}

5. 常用的 Plugin 有哪些?

答案

HTML 处理

javascript
// 生成 HTML 文件
new HtmlWebpackPlugin({
  template: './src/index.html',
  filename: 'index.html',
  minify: {
    collapseWhitespace: true,
    removeComments: true
  }
})

CSS 处理

javascript
// 提取 CSS 到单独文件
new MiniCssExtractPlugin({
  filename: '[name].[contenthash].css'
})

// 压缩 CSS
new CssMinimizerPlugin()

代码优化

javascript
// 压缩 JavaScript
new TerserPlugin({
  parallel: true,
  terserOptions: {
    compress: {
      drop_console: true,
      drop_debugger: true
    }
  }
})

// 分析打包体积
new BundleAnalyzerPlugin()

环境变量

javascript
// 定义全局常量
new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify('production'),
  'API_URL': JSON.stringify('https://api.example.com')
})

其他

javascript
// 清理输出目录
new CleanWebpackPlugin()

// 复制静态资源
new CopyWebpackPlugin({
  patterns: [
    { from: 'public', to: 'assets' }
  ]
})

// 进度条
new ProgressPlugin()

二、构建流程

6. Webpack 的构建流程是什么?

答案

Webpack 的构建流程分为三个阶段

1. 初始化阶段

1. 读取配置文件(webpack.config.js)
2. 合并配置参数(命令行 + 配置文件)
3. 创建 Compiler 对象
4. 加载所有配置的插件
5. 执行 Compiler.run() 开始编译

2. 编译阶段

1. 从 Entry 入口文件开始
2. 调用对应的 Loader 转换模块内容
3. 解析模块依赖(import、require)
4. 递归处理所有依赖模块
5. 生成 Chunk(代码块)
6. 构建完整的依赖图(Dependency Graph)

3. 输出阶段

1. 根据依赖图生成最终代码
2. 根据 Output 配置输出文件
3. 写入文件系统

详细流程图

初始化

读取配置 → 创建 Compiler → 注册插件

编译

确定入口 → 编译模块 → 完成模块编译
  ↓                ↑
  └─ 递归依赖 ─────┘

输出

生成 Chunk → 输出资源 → 写入文件

核心对象

  • Compiler:全局唯一,负责整个编译流程
  • Compilation:每次编译创建,包含当前模块资源、编译生成资源等
  • Module:代表一个模块
  • Chunk:代码块,由多个 Module 组成

7. Webpack 的热更新(HMR)原理是什么?

答案

HMR(Hot Module Replacement) 允许在运行时更新模块,无需刷新整个页面。

工作流程

1. Webpack Compiler 监听文件变化
2. 文件变化后,重新编译生成新的模块
3. Webpack Dev Server 通过 WebSocket 推送更新消息
4. 客户端接收到更新消息
5. 客户端通过 JSONP 请求新模块代码
6. HMR Runtime 替换旧模块
7. 触发 module.hot.accept() 回调

配置示例

javascript
// webpack.config.js
module.exports = {
  devServer: {
    hot: true, // 启用 HMR
    port: 3000
  }
}

使用示例

javascript
// index.js
import { render } from './app.js'

render()

// 启用 HMR
if (module.hot) {
  module.hot.accept('./app.js', () => {
    console.log('app.js 更新了')
    render()
  })
}

通信机制

Webpack Dev Server (Node.js)
         ↓ WebSocket
    浏览器客户端
         ↓ JSONP
    获取更新的模块

    HMR Runtime 替换模块

优势

  • 保留应用状态
  • 只更新变化的模块
  • 提升开发效率

8. 什么是 Source Map?如何配置?

答案

Source Map 是源代码与打包后代码的映射文件,用于调试时定位源代码位置。

配置选项

javascript
module.exports = {
  devtool: 'source-map' // 多种选项
}

常用选项对比

devtool构建速度重构速度生产环境质量
eval++++++生成代码
eval-source-map--+原始源代码
cheap-source-map+++转换后代码(仅行)
cheap-module-source-map+++原始源代码(仅行)
source-map----原始源代码
hidden-source-map----原始源代码(不暴露)
nosources-source-map----无源代码内容

推荐配置

javascript
// 开发环境
devtool: 'eval-cheap-module-source-map'

// 生产环境
devtool: 'hidden-source-map' // 或 false

原理

javascript
// 打包后的代码末尾
//# sourceMappingURL=bundle.js.map
json
// bundle.js.map
{
  "version": 3,
  "sources": ["webpack:///src/index.js"],
  "mappings": "AAAA;AACA;AACA",
  "file": "bundle.js"
}

三、性能优化

9. 如何优化 Webpack 构建速度?

答案

1. 缩小构建范围

javascript
module.exports = {
  // 指定查找模块的目录
  resolve: {
    modules: [path.resolve(__dirname, 'node_modules')],
    extensions: ['.js', '.json'], // 减少尝试的扩展名
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  
  // 排除不需要处理的文件
  module: {
    rules: [
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/,
        include: path.resolve(__dirname, 'src')
      }
    ]
  }
}

2. 使用缓存

javascript
module.exports = {
  // Webpack 5 持久化缓存
  cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.temp_cache')
  },
  
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true // Babel 缓存
          }
        }
      }
    ]
  }
}

3. 多进程构建

javascript
// thread-loader
{
  test: /\.js$/,
  use: [
    'thread-loader',
    'babel-loader'
  ]
}

// TerserPlugin 多进程压缩
optimization: {
  minimizer: [
    new TerserPlugin({
      parallel: true
    })
  ]
}

4. 优化 Loader

javascript
// 使用更快的 Loader
{
  test: /\.js$/,
  use: 'esbuild-loader' // 比 babel-loader 快 10 倍
}

5. DLL 预编译(已过时,Webpack 5 用 cache 代替)

6. 减少 Plugin 使用

javascript
// 只在生产环境使用某些插件
plugins: [
  ...(isProd ? [new BundleAnalyzerPlugin()] : [])
]

效果对比

优化前:构建耗时 60s
优化后:构建耗时 15s(提升 75%)

10. 如何优化 Webpack 打包体积?

答案

1. Tree Shaking(摇树优化)

javascript
// package.json
{
  "sideEffects": false // 标记所有文件无副作用
}

// 或指定有副作用的文件
{
  "sideEffects": ["*.css", "*.scss"]
}

// webpack.config.js
optimization: {
  usedExports: true,  // 标记未使用的导出
  minimize: true,      // 删除未使用的代码
  sideEffects: true    // 读取 package.json 的 sideEffects
}

2. Code Splitting(代码分割)

javascript
optimization: {
  splitChunks: {
    chunks: 'all',
    cacheGroups: {
      // 提取第三方库
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        priority: 10
      },
      // 提取公共代码
      common: {
        minChunks: 2,
        priority: 5,
        reuseExistingChunk: true
      }
    }
  }
}

3. 动态导入(懒加载)

javascript
// 路由懒加载
const Home = () => import('./views/Home.vue')

// 条件加载
button.addEventListener('click', async () => {
  const module = await import('./heavy-module.js')
  module.init()
})

4. 压缩代码

javascript
optimization: {
  minimizer: [
    // 压缩 JS
    new TerserPlugin({
      terserOptions: {
        compress: {
          drop_console: true,
          drop_debugger: true
        }
      }
    }),
    // 压缩 CSS
    new CssMinimizerPlugin()
  ]
}

5. 外部化依赖(CDN)

javascript
externals: {
  vue: 'Vue',
  'vue-router': 'VueRouter',
  axios: 'axios'
}
html
<!-- index.html -->
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>

6. 图片优化

javascript
// 压缩图片
{
  test: /\.(png|jpg|gif)$/,
  use: [
    {
      loader: 'image-webpack-loader',
      options: {
        mozjpeg: { quality: 80 },
        pngquant: { quality: [0.65, 0.90] }
      }
    }
  ]
}

7. 分析打包体积

javascript
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

plugins: [
  new BundleAnalyzerPlugin()
]

效果对比

优化前:bundle.js 2.5MB
优化后:
  - vendors.js 800KB
  - app.js 300KB
  - home.js 150KB(懒加载)
  总计:1.25MB(减少 50%)

11. 什么是 Tree Shaking?如何配置?

答案

Tree Shaking 是一种通过静态分析删除未使用代码(dead code)的优化技术。

原理

  1. 基于 ES6 Module 的静态结构(import/export
  2. 分析哪些导出被使用
  3. 删除未使用的导出

配置

javascript
// webpack.config.js
module.exports = {
  mode: 'production', // 自动启用 Tree Shaking
  optimization: {
    usedExports: true,  // 标记未使用的导出
    minimize: true,      // 删除未使用的代码
    sideEffects: true    // 读取 package.json 的 sideEffects
  }
}
json
// package.json
{
  "sideEffects": false
}

// 或指定有副作用的文件
{
  "sideEffects": [
    "*.css",
    "*.scss",
    "./src/polyfills.js"
  ]
}

示例

javascript
// utils.js
export function add(a, b) {
  return a + b
}

export function subtract(a, b) {
  return a - b
}

// index.js
import { add } from './utils.js'

console.log(add(1, 2))

// 打包后,subtract 函数会被删除

注意事项

  1. 必须使用 ES6 Module(CommonJS 不支持)
javascript
// ✅ 支持 Tree Shaking
import { add } from './utils'

// ❌ 不支持 Tree Shaking
const { add } = require('./utils')
  1. 避免副作用
javascript
// ❌ 有副作用,不会被删除
export function setup() {
  window.myGlobal = 'value'
}

// ✅ 无副作用,可以被删除
export function add(a, b) {
  return a + b
}
  1. Babel 配置
json
// .babelrc
{
  "presets": [
    ["@babel/preset-env", {
      "modules": false // 保留 ES6 Module
    }]
  ]
}

12. 什么是 Code Splitting?有哪些实现方式?

答案

Code Splitting 是将代码分割成多个 bundle,实现按需加载,减少初始加载时间。

三种实现方式

1. 多入口分割

javascript
entry: {
  app: './src/app.js',
  admin: './src/admin.js'
},
output: {
  filename: '[name].bundle.js'
}

2. SplitChunksPlugin(推荐)

javascript
optimization: {
  splitChunks: {
    chunks: 'all', // 'initial' | 'async' | 'all'
    minSize: 20000, // 最小 20KB
    maxSize: 244000, // 最大 244KB
    minChunks: 1, // 最少被引用次数
    maxAsyncRequests: 30,
    maxInitialRequests: 30,
    
    cacheGroups: {
      // 第三方库
      defaultVendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10,
        reuseExistingChunk: true,
        name: 'vendors'
      },
      // 公共代码
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true,
        name: 'common'
      },
      // React 相关
      react: {
        test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
        name: 'react',
        priority: 10
      },
      // UI 库
      ui: {
        test: /[\\/]node_modules[\\/](antd|@ant-design)[\\/]/,
        name: 'ui',
        priority: 10
      }
    }
  }
}

3. 动态导入(Dynamic Import)

javascript
// 路由懒加载
const routes = [
  {
    path: '/home',
    component: () => import(/* webpackChunkName: "home" */ './views/Home.vue')
  },
  {
    path: '/about',
    component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
  }
]

// 条件加载
button.addEventListener('click', async () => {
  const { default: Chart } = await import(
    /* webpackChunkName: "chart" */
    /* webpackPrefetch: true */
    './Chart.js'
  )
  new Chart()
})

魔法注释

javascript
import(
  /* webpackChunkName: "my-chunk" */  // 指定 chunk 名称
  /* webpackPrefetch: true */          // 预加载
  /* webpackPreload: true */           // 预加载(优先级更高)
  './module.js'
)

效果

优化前:
  bundle.js: 2MB

优化后:
  vendors.js: 800KB
  react.js: 300KB
  ui.js: 400KB
  app.js: 200KB
  home.js: 150KB (懒加载)
  about.js: 150KB (懒加载)

四、高级特性

13. Webpack 5 有哪些新特性?

答案

1. 持久化缓存(Persistent Cache)

javascript
cache: {
  type: 'filesystem',
  cacheDirectory: path.resolve(__dirname, '.temp_cache'),
  buildDependencies: {
    config: [__filename]
  }
}

效果:二次构建速度提升 90%+

2. Module Federation(模块联邦)

javascript
// 应用 A(Remote)
new ModuleFederationPlugin({
  name: 'app_a',
  filename: 'remoteEntry.js',
  exposes: {
    './Button': './src/components/Button',
    './Header': './src/components/Header'
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true }
  }
})

// 应用 B(Host)
new ModuleFederationPlugin({
  name: 'app_b',
  remotes: {
    app_a: 'app_a@http://localhost:3001/remoteEntry.js'
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true }
  }
})

3. Asset Modules(资源模块)

javascript
// 替代 file-loader、url-loader、raw-loader
{
  test: /\.png$/,
  type: 'asset/resource' // 输出文件
}

{
  test: /\.svg$/,
  type: 'asset/inline' // 转 base64
}

{
  test: /\.txt$/,
  type: 'asset/source' // 导出源代码
}

{
  test: /\.jpg$/,
  type: 'asset', // 自动选择
  parser: {
    dataUrlCondition: {
      maxSize: 8 * 1024
    }
  }
}

4. 更好的 Tree Shaking

  • 支持嵌套的 Tree Shaking
  • 支持 CommonJS 的 Tree Shaking
  • 更智能的副作用分析

5. 移除 Node.js Polyfills

javascript
// Webpack 4 自动注入
// Webpack 5 需要手动配置
resolve: {
  fallback: {
    "path": require.resolve("path-browserify"),
    "crypto": require.resolve("crypto-browserify")
  }
}

6. 更好的长期缓存

javascript
output: {
  filename: '[name].[contenthash].js',
  chunkFilename: '[name].[contenthash].chunk.js'
}

// Webpack 5 的 contenthash 更稳定

14. 什么是 Module Federation?

答案

Module Federation(模块联邦) 是 Webpack 5 的革命性特性,允许多个独立的构建可以共享模块。

核心概念

  • Host:消费其他应用的应用
  • Remote:被消费的应用
  • Shared:共享的依赖

使用场景

  1. 微前端架构
  2. 组件库共享
  3. 多团队协作

配置示例

javascript
// 应用 A(Remote)
new ModuleFederationPlugin({
  name: 'app_a',
  filename: 'remoteEntry.js',
  exposes: {
    './Button': './src/components/Button',
    './Header': './src/components/Header'
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true }
  }
})

// 应用 B(Host)
new ModuleFederationPlugin({
  name: 'app_b',
  remotes: {
    app_a: 'app_a@http://localhost:3001/remoteEntry.js'
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true }
  }
})

使用

javascript
// 应用 B 中使用应用 A 的组件
import React, { lazy, Suspense } from 'react'

const RemoteButton = lazy(() => import('app_a/Button'))

function App() {
  return (
    <Suspense fallback="Loading...">
      <RemoteButton />
    </Suspense>
  )
}

优势

  • 运行时加载远程模块
  • 共享依赖,避免重复打包
  • 独立部署,互不影响
  • 版本控制灵活

五、工程实践

15. 如何配置多页应用?

答案

javascript
const HtmlWebpackPlugin = require('html-webpack-plugin')
const glob = require('glob')

// 自动获取入口
function getEntries() {
  const entries = {}
  const files = glob.sync('./src/pages/*/index.js')
  
  files.forEach(file => {
    const name = file.match(/pages\/(.*)\/index\.js/)[1]
    entries[name] = file
  })
  
  return entries
}

// 生成 HtmlWebpackPlugin 配置
function getHtmlPlugins() {
  const entries = getEntries()
  
  return Object.keys(entries).map(name => {
    return new HtmlWebpackPlugin({
      template: `./src/pages/${name}/index.html`,
      filename: `${name}.html`,
      chunks: ['vendors', 'common', name],
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  })
}

module.exports = {
  entry: getEntries(),
  
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist')
  },
  
  optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
          priority: 10
        },
        common: {
          minChunks: 2,
          name: 'common',
          chunks: 'all',
          priority: 5
        }
      }
    }
  },
  
  plugins: [
    ...getHtmlPlugins()
  ]
}

目录结构

src/
  pages/
    home/
      index.js
      index.html
    about/
      index.js
      index.html
    contact/
      index.js
      index.html

16. 如何区分开发环境和生产环境?

答案

方法 1:使用不同的配置文件

javascript
// webpack.common.js
module.exports = {
  entry: './src/index.js',
  module: {
    rules: [...]
  }
}

// webpack.dev.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  mode: 'development',
  devtool: 'eval-cheap-module-source-map',
  devServer: {
    hot: true,
    port: 3000
  }
})

// webpack.prod.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  mode: 'production',
  devtool: 'source-map',
  optimization: {
    minimize: true
  }
})
json
// package.json
{
  "scripts": {
    "dev": "webpack serve --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  }
}

方法 2:使用环境变量

javascript
// webpack.config.js
const isProd = process.env.NODE_ENV === 'production'

module.exports = {
  mode: isProd ? 'production' : 'development',
  devtool: isProd ? 'source-map' : 'eval-cheap-module-source-map',
  
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    }),
    ...(isProd ? [
      new MiniCssExtractPlugin(),
      new CompressionPlugin()
    ] : [])
  ]
}
json
{
  "scripts": {
    "dev": "NODE_ENV=development webpack serve",
    "build": "NODE_ENV=production webpack"
  }
}

17. 如何处理环境变量?

答案

方法 1:DefinePlugin

javascript
new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify('production'),
  'API_URL': JSON.stringify('https://api.example.com'),
  'VERSION': JSON.stringify('1.0.0')
})
javascript
// 代码中使用
if (process.env.NODE_ENV === 'production') {
  console.log('生产环境')
}

fetch(API_URL + '/users')

方法 2:dotenv-webpack

bash
npm install dotenv-webpack -D
// .env
API_URL=https://api.example.com
APP_NAME=MyApp
javascript
// webpack.config.js
const Dotenv = require('dotenv-webpack')

plugins: [
  new Dotenv()
]
javascript
// 代码中使用
console.log(process.env.API_URL)

方法 3:EnvironmentPlugin

javascript
new webpack.EnvironmentPlugin({
  NODE_ENV: 'development',
  API_URL: 'http://localhost:3000'
})

六、面试高频题

18. Webpack 与 Vite 有什么区别?

答案

特性WebpackVite
构建方式Bundle(打包)ESM + esbuild
开发服务器Bundle 后启动即时启动
热更新速度较慢(重新打包)极快(ESM)
生产构建WebpackRollup
生态成熟完善快速发展
配置复杂度较复杂简单
适用场景大型复杂项目现代浏览器项目

Webpack 优势

  • 生态成熟,插件丰富
  • 支持各种复杂场景
  • 兼容性好

Vite 优势

  • 开发体验极佳
  • 启动速度快
  • HMR 速度快

19. 如何实现长期缓存?

答案

1. 使用 contenthash

javascript
output: {
  filename: '[name].[contenthash].js',
  chunkFilename: '[name].[contenthash].chunk.js'
}

plugins: [
  new MiniCssExtractPlugin({
    filename: '[name].[contenthash].css'
  })
]

2. 提取 runtime

javascript
optimization: {
  runtimeChunk: 'single' // 或 { name: 'runtime' }
}

3. 分离第三方库

javascript
optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        chunks: 'all'
      }
    }
  }
}

4. Module IDs 优化

javascript
optimization: {
  moduleIds: 'deterministic' // Webpack 5 默认
}

效果

修改业务代码:
  app.js 变化 ✓
  vendors.js 不变 ✓(命中缓存)
  runtime.js 变化 ✓(体积小)

20. 如何分析打包结果?

答案

1. webpack-bundle-analyzer

bash
npm install webpack-bundle-analyzer -D
javascript
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

plugins: [
  new BundleAnalyzerPlugin({
    analyzerMode: 'static',
    openAnalyzer: false,
    reportFilename: 'bundle-report.html'
  })
]

2. webpack --profile --json

bash
webpack --profile --json > stats.json

上传到 https://webpack.github.io/analyse/

3. speed-measure-webpack-plugin

javascript
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()

module.exports = smp.wrap({
  // webpack 配置
})

输出每个 Loader 和 Plugin 的耗时。


总结

本文涵盖了 Webpack 面试中的核心知识点:

基础概念:Entry、Output、Loader、Plugin、Mode
构建流程:初始化、编译、输出三阶段
性能优化:构建速度优化、打包体积优化
高级特性:Module Federation、Persistent Cache
工程实践:多页应用、环境区分、长期缓存

掌握这些知识点,足以应对 2026 年的 Webpack 面试!