Webpack面试题

本文最后更新于 2025年8月4日 晚上

参考:
https://juejin.cn/post/6844904094281236487
https://juejin.cn/post/6943468761575849992

Webpack 的作用是什么?

  • 模块打包。可以将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。利用好打包我们就可以在开发的时候根据我们自己的业务自由划分文件模块,保证项目结构的清晰和可读性。
  • 编译兼容。在前端的“上古时期”,手写一堆浏览器兼容代码一直是令前端工程师头皮发麻的事情,而在今天这个问题被大大的弱化了,通过 Webpack 的 Loader 机制,不仅仅可以帮助我们对代码做 polyfill,还可以编译转换诸如 .less、.vue、.jsx 这类在浏览器无法识别的格式文件,让我们在开发的时候可以使用新特性和新语法做开发,提高开发效率。
  • 能力扩展。通过 Webpack 的 Plugin 机制,在实现模块化打包和编译兼容的基础上,可以进一步实现如按需加载,代码压缩等一系列功能,帮助我们进一步提高自动化程度,工程效率以及打包输出的质量。

Webpack 构建流程

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  • 初始化参数
    从配置文件和 Shell 语句中读取与合并参数,得出最终的参数
  • 开始编译
    用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
  • 确定入口
    根据配置中的 Entry 找出所有的入口文件
  • 编译模块
    从入口文件出发,调用所有配置的 Loader 对模块进行翻译,找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理
  • 完成模块编译
    经过上一步使用 Loader 翻译完所有模块后,得到每个模块被翻译后的最终内容以及它们之间的依赖关系
  • 输出资源
    根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,然后把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会
  • 输出完成
    在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。

简洁版:

  • 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
  • 编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理。
  • 输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中。

Loader 和 Plugin 的区别?

Loader 是函数,在该函数中对接收到的内容进行转换,返回转换后的结果。因为 Webpack 只认识 JavaScript,所以 Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。

Loader 在 module.rules 中配置,作为模块的解析规则,类型为数组。每一项都是一个 Object,内部包含了 test(类型文件)、loader、options (参数)等属性。

Plugin 是插件,基于事件流框架 Tapable,插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

Plugin 在 plugins 中单独配置,类型为数组,每一项是一个 Plugin 的实例,参数都通过构造函数传入。

有哪些常见的 Loader?

Loader 官网:https://Webpack.docschina.org/loaders

文件

  • val-loader:将代码作为模块执行,并将其导出为 JS 代码
  • ref-loader:用于手动建立文件之间的依赖关系

JSON

  • cson-loader:加载并转换 CSON 文件

语法转换

  • babel-loader:把 ES6 转换成 ES5
  • buble-loader:使用 Bublé 加载 ES2015+ 代码并将其转换为 ES5
  • traceur-loader:使用 Traceur 加载 ES2015+ 代码并将其转换为 ES5
  • ts-loader:像加载 JavaScript 一样加载 TypeScript 2.0+
  • coffee-loader:像加载 JavaScript 一样加载 CoffeeScript
  • fengari-loader:使用 fengari 加载 Lua 代码
  • elm-webpack-loader:像加载 JavaScript 一样加载 Elm

模板

  • html-loader:将 HTML 导出为字符串,需要传入静态资源的引用路径
  • pug-loader:加载 Pug 和 Jade 模板并返回一个函数
  • markdown-loader:将 Markdown 编译为 HTML
  • react-markdown-loader:使用 markdown-parse 解析器将 Markdown 编译为 React 组件
  • posthtml-loader:使用 PostHTML 加载并转换 HTML 文件
  • handlebars-loader:将 Handlebars 文件编译为 HTML
  • markup-inline-loader:将 SVG/MathML 文件内嵌到 HTML 中。在将图标字体或 CSS 动画应用于 SVG 时,此功能非常实用。
  • twig-loader:编译 Twig 模板并返回一个函数
  • remark-loader:通过 remark 加载 markdown,且支持解析内容中的图片

