4.1 KiB
id, title, type, domain, stack, tags, level, related, week
| id | title | type | domain | stack | tags | level | related | week | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frontend.webpack.interview | webpack 面试题 | interview | frontend |
|
|
intermediate |
|
|
webpack 面试题
基础
【基础】loader 和 plugin 有什么区别?
参考答案:loader 负责把某类文件转换成 webpack 能处理的 JS 模块,本质是转换函数,在 module.rules 中配置;plugin 通过钩子介入整个编译生命周期,做打包优化、资源管理、注入环境变量等,在 plugins 中配置。
追问:多个 loader 的执行顺序?→ 从右到左(数组从后往前);每个 loader 还有 pitch 阶段,从左到右执行。
【基础】hash、chunkhash、contenthash 的区别?
参考答案:hash 与整次构建相关,任何改动都会变;chunkhash 与所在 chunk 相关;contenthash 与文件内容相关,最适合长期缓存(例如 CSS 文件不随 JS 变化)。
追问:只改了业务代码,vendor 的文件名也变了,为什么?→ 运行时代码或模块 id 混在 vendor 中;用 runtimeChunk: "single" 并使用确定性的模块 id(webpack 5 生产模式默认)。
【基础】什么是 tree shaking?
参考答案:删除未使用代码。依赖 ES 模块的静态导入导出,构建时标记未使用的导出,压缩阶段删除;sideEffects 声明哪些模块有副作用。
追问:什么情况会失效?→ 使用 CommonJS、模块有副作用但未声明、babel 把 ESM 转成了 CommonJS、动态访问导出对象。
进阶
【进阶】讲讲 webpack 的构建流程。
参考答案:合并配置 → 创建 Compiler 并注册插件 → 从入口开始构建模块:调用 loader 转换、解析 AST 收集依赖、递归 → 形成模块依赖图 → 按入口、动态导入和 splitChunks 规则生成 chunk → 生成代码、写入文件。全程通过 tapable 钩子通知插件。
追问:Compiler 和 Compilation 的区别?→ Compiler 代表整个 webpack 实例,生命周期贯穿始终;Compilation 代表一次构建(监听模式下每次重新构建创建新的 Compilation)。
【进阶】如何提升 webpack 的构建速度?
参考答案:持久化缓存;缩小 loader 范围;更快的转译器(swc / esbuild 类 loader);减少或简化 source map;类型检查并行;合理的 resolve 配置;必要时考虑 Rspack。
追问:怎么确定瓶颈?→ 先用速度分析工具或 --profile 统计各阶段和 loader 耗时,再有针对性地优化。
【进阶】什么是模块联邦?适用场景?
参考答案:webpack 5 提供的能力,让独立构建和部署的应用在运行时互相加载模块,并共享依赖(如同一份 Vue)。用于微前端、多团队独立发布。
追问:有什么风险?→ 共享依赖版本不一致、运行时加载失败要降级、类型共享麻烦、调试复杂。
场景题
【场景题】CI 构建十几分钟、首页 JS 几 MB,你怎么优化并防止反弹?
参考答案:先度量(速度分析、产物分析)→ 构建提速(缓存、swc、并行类型检查)→ 体积优化(懒加载、按需引入、拆包、tree shaking)→ CI 体积预算。详见构建优化场景。
追问:优化效果怎么证明?→ 对比优化前后的构建时间和关键页面的产物大小、LCP 等指标,用数据说话。
【场景题】要求你写一个 loader,把团队内部的 .md 文档直接作为字符串导入组件,怎么做?
参考答案:loader 导出一个函数,参数是文件内容,用 this.getOptions() 读取配置,返回 export default <JSON 字符串> 形式的 JS 代码;在 module.rules 中用 test: /\.md$/ 配置。见 examples/webpack-config。
追问:如果要转成 HTML 并支持异步处理?→ 使用 this.async() 获取回调,调用 Markdown 解析库后回调结果;注意输出内容的 XSS 风险。