全栈程序员-前端第二节- vite是什么?

Vite 用户可见功能

1. 开发服务器 (vite dev)

  • 即时启动
  • 热模块替换(HMR)
  • 原生 ES 模块支持
  • 自动依赖预构建

2. 生产构建 (vite build)

  • 代码打包与优化
  • 代码分割
  • 资源优化
  • Source Map 生成
  • SSR 构建支持

3. 预览构建结果 (vite preview)

  • 本地预览生产构建
  • 验证构建结果

4. 依赖优化 (vite optimize)

  • 依赖预构建(已废弃,自动执行)

总结

对用户来说,Vite 主要有 3 个核心功能:

  1. 开发服务器(开发时使用)
  1. 生产构建(构建时使用)
  1. 预览服务器(预览构建结果)

其他功能(如 HMR、依赖优化、插件等)是这些核心功能的组成部分,用户通过配置和插件系统使用它们。

Vite 的三个核心功能

1. 开发服务器 (vite dev / vite serve)

作用:启动本地开发服务器,用于开发阶段。

主要特性:

  • 即时启动:基于原生 ES 模块,无需打包即可启动
  • 热模块替换(HMR):修改代码后立即更新,无需刷新页面
  • 自动依赖预构建:首次启动时预构建 CommonJS/UMD 依赖
  • 文件监听:监听文件变化并触发更新
  • WebSocket 通信:用于 HMR 和错误提示
  • 中间件链:处理静态文件、代理、转换等

使用场景:日常开发

复制代码
vite dev          # 启动开发服务器
vite serve        # 别名,功能相同

2. 生产构建 (vite build)

作用:将源代码打包并优化,生成生产环境可部署的静态资源。

主要特性:

  • 代码打包:使用 Rolldown/Rollup 打包
  • 代码压缩:使用 esbuild 或 terser 压缩
  • 代码分割:自动分割代码块,优化加载
  • 资源优化:处理图片、CSS 等静态资源
  • Source Map:生成调试用的 source map
  • SSR 构建:支持服务端渲染构建
  • 清单文件:生成 manifest.json 用于资源映射

使用场景:部署到生产环境前

复制代码
vite build        # 构建生产版本
vite build --watch # 监听模式构建

3. 预览服务器 (vite preview)

作用:本地预览生产构建的结果,验证构建产物。

主要特性:

  • 静态文件服务:提供构建后的静态文件
  • 代理支持:支持 API 代理配置
  • CORS 支持:可配置跨域
  • 压缩支持:支持 gzip 压缩
  • HTML 回退:支持 SPA 路由回退

使用场景:构建完成后,在本地验证生产构建结果

复制代码
vite build         # 先构建
vite preview       # 预览构建结果

三者关系

复制代码
开发阶段: vite dev
    ↓
   开发、调试、测试
    ↓
构建阶段: vite build  
    ↓
   生成 dist/ 目录
    ↓
预览阶段: vite preview
    ↓

总结

  • 开发服务器:开发时使用,提供 HMR 和即时反馈
  • 生产构建:构建时使用,生成优化的生产代码
  • 预览服务器:预览时使用,验证构建结果

这三个功能覆盖了从开发到部署的完整流程。

为什么生产要用npm run build不用npm run dev

npm run build 的优势

1. 性能优化

代码压缩和优化
复制代码
开发模式 (dev):
main.js: 500KB (未压缩,包含注释和空格)

生产构建 (build):
main.js: 150KB (压缩后,去除注释、空格、变量名简化)
  • 文件体积更小:代码压缩、去除注释和调试信息
  • 加载更快:更小的文件下载更快
  • 执行更快:优化后的代码执行效率更高
代码分割(Code Splitting)
复制代码
开发模式: 所有代码在一个请求中
生产构建: 按需分割成多个 chunk
  - main.js (核心代码)
  - vendor.js (第三方库)
  - component-a.js (按需加载)
  • 按需加载:只加载当前需要的代码
  • 并行加载:多个文件可以同时下载
  • 缓存优化:修改代码时,未变的文件可以继续使用缓存

2. 生产环境特性

Tree Shaking(移除未使用代码)
复制代码
// 你的代码
import { func1, func2 } from 'library'
// 只使用了 func1

开发模式: 可能包含 func1 和 func2
生产构建: 只包含 func1(移除未使用的 func2)
资源优化
  • 图片压缩:自动优化图片大小
  • CSS 压缩:去除空格和注释
  • 小资源内联:小于 4KB 的资源转为 base64

