知蛛网
  • 首页
  • 会员
  • 活动
  • 工作台

常见问题
活动
关于我们
联系我们
隐私协议
用户协议
会员协议
© 2026 知蛛网. 保留所有权利。
首页会员工作台我的
flynn@flynn
主页wiki简历作品集
目录
全部书籍
00-路线
  • 学习路线
  • 命名与写作规范
01-计算机基础
01-计算机网络
  • 互联网是如何工作的
  • HTTP协议
  • TCP/IP协议
  • 浏览器直接打开本地html文件,请求时的协议问题
02-浏览器原理
  • 浏览器是如何渲染页面的
  • 浏览器是如何渲染页面的
  • 面试之浏览器
03-操作系统
  • 进程与线程
  • 内存管理与虚拟内存
  • IO 模型与多路复用
  • 文件系统与页缓存
04-数据结构与算法
  • 数组与链表
  • 栈与队列
  • 哈希表
  • 树与堆
  • 基础数据结构
01-基础数据结构
02-高级算法
  • 排序算法
  • 二分查找
  • 递归与回溯
  • 动态规划
  • 双指针与滑动窗口
03-leetcode刷题
02-前端核心
01-web开发
  • Web 和 Web 标准
  • web 入门
  • web 开发
  • URL
  • 域名
  • Web服务器
  • 命令行
  • 工作流程和流程
  • 超链接
  • 浏览器指纹
02-html
  • HTML基础语法
  • HTML 概述
  • HTML 发展史
  • HTML调试
  • HTML标题与段落
  • 文本格式化
  • 强调与重要性
  • 块级元素和内联元素
  • 列表
  • 区块
  • 语义元素
  • 页面结构化和语义化
  • 超链接
  • 相对路径和绝对路径
  • 图片
  • 表格
  • 表单和按钮
  • 多媒体
  • 视频/音频
  • HTML 头部
  • HTML 字符集
  • HTML颜色
  • HTML 语言代码
  • HTML 国家/地区
  • Emoji (表情符号)
  • HTML 标签简写及全称 |
  • SVG
  • Canvas 2D
  • Canvas 3D
  • 框架 `<iframe>`
  • HTML 拖放
  • HTML5 Geolocation(地理定位)
  • Web 存储
  • HTML URL 编码
  • MathML
  • 远程图片资源在自己网站中无法展示问题
03-css
  • CSS简介
  • CSS 语法
  • CSS 创建
  • CSS 发展史
  • CSS 浏览器支持
  • CSS 选择器
  • CSS `!important` 规则
  • css颜色
  • CSS 文本格式
  • CSS 盒子模型
  • CSS 尺寸
  • CSS 内边距
  • CSS 外边距
  • CSS 边框
  • CSS 轮廓
  • CSS 背景(background)
  • CSS 溢出
  • CSS 文档流
  • CSS 显示和可见性
  • CSS 浮动
  • CSS 定位
  • CSS 对齐方式
  • CSS 网页布局
  • CSS 多列布局(CSS Multi-column Layout)
  • CSS 透明度
  • CSS 响应式设计(Responsive Design)
  • CSS 媒体查询
  • CSS 列表
  • CSS 表格
  • CSS 表单
  • CSS 链接
  • CSS 用户界面
  • CSS 计数器
  • CSS 过渡
  • CSS 动画
  • CSS 2D 转换
  • CSS 3D 转换
  • CSS 变量(CSS Custom Properties)
  • CSS 原生嵌套(CSS Nesting)
  • CSS 函数(CSS Functions)
04-javascript
  • 什么是 JavaScript?
  • 编程范式(Programming Paradigm)
  • 什么是范式?
  • ECMAScript 规范
  • 什么是语法糖
  • 开发环境搭建
  • 什么是堆和栈?
  • 什么是执行上下文
  • JavaScript 垃圾回收机制
  • 作业队列与事件循环
  • 深拷贝和浅拷贝
  • 语法与类型
  • 字面量
  • 控制流与错误处理
  • 循环与迭代
  • 函数
  • 表达式与运算符
  • 数字和字符串
  • 表达日期与时间
  • 正则表达式
  • 索引集合类
  • 带键的集合
  • 对象
  • 类
  • Promise
  • async/await
  • 迭代器和生成器
  • 国际化
  • 模块
  • 资源管理
  • 属性的可枚举性和所有权
  • 闭包
  • 继承与原型链
  • 元编程
  • 内存管理
  • 内置对象
  • arguments 对象
  • BOM 对象(浏览器对象模型)
  • DOM 对象(文档对象模型)
  • bind、apply、call的区别
  • new 操作符
  • typeof 和 instanceof 的区别
  • HTML5 Web Workers
