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 面试!