Vite 与 webpack:从原理到排障
面试里最危险的回答是背“Vite 开发用 esbuild、生产用 Rollup”而不核对版本。工具链会演进:当前 Vite 官方文档已经使用 Rolldown 描述依赖预构建和部分构建配置。稳妥回答应先说明项目版本,再解释不随版本变化的设计目标。
Vite 为什么开发启动快
Vite 开发期通过原生 ESM 按浏览器实际请求转换源码,而不是启动前把整个应用打成一个 bundle。依赖预构建主要解决两件事:把 CommonJS/UMD 兼容为 ESM;把包含大量内部模块的依赖合并,减少浏览器请求瀑布。
预构建缓存受锁文件、补丁目录、相关配置和 NODE_ENV 等影响。依赖行为异常时先找缓存键变化原因,再决定是否 --force,不要把删缓存当固定仪式。
开发和生产不是同一条链路
开发目标是按需转换、快速 HMR 和调试;生产需要完整模块图、tree shaking、chunk、压缩、资源哈希与可部署产物。插件钩子虽统一,边界行为不同,因此必须执行生产构建并预览。
本博客升级时就发现旧页面在开发环境正常,但构建期 SSR 报 window is not defined。根因是 Markdown 脚本在模块顶层访问浏览器全局;修复方式是默认设置 SSR 安全状态,并在 onMounted 后访问浏览器 API。
webpack loader 与 plugin
- loader:面向单个模块内容的转换,把非 JavaScript 资源或新语法变成模块。
- plugin:通过 compiler/compilation hooks 参与完整构建生命周期,可生成、优化、注入和分析资产。
回答时按“输入、作用域、生命周期、例子”区分,比只背名词更可靠。
tree shaking 失效的常见原因
需要静态 ESM、生产优化和可分析的副作用。usedExports 标识引用,sideEffects 帮助跳过整个无副作用模块/子树。错误设置 sideEffects: false 可能把 CSS、polyfill 或注册代码移除;Babel 转 CJS、动态访问导出也会削弱分析。
验证方式不是看配置,而是做最小消费构建、分析产物并做功能回归。
chunk 与缓存一起设计
- 入口按路由或业务域动态导入。
- 稳定且高频共享依赖可形成长期缓存 chunk,但不要创建一个巨型 vendor。
- 静态资产使用 content hash + 长缓存;HTML 短缓存或
no-cache。 - 发布保持原子性,并保留上一版本 chunk,降低
ChunkLoadError。
构建慢怎么定位
- 区分冷启动、HMR、类型检查和生产构建。
- 启用构建 profile/debug,检查插件耗时与重复转换。
- 关注模块数量、barrel files、Source Map、图片管线和大依赖。
- 建立基线,优化后使用相同机器与缓存状态回归。
参考:Vite 依赖预构建、Vite 性能指南、webpack Tree Shaking、webpack Code Splitting。