05-typescript
  • TypeScript 类型系统基础
  • 类型体操
03-框架与跨端
01-react
  • 开发环境搭建
  • JSX
  • 组件
  • 生命周期
  • Hooks
  • 组件通信
  • 状态管理
  • React 19 新特性
  • useCallback 闭包陷阱
  • 常用的性能优化操作
  • Firbe 架构
  • React 18 新特性
  • useRef
  • 基于umijs 4.0 搭建官网
  • react+vite本地开发,如何手机联调
  • React 实现谷歌登录
  • React 项目调起 WhatsApp
02-vue
  • vue 解决跨域请求
  • 在vue2使用TinyMCE富文本编辑器
  • 使用jszip 导出新闻
  • Vue 本地开发启用 https
  • 基于vue3+vite+ts+elementplus+pinia+axios搭建后台管理系统
03-react-native
  • iOS 开发环境(RN 0.72)
  • RN 原生模块(Native Module)
  • 查看Maven包的Java包名
  • 优化 APP 启动速度
  • 安全键盘
  • 启动图与 Icon 尺寸规范
  • RN如何生成/配置iOS的开发者证书和生产证书
  • 邓白氏编码
  • 微信开放平台配置Universal Link
  • 上架至Apple App Store
04-android
  • 开发环境搭建
  • Android项目目录结构
  • 认识Gradle
04-工程化
01-git
  • 如何解决已被git跟踪文件不在跟踪
  • git标签
  • Git报错: Failed to connect to github.com port 443 解决方案
  • Git 分支操作速查
02-构建工具
  • 构建工具原理与选型
02-webpack
  • webpack 核心概念与构建流程
  • webpack 性能优化
03-vite
  • vite 为什么快
  • vite 插件与生产构建
03-测试
  • 前端测试体系
04-部署
  • Nginx 反向代理解决跨域
  • SPA 刷新非首页报 404
05-docker
  • Docker 常用命令
  • docker-compose nginx配置ssl证书
  • Docker Desktop 升级后 docker-compose 命令找不到
06-性能优化
  • 前端性能优化体系
  • 背景 GIF 优化方案
07-微前端
  • 微前端实战(qiankun)
  • 微前端 · qiankun
01-qiankun
05-后端与数据
01-nodejs
  • Node 版本与依赖的 engines 冲突
  • Express 实现 Gmail 发信(邮箱验证码)
02-php
  • 浏览器保存新闻,发布到自有网站
  • [分布式] 浏览器保存新闻,发布到自有网站
  • 邮件发送,多账号轮询
  • nginx和php-fpm通信问题导致网站页面空白
03-python
  • macOS M1 芯片 如何安装 py 和 tkinter
  • tkinter 编写的程序如何打包成桌面软件
04-架构设计
  • 后台管理系统中角色管理、管理员管理、权限设置他们三者之间的关系
05-运维
  • redis启动失败
  • 实现自动备份宝塔项目及数据库到本地
  • 宝塔面板
01-宝塔
06-实战项目
  • 实战准备工作
02-项目记录
  • AI-Chat 模块技术文档
  • CRMChat 部署
07-面试专项
01-面试
  • 面试之自我介绍
  • CSS 面试
  • JS面试
  • React面试
  • Vue面试
  • RN 面试 · 题目清单
  • RN 面试 · 答案详解
  • RN 物流公司 · 题目清单
  • RN 物流公司 · 答案详解
  • Uniapp 面试
  • 带团队经验
12-react专项
  • 一个表格,某一行的某一列数据变动了,如何优化性能?
13-reactnative专项
  • RN 开发过程中,有遇到什么棘手的问题?你是如何解决的?
14-过往面试总结
  • 冷哥传媒 · 面试题
  • 沐腾科技 · 面试题
  • 字符频率排序
02-面试八股
  • 网络八股
  • 浏览器八股
  • 工程化八股
03-算法面试题
  • 前端高频手写题
  • 场景设计题
04-真实面试经历
  • 20251027 盾蓝科技 面试
  • 20251028 芝麻甜心 面试
08-工具
01-n8n
  • 初始n8n
  • 快速入门
  • 在宝塔中搭建n8n环境
  • n8n中常用节点
  • n8n和代码的区别