3. 浏览器兼容性

代码转译
复制代码
开发模式: 使用现代 JavaScript(ES2020+)
生产构建: 转译为兼容更多浏览器(ES2015+)
  • 兼容更多浏览器:转译为旧版 JavaScript
  • 自动添加 polyfill:为旧浏览器提供新特性支持

4. 安全性

代码混淆
复制代码
开发模式:
function getUserData() { ... }  // 函数名清晰可见

生产构建:
function a(){...}  // 函数名被混淆,难以理解
  • 代码混淆:增加逆向难度
  • 隐藏实现细节:保护业务逻辑

5. 部署优势

静态文件部署
复制代码
开发模式:
- 需要 Node.js 环境
- 需要运行 npm run dev
- 占用服务器资源(CPU、内存)

生产构建:
- 只需要静态文件服务器(Nginx)
- 不需要 Node.js
- 资源占用极低

6. 实际对比

文件大小对比
复制代码
开发模式:
- main.js: 2.5MB
- 100+ 个文件请求
- 总加载时间: 5秒

生产构建:
- main.js: 200KB (压缩后)
- vendor.js: 150KB
- 10个文件请求
- 总加载时间: 0.8秒
加载速度对比
复制代码
开发模式:
首次加载: 需要转换所有文件,较慢
后续加载: 有缓存,但仍有转换开销

生产构建:
首次加载: 直接加载优化后的文件,很快
后续加载: 利用浏览器缓存,极快

7. 用户体验

  • 更快的页面加载:优化后的文件加载更快
  • 更流畅的交互:代码优化后执行更快
  • 更好的移动端体验:文件更小,节省流量

总结对比表

特性 npm run dev npm run build
文件大小 大(未压缩) 小(压缩优化)
加载速度 慢(需要转换) 快(直接加载)
代码分割 有(按需加载)
浏览器兼容 现代浏览器 更多浏览器
部署方式 需要 Node.js 只需静态服务器
安全性 代码可见 代码混淆
适用场景 开发调试 生产部署

结论

npm run build 的优势:

  1. 性能:文件更小、加载更快
  1. 优化:代码压缩、分割、Tree Shaking
  1. 兼容性:支持更多浏览器
  1. 部署:简单、成本低、可扩展
  1. 用户体验:更快的加载和交互

简单说:dev 适合开发,build 适合生产。生产环境必须使用 build 才能获得这些优势。

Vite的缓存策略

Nginx 什么时候能帮忙缓存?

关键区别:开发环境 vs 生产环境

环境 缓存策略 原因
开发环境 (npm run dev) ❌ 不缓存 代码频繁变化,需要实时更新
生产环境 (npm run build) ✅ 可以缓存 代码稳定,文件名包含 hash

生产构建的文件名机制

关键代码(build.ts 第727-730行):

复制代码
entryFileNames: `[name]-[hash].${jsExt}`
// 例如: main-abc123def456.js

chunkFileNames: `[name]-[hash].${jsExt}`
// 例如: vendor-xyz789ghi012.js

构建后的文件名包含内容 hash:

复制代码
dist/
  ├── index.html
  ├── assets/
  │   ├── main-abc123def456.js    ← 文件名包含 hash
  │   ├── main-abc123def456.css
  │   └── vendor-xyz789ghi012.js

为什么可以安全缓存?

1. 文件名包含内容 hash
复制代码
文件内容变化前:
main-abc123def456.js  (hash: abc123def456)

你修改了代码,重新构建:
main-xyz789ghi012.js  (hash: xyz789ghi012)  ← 文件名变了!
  • 内容变化 → hash 变化 → 文件名变化
  • 文件名变化 → 浏览器认为是新文件 → 自动请求新文件
2. HTML 文件引用会更新
复制代码
<!-- 构建前 -->

<script src="/assets/main-abc123def456.js"></script>

<!-- 你修改代码,重新构建后 -->

<script src="/assets/main-xyz789ghi012.js"></script>
  • HTML 会更新引用
  • 旧文件不会被请求
  • 新文件自动加载

Nginx 缓存配置