样式

  • style-loader:将模块导出的内容作为样式并添加到 DOM 中,通过 DOM 操作去加载 CSS
  • css-loader:加载 CSS 文件并解析 import 的 CSS 文件,最终返回 CSS 代码,支持模块化、压缩、文件导入等特性
  • less-loader:加载并编译 LESS 文件
  • sass-loader:加载并编译 SASS/SCSS 文件
  • postcss-loader:使用 PostCSS 加载并转换 CSS/SSS 文件,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀
  • stylus-loader:加载并编译 Stylus 文件

框架

  • vue-loader:加载并编译 Vue 组件
  • angular2-template-loader:加载并编译 Angular 组件

第三方

  • awesome-typescript-loader:将 TypeScript 转换成 JavaScript,性能优于 ts-loader
  • eslint-loader:通过 ESLint 检查 JavaScript 代码
  • tslint-loader:通过 TSLint 检查 TypeScript 代码
  • mocha-loader:加载 Mocha 测试用例的代码
  • coverjs-loader:计算测试的覆盖率
  • i18n-loader: 国际化
  • cache-loader: 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里
  • file-loader
  • url-loader

有哪些常见的 Plugin?

Plugin 官网:https://Webpack.docschina.org/plugins

  • define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
  • ignore-plugin:忽略部分文件
  • html-Webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)
  • web-Webpack-plugin:可方便地为单页应用输出 HTML,比 html-Webpack-plugin 好用
  • uglifyjs-Webpack-plugin:不支持 ES6 压缩 (Webpack4 以前)
  • terser-Webpack-plugin: 支持压缩 ES6 (Webpack4)
  • Webpack-parallel-uglify-plugin: 多进程执行代码压缩,提升构建速度
  • mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载
    (替代 extract-text-Webpack-plugin)
  • serviceworker-Webpack-plugin:为网页应用增加离线缓存功能
  • clean-Webpack-plugin: 目录清理
  • ModuleConcatenationPlugin: 开启 Scope Hoisting
  • speed-measure-Webpack-plugin: 可以看到每个 Loader 和 Plugin 执行耗时
    (整个打包耗时、每个 Plugin 和 Loader 耗时)
  • Webpack-bundle-analyzer: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)

文件监听原理

在发现源码发生变化时,自动重新构建出新的输出文件。

Webpack 开启监听模式,有两种方式:

  • 启动 Webpack 命令时,带上 –watch 参数
  • 在配置 Webpack.config.js 中设置 watch:true

原理:轮询判断文件的最后编辑时间是否变化,如果某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等aggregateTimeout后再执行。

缺点:每次需要手动刷新浏览器。

1
2
3
4
5
6
7
8
9
10
11
12
13
module.export = {
// 默认false,也就是不开启
watch: true,
// 只有开启监听模式时,watchOptions才有意义
watchOptions: {
// 默认为空,不监听的文件或者文件夹,支持正则匹配
ignored: /node_modules/,
// 监听到变化发生后会等300ms再去执行,默认300ms
aggregateTimeout: 300,
// 判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,默认每秒问1000次
poll: 1000,
},
};

热更新原理

Webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。这个机制可以做到不用人刷新浏览器而将新变更的模块替换掉旧的模块。

HMR 的核心就是客户端从服务端拉去更新后的文件,准确的来说是 chunk diff(chunk 需要更新的部分),实际上 WDS 与浏览器之间维护了一个 Websocket,当本地资源发生变化时,WDS 会向浏览器推送更新,并带上构建时的 hash,让客户端与上一次资源进行对比。客户端对比出差异后会向 WDS 发起 Ajax 请求来获取更改内容(文件列表、hash),这样客户端就可以再借助这些信息继续向 WDS 发起 jsonp 请求获取该 chunk 的增量更新。

后续的部分(拿到增量更新之后如何处理?哪些状态该保留?哪些又需要更新?)是由 HotModulePlugin 来完成,提供了相关 API 以供开发者针对自身场景进行处理,像 react-hot-loader 和 vue-loader 都是借助这些 API 实现 HMR。


Webpack面试题
https://xuekeven.github.io/2021/09/25/Webpack面试题/
作者
Keven
发布于
2021年9月25日
更新于
2025年8月4日
许可协议