02-Trae
  • Figma MCP 配置指南
03-UI_UX_pro_max
  • UI_UX_pro_max的使用
04-开发环境
  • VMWare虚拟机安装
  • PowerShell 执行策略与编码设置
98-杂项
  • A股股票交易相关费用
99-手册
  • iOS 开发者账号申请流程及费用
  • 邓白氏编码申请及费用
  • App 推送通道申请及费用
  • App 开发收费项目清单
  • 注册AWS账号
  • 使用Amazon Polly实现文本转语音
  • Google 翻译 Key 申请与前端调用
  • 使用SmsForwarder转发短信

vite 为什么快

03-vite2026/11/14

vite 开发态快的本质是把「编译时机」从启动时推迟到请求时,代价是首屏模块请求数随项目深度增长。

同一个项目,webpack 冷启动 32 秒、改一行等 2 秒;换成 vite 启动 800 毫秒,改一行几乎瞬时。但本地首屏白屏 2 秒,Network 面板里滚了 200 多个 JS 请求。这两件事是同一个设计的正反面。

一、开发态不打包

webpack dev server   entry → 递归解析全部依赖 → 内存里生成 bundle → 浏览器加载 1-3 个文件
vite dev server      浏览器请求 /src/main.tsx → 服务端即时编译这一个文件 → 返回 ESM

浏览器原生支持 <script type="module">,每个 import 就是一次 HTTP 请求。vite 不需要提前知道依赖图,只在请求到来时用 esbuild 把该文件转成可执行的 ESM(TS/JSX 转换、CSS 处理、路径重写)。没被请求到的文件永远不会被编译,启动时间与业务代码规模解耦。

维度webpackvite dev
启动编译全量依赖图只做依赖预构建
改文件重建受影响 chunk只编译该文件,浏览器重取
页面入口打包后的 bundle源码入口 + 原生 ESM
规模增长线性变慢近似不变

二、裸模块问题与依赖预构建

浏览器不认识 import vue from 'vue':它不会去 node_modules 找文件,也不处理 CJS 的 module.exports。**依赖预构建(pre-bundle)**解决两件事:

  1. 格式转换:把 CJS / UMD 依赖转成 ESM,react 会被包成带 export default 的形式。
  2. 请求数收敛:lodash-es 有 600 多个内部文件,逐个请求会产生请求瀑布,预构建合并成单文件。
node_modules/.vite/deps/
├── _metadata.json   # 记录每个包的 hash 与来源,用于判断缓存有效性
├── vue.js
└── chunk-XXXX.js

什么情况会触发重新预构建

触发条件说明
lockfile 变化lock 文件 hash 变了,说明依赖版本可能变
optimizeDeps 变化include / exclude / esbuildOptions 改动
相关配置变化define、resolve.alias、插件返回的 config 影响解析结果
mode / NODE_ENV 变化不同 mode 的 define 不同,产物不能复用
运行时发现新依赖动态拼接的路径首次没扫到,vite 补跑并触发页面 reload
手动 --force强制清空 cacheDir 重跑

三、optimizeDeps.exclude / include

上一篇已经是第一篇
下一篇vite 插件与生产构建
本页目录
一、开发态不打包二、裸模块问题与依赖预构建什么情况会触发重新预构建三、optimizeDeps.exclude / include四、请求瀑布与 modulepreload五、生产构建为什么还用 Rollup六、HMR 为什么快七、vite.config.ts 示例八、常见误区面试怎么答关联阅读
optimizeDeps: {
  exclude: ['@my/ui', 'some-esm-lib'],          // 链接的本地包、已是 ESM 且要 HMR 的包
  include: ['my-lib/dist/deep-entry', 'cjs-only-pkg'], // 扫描不到的深层 CJS 依赖
}

exclude 用于 monorepo 里 file: 或 workspace 链接的包:源码是 ESM 且需要热更新,被预构建后会退化成「重新预构建 + 整页 reload」,HMR 失效。include 用于静态扫描识别不了的深层入口,import('my-lib/' + name) 这种拼接写法首屏才暴露,触发一次全量预构建并刷新页面,体验很差。

四、请求瀑布与 modulepreload

原生 ESM 的 import 是串行发现的:浏览器解析 main.tsx 才知道要请求 App.tsx,解析完才知道要请求 router.ts。层级越深,串行 RTT 越多:

main.tsx (1 RTT) → App.tsx (2 RTT) → router.ts (3 RTT) → ...

