Files
zhuangang/topics/frontend/vite/interview.md
T

3.9 KiB
Raw Blame History

id, title, type, domain, stack, tags, level, related, week
id title type domain stack tags level related week
frontend.vite.interview Vite 面试题 interview frontend
vite
Vite
Rolldown
HMR
插件
面试
intermediate
frontend.vite.dev-build-config
frontend.webpack.interview
7
16

Vite 面试题

基础

【基础】Vite 为什么开发时启动快?

参考答案:开发时不打包,利用浏览器原生 ES 模块按需请求、按需转换;第三方依赖预构建并强缓存;热更新只更新修改的模块,与项目规模基本无关。

追问:预构建做了什么?→ 把 CommonJS / UMD 依赖转成 ESM,把有很多内部模块的依赖合并成少量文件,减少浏览器请求数。

【基础】既然浏览器支持 ESM,生产环境为什么还要打包?

参考答案:未打包时模块请求多、瀑布式加载慢;打包可以做 tree shaking、压缩、拆包、资源哈希命名以便长期缓存、兼容处理。

追问:Vite 8 生产构建用什么?→ Rolldown(Rust 实现、兼容 Rollup 插件接口);Vite 7 及以前是 Rollup。

【基础】Vite 中的环境变量怎么使用?

参考答案:.env / .env.[mode] 文件;浏览器代码通过 import.meta.env 读取,只有 VITE_ 前缀的变量会暴露;配置文件中用 loadEnv 读取全部变量。

追问:密钥可以放进 VITE_ 变量吗?→ 不可以,会被打包进前端代码。

进阶

【进阶】Vite 插件有哪些常用钩子?

参考答案:通用钩子(与 Rollup 兼容):resolveId、load、transform、buildStart / buildEnd;Vite 专有:config、configResolved、configureServer(给开发服务器加中间件)、transformIndexHtml、handleHotUpdate。可以用 enforce 控制顺序、apply 控制只在开发或构建时生效。

追问:虚拟模块怎么实现?→ resolveId 识别特定 id 返回带 \0 前缀的内部 id,load 返回模块源码。

【进阶】Vite 的 HMR 是如何工作的?

参考答案:开发服务器监听文件变化,通过 WebSocket 通知浏览器;客户端根据模块依赖图找到接受更新的边界模块(例如 Vue 组件),重新请求该模块并替换,组件状态尽量保留;找不到边界时刷新整页。

追问:为什么有时候修改后整页刷新?→ 修改的模块及其上层没有模块接受热更新(例如修改了入口文件或纯工具模块的上层没有 HMR 边界)。

【进阶】怎么做拆包?

参考答案:动态 import() 自动生成独立 chunk(路由懒加载);第三方库按变化频率分组(Vite 8 用 codeSplitting.groups),利于长期缓存;避免拆得过碎。

追问:如何分析产物体积?→ 使用打包分析插件生成可视化报告,找大依赖和重复依赖。

场景题

【场景题】老项目从 webpack 迁移到 Vite,你怎么推进?

参考答案:盘点 webpack 专有用法 → 两套配置并存 → 逐项替换(require.context、环境变量、自定义 loader)→ 冒烟测试和产物对比 → 灰度上线并保留回滚。详见迁移场景。

追问:迁移遇到的最大问题?→ 常见的是 CommonJS 依赖和隐式的 Node 全局变量,以及开发模式正常、生产构建报错。

【场景题】开发时用 Vite 代理调用 AI 流式接口,前端收到的内容是一次性出现的,怎么排查?

参考答案:先用 curl 直连后端确认后端是否真的逐条发送和 flush;再经过代理用 curl -N 验证;检查响应头是否是 text/event-stream、是否被压缩中间件缓冲;最后检查前端是否用流式方式读取(fetch 的 body.getReader() 或 EventSource),而不是 await res.text()。

追问:生产环境同样问题?→ 检查 Nginx 的 proxy_buffering 和 X-Accel-Buffering 响应头、CDN / 网关是否缓冲。