推荐配置
复制代码
server {
    listen 80;
    root /path/to/dist;
    index index.html;

    # HTML 文件不缓存(因为会更新引用)
    location ~* \.html$ {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";
    }

    # 静态资源(JS/CSS/图片)长期缓存
    # 因为文件名包含 hash,内容变化时文件名也会变化
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        add_header Cache-Control "public, max-age=31536000, immutable";
        # 31536000 秒 = 1 年
    }

    # SPA 路由回退
    location / {
        try_files $uri $uri/ /index.html;
    }
}

缓存策略对比

开发环境(不能缓存)
复制代码
请求: GET /assets/main-abc123def456.js
响应: Cache-Control: public, max-age=31536000, immutable
原因: 
  - 文件名包含 hash
  - 内容变化时文件名也会变化
  - 可以安全地长期缓存

实际例子

场景 1:首次部署
复制代码
1. 构建: npm run build
   生成: main-abc123def456.js

2. 用户访问网站
   浏览器请求: GET /assets/main-abc123def456.js
   Nginx 返回文件,设置缓存 1 年

3. 用户再次访问
   浏览器使用缓存 ✅(因为文件名没变)
场景 2:更新代码(html不缓存更新引用)
复制代码
1. 你修改了代码,重新构建
   生成: main-xyz789ghi012.js  ← 新文件名!

2. HTML 更新引用:
   <script src="/assets/main-xyz789ghi012.js"></script>

3. 用户访问网站
   浏览器请求: GET /assets/main-xyz789ghi012.js
   ← 这是新文件,浏览器会请求(不会用旧缓存)

4. 旧文件 main-abc123def456.js 不再被引用
   可以安全删除或继续缓存(不会被使用)

缓存的好处

  1. 性能提升
  • 减少服务器请求
  • 减少带宽消耗
  • 更快的页面加载
  1. 成本降低
  • 减少服务器负载
  • 减少 CDN 流量费用
  1. 用户体验
  • 更快的响应速度
  • 更好的离线体验

总结

Nginx 可以在生产环境缓存,因为:

  1. 文件名包含 hash:内容变化时文件名也会变化
  1. HTML 会更新引用:确保加载新文件
  1. 静态文件稳定:生产环境代码不会频繁变化

开发环境不能缓存(Vite 设置 no-cache),生产环境可以缓存(文件名包含 hash,可以安全地长期缓存)。

这就是为什么:

  • 开发时:Cache-Control: no-cache(不缓存)
  • 生产时:Cache-Control: max-age=31536000, immutable(长期缓存)

Vite 如何转换 Vue/React 代码

核心转换工具

Vite 使用两种转换器(按优先级):

  1. OXC(新,默认)
  • 更快的 Rust 实现
  • 支持 JS/TS/JSX/TSX
  1. ESBuild(旧,已废弃)
  • 仍可用但会警告
  • 逐步迁移到 OXC

转换流程

1. 浏览器请求文件(npm run dev 模式)
复制代码
浏览器请求: GET /src/App.vue
    ↓
Vite 开发服务器接收请求
    ↓
进入 transformRequest 流程

最终返回处理后的结果给前端浏览器 前端浏览器看到的代码是未转化的TS、Vue、React代码

为什么要转换?

核心原因:浏览器无法直接执行这些代码

复制代码
1. JSX/TSX 语法浏览器不支持
JSX 不是有效的 JavaScript
// ❌ 浏览器无法理解这个语法function App() {  return <div>Hello</div>}
浏览器只能理解:
// ✅ 浏览器能理解的 JavaScriptfunction App() {  return React.createElement('div', null, 'Hello')}
原因:
JSX 是语法糖,不是标准 JavaScript
浏览器只能执行标准 JavaScript
需要转换为浏览器能理解的代码
2. Vue 模板语法浏览器不支持
Vue 模板不是 JavaScript
<!-- ❌ 浏览器无法理解 --><template>  <div>{{ message }}</div></template>
需要转换为:
// ✅ 浏览器能理解的 JavaScriptimport { createElementVNode } from 'vue'export default {  render() {    return createElementVNode('div', null, this.message)  }}

构建后的代码是纯 JavaScript

构建前 vs 构建后

Vue 组件
复制代码
<!-- 构建前:src/App.vue -->
<template>
  <div class="container">
    <h1>{{ title }}</h1>
    <button @click="handleClick">Click me</button>
  </div>
</template>

<script setup>
import { ref } from 'vue'
const title = ref('Hello Vue')
const handleClick = () => {
  console.log('clicked')
}
</script>

构建后