缓解手段是 <link rel="modulepreload">,让浏览器提前并行抓取静态依赖,生产构建会自动注入。但开发态的请求瀑布无法根治,它是模型的固有开销;项目层级极深(单页 500+ 模块)时,vite 首屏可能比 webpack 的 bundle 模式更慢。

五、生产构建为什么还用 Rollup

原因说明
Tree shaking 更彻底基于 ESM 静态分析,能跨模块删导出,配合 scope hoisting 产物更紧凑
插件生态成熟大量 Rollup 插件可直接复用,vite 插件本身就是其超集
代码分割可控manualChunks、output.format 适合多入口与库构建
esbuild 打包能力弱tree shaking、CSS 拆分、chunk 策略都不够完善

分工是:开发用 esbuild(单文件转换快),生产用 Rollup(产物质量优先)。这也解释了「vite 启动快 ≠ 打包快」——大项目 vite build 可能比 webpack build 更慢。

六、HMR 为什么快

webpack 的 HMR 要沿依赖图向上找 boundary:从变化的模块出发逐层检查 module.hot.accept,找不到就整页刷新,链越长重构建的 chunk 越多。

vite 的 HMR 建立在浏览器已有的 ESM 模块图上:文件变更 → 沿 import 链找到最近的 accept 边界 → 只让浏览器重新请求「该模块 + 失效的 importer」,URL 带 ?t=时间戳 破缓存。每个模块本来就是独立 URL,失效粒度天然是文件级,不需要重新打包。

维度webpack HMRvite HMR
失效粒度chunk / 模块,需重算边界单文件 URL
重建成本重建受影响 chunk只编译变更文件
传输内容新 chunk单模块 ESM

七、vite.config.ts 示例

export default defineConfig({
  plugins: [react()],
  resolve: { alias: { '@': path.resolve(__dirname, 'src') } },
  server: {
    port: 5173,
    proxy: {
      '/api': { target: 'http://127.0.0.1:8080', changeOrigin: true,
                rewrite: (p) => p.replace(/^\/api/, '') },
    },
  },
  build: {
    target: 'es2020',
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (!id.includes('node_modules')) return;
          if (/[\\/](react|react-dom|scheduler)[\\/]/.test(id)) return 'react';
          if (id.includes('lodash')) return 'lodash';
          return 'vendor';
        },
      },
    },
  },
});

manualChunks 返回 undefined 表示交回默认策略。react 系列必须同组,因为 react-dom 依赖 scheduler,分开会产生跨 chunk 循环引用。

八、常见误区

  1. 以为 vite 开发态完全不编译。TS、JSX、CSS Modules、路径重写都要在请求时处理,只是按需而非全量。
  2. 以为预构建缓存永远正确。改了 optimizeDeps 或 lockfile 后没生效,先删 node_modules/.vite 或 vite --force。
  3. 以为 vite 打包一定比 webpack 快。生产走 Rollup,大项目里 Rollup 的 tree shaking 与 chunk 生成可能更慢。
  4. 以为 exclude 越多越好。把 CJS 包 exclude 出去,浏览器会拿到 module.exports 报 does not provide an export named。

面试怎么答

Q:vite 为什么启动快? 开发态不做全量打包,只对 node_modules 做一次依赖预构建(esbuild),业务代码零编译启动;浏览器请求某个文件时才即时转换。启动耗时与项目模块数解耦,只与依赖数量相关。

Q:依赖预构建解决什么问题? 把 CJS/UMD 转成 ESM;把零散内部模块(如 lodash-es 的数百个文件)合并成单文件减少请求。产物在 node_modules/.vite/deps,靠 lockfile hash、optimizeDeps 配置、mode 判断是否复用。

Q:生产构建为什么不用 esbuild? esbuild 的单文件转换极快,但 tree shaking 精细度、CSS 代码分割、chunk 策略不如 Rollup。生产更看重产物质量与插件生态,所以用 Rollup,也说明「开发快」和「打包快」是两件事。

Q:vite 的 HMR 为什么比 webpack 快? webpack 要从变更模块沿依赖图向上找 accept boundary,再重建受影响 chunk;vite 的模块本来就是独立 URL,失效粒度是文件级,只需重取变更文件与失效的 importer,省掉打包与边界计算。

关联阅读

  • vite 插件与生产构建:钩子体系、manualChunks、legacy 与 base 配置
  • 构建工具原理与选型:两代构建模型的差异与选型判断
  • 前端性能优化体系:首屏指标与资源加载策略