复制代码
// dist/assets/main-abc123.js
import{a as e,b as r}from"vue";
const s=e("

验证方法

  1. 运行构建:

    复制代码
       npm run build
  1. 查看 dist/ 目录:

    复制代码
       dist/
    
         ├── index.html
    
         └── assets/
    
             ├── main-abc123.js    ← 纯 JavaScript
    
             └── main-abc123.css
  1. 打开 dist/assets/main-abc123.js:
  • 看到的是纯 JavaScript
  • 没有 <template>、<script setup>
  • 没有 JSX 语法
  • 没有 TypeScript 类型
  1. 在浏览器中查看:
  • 打开开发者工具 → Sources
  • 查看加载的 JS 文件
  • 都是标准 JavaScript

总结

  • 构建后,浏览器看到的是纯 JavaScript 代码
  • Vue/React 的特殊语法已被转换为标准 JavaScript 函数调用
  • 浏览器可以直接执行,无需额外转换

这就是为什么构建后的代码可以直接部署到任何静态服务器,浏览器可以直接运行。

Vite 如何将代码更新推送到所有浏览器(只适用于 npm run dev)

核心机制:WebSocket 广播

Vite 使用 WebSocket 服务器管理所有浏览器连接,并通过广播将更新推送给所有客户端。

完整流程

1. 建立 WebSocket 连接
复制代码
// 浏览器打开页面时
浏览器 → 连接 WebSocket (ws://localhost:5173)
    ↓
Vite WebSocket 服务器接收连接
    ↓
将客户端添加到 wss.clients 集合中
2.发生变更,广播到所有的客户端
复制代码
文件变化 (src/App.vue)
    ↓
chokidar 文件监听器检测到变化
    ↓
触发 watcher.on('change')
    ↓
调用 handleHMRUpdate()
    ↓
生成 HMR 更新消息
    ↓
WebSocket 服务器.send()
    ↓
遍历所有客户端: wss.clients.forEach()
    ↓
┌─────────────────────────────────┐
│  浏览器1 (Chrome)                │ ← 收到更新
│  浏览器2 (Firefox)               │ ← 收到更新
│  浏览器3 (Safari)                │ ← 收到更新
│  标签页1 (localhost:5173)       │ ← 收到更新
│  标签页2 (localhost:5173/page2) │ ← 收到更新
└─────────────────────────────────┘

Vite的HMR(热更新)只适用于 npm run dev

复制代码
1. 你修改文件 (App.vue)
    ↓
2. chokidar 检测到变化
    ↓
3. handleHMRUpdate()
    ├─ 找到受影响的模块
    ├─ propagateUpdate() 分析更新边界
    └─ 确定哪些模块可以热更新
    ↓
4. 生成更新消息
   {
     type: 'update',
     updates: [{
       type: 'js-update',
       path: '/src/App.vue',
       acceptedPath: '/src/App.vue',
       timestamp: 1234567890
     }]
   }
    ↓
5. WebSocket 广播
   wss.clients.forEach(client => {
     client.send(updateMessage)
   })
    ↓
6. 浏览器接收消息
    ↓
7. 客户端处理更新
   ├─ 重新导入模块: import('/src/App.vue?t=1234567890')
   ├─ 执行模块的 accept 回调
   └─ 更新 DOM(如果模块有更新逻辑)
    ↓
8. 页面更新,无需刷新 ✅
相关推荐
你脸上有BUG2 小时前
TreeSelect 组件 showCheckedStrategy 属性不生效问题
前端·vue
小北方城市网2 小时前
第 6 课:Vue 3 工程化与项目部署实战 —— 从本地开发到线上发布
大数据·运维·前端·ai
BD_Marathon2 小时前
Vue3_响应式数据的处理方式
前端·javascript·vue.js
90后的晨仔3 小时前
🛠️ 修复 macOS 预览乱码 PDF 的终极方案:用 Python 批量“图像化”拯救无法打开的 PDF
前端
嚣张丶小麦兜3 小时前
Vue常用工具库
前端·javascript·vue.js
曹牧4 小时前
C#:记录日志
服务器·前端·c#
小飞侠在吗4 小时前
Vue customRef
前端·javascript·vue.js
xhxxx4 小时前
别再让 AI 自由发挥了!用 LangChain + Zod 强制它输出合法 JSON
前端·langchain·llm
指尖跳动的光4 小时前
判断页签是否为活跃状态
前端·javascript·vue.js