Skip to content

Vite

Vite(法语中"快速"的意思,发音 /vit/)是下一代前端构建工具的全面指南。

Vite 简介

Vite 是由 Vue.js 的创建者尤雨溪(Evan You)开发的现代前端构建工具。它为现代 Web 项目提供了更快、更精简的开发体验。Vite 主要由两部分组成:

  1. 一个开发服务器,通过原生 ES 模块提供源文件,具有丰富的内置功能和极快的热模块替换(HMR)。
  2. 一个构建命令,使用 Rollup 打包代码,预配置为输出高度优化的生产静态资源。

主要特点

  • 极速冷启动:Vite 利用浏览器中的原生 ES 模块,在开发过程中避免打包。
  • 即时热模块替换(HMR):更新会立即反映在浏览器中,无需重新加载页面。
  • 真正的按需编译:只有正在编辑的模块才会被转换和更新。
  • 开箱即用支持 TypeScript、JSX、CSS 预处理器等。
  • 优化的构建:生产构建使用 Rollup 高度优化。
  • 框架无关:适用于 Vue、React、Preact、Lit、Svelte 和原生 JavaScript。
  • 插件生态系统:可通过 Rollup 兼容插件扩展。

Vite 入门

安装

您可以使用 npm、yarn 或 pnpm 创建新的 Vite 项目:

bash
# npm
npm create vite@latest my-vite-app -- --template vanilla

# yarn
yarn create vite my-vite-app --template vanilla

# pnpm
pnpm create vite my-vite-app --template vanilla

可用的模板包括:

  • vanilla:纯 JavaScript
  • vanilla-ts:TypeScript
  • vue:Vue
  • vue-ts:Vue + TypeScript
  • react:React
  • react-ts:React + TypeScript
  • preact:Preact
  • preact-ts:Preact + TypeScript
  • lit:Lit
  • lit-ts:Lit + TypeScript
  • svelte:Svelte
  • svelte-ts:Svelte + TypeScript

项目结构

典型的 Vite 项目结构如下:

my-vite-app/
├── node_modules/
├── public/             # 静态资源,将按原样提供服务
│   └── favicon.ico
├── src/                # 应用程序源代码
│   ├── assets/         # 将由 Vite 处理的资源
│   │   └── logo.png
│   ├── components/     # 应用程序组件
│   │   └── HelloWorld.vue
│   ├── App.vue         # 根组件(Vue 项目)
│   └── main.js         # 应用程序入口点
├── index.html          # HTML 入口点
├── package.json        # 项目依赖和脚本
├── vite.config.js      # Vite 配置
└── README.md           # 项目文档

开发服务器

启动开发服务器:

bash
# 导航到项目目录
cd my-vite-app

# 安装依赖
npm install

# 启动开发服务器
npm run dev

开发服务器默认将在 http://localhost:5173 启动。

核心概念

ES 模块

Vite 利用浏览器中的原生 ES 模块,这使得它能够在开发过程中无需打包即可提供源代码。这导致更快的启动时间和更高效的热模块替换。

html
<!-- index.html -->
<script type="module" src="/src/main.js"></script>
javascript
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

createApp(App).mount('#app')

热模块替换(HMR)

Vite 提供了一个 HMR API,允许模块交换和更新,而无需重新加载页面:

javascript
// 带有 HMR 支持的计数器模块
export let count = 0

export function increment() {
  count++
}

// HMR 接口
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    count = newModule.count
  })
}

静态资源处理

Vite 自动处理和优化静态资源:

javascript
// 导入资源
import imgUrl from './img.png'               // 解析为公共 URL
import svgContent from './icon.svg?raw'      // 原始内容作为字符串
import Component from './Component.vue?url'  // 获取组件的 URL

// 在模板中使用资源(Vue 示例)
<img :src="imgUrl" alt="图片">

环境变量

Vite 在特殊的 import.meta.env 对象上暴露环境变量:

javascript
console.log(import.meta.env.MODE)          // 'development' 或 'production'
console.log(import.meta.env.VITE_API_URL)  // 以 VITE_ 为前缀的自定义变量

自定义环境变量可以在 .env 文件中定义:

# .env
VITE_API_URL=https://api.example.com

配置

基本配置

Vite 通过项目根目录中的 vite.config.js 文件进行配置:

javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  },
  server: {
    port: 3000,
    open: true
  },
  build: {
    outDir: 'dist',
    minify: 'terser'
  }
})

常见配置选项

插件

插件扩展 Vite 的功能:

javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
    // 自定义插件
    {
      name: 'my-plugin',
      transform(code, id) {
        if (id.endsWith('.special')) {
          return { code: transformSpecialFile(code), map: null }
        }
      }
    }
  ]
})

开发服务器

配置开发服务器:

javascript
export default defineConfig({
  server: {
    host: '0.0.0.0',
    port: 3000,
    strictPort: true,
    https: true,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

构建选项

配置生产构建:

javascript
export default defineConfig({
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    assetsInlineLimit: 4096, // 4kb
    cssCodeSplit: true,
    sourcemap: true,
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    },
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['vue', 'vue-router'],
          utils: ['./src/utils/index.js']
        }
      }
    }
  }
})

解析

配置模块解析:

javascript
export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '~': path.resolve(__dirname, './node_modules')
    },
    extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
  }
})

模式特定配置

您可以为开发和生产指定不同的配置:

javascript
export default defineConfig(({ command, mode }) => {
  const isProduction = mode === 'production'
  
  return {
    define: {
      __APP_VERSION__: JSON.stringify('1.0.0'),
      __API_URL__: isProduction
        ? JSON.stringify('https://api.example.com')
        : JSON.stringify('http://localhost:8080')
    },
    build: {
      minify: isProduction ? 'terser' : false
    }
  }
})

高级功能

CSS 处理

Vite 内置支持 CSS 预处理:

javascript
// 导入 CSS
import './style.css'

// CSS 模块
import styles from './style.module.css'
element.className = styles.heading

// CSS 预处理器(需要安装相应的预处理器)
import './style.scss'
import './style.less'
import './style.styl'

vite.config.js 中配置 CSS:

javascript
export default defineConfig({
  css: {
    modules: {
      scopeBehaviour: 'local',
      localsConvention: 'camelCaseOnly'
    },
    preprocessorOptions: {
      scss: {
        additionalData: `@import "./src/styles/variables.scss";`
      },
      less: {
        javascriptEnabled: true
      }
    },
    postcss: {
      plugins: [autoprefixer()]
    }
  }
})

TypeScript 集成

Vite 开箱即用支持 TypeScript:

typescript
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'

interface User {
  name: string
  age: number
}

const user: User = {
  name: 'John',
  age: 30
}

console.log(user)
createApp(App).mount('#app')

vite.config.js 中配置 TypeScript:

javascript
export default defineConfig({
  esbuild: {
    target: 'es2020'
  }
})

WebAssembly

直接导入 WebAssembly 模块:

javascript
import init, { add } from './add.wasm'

init().then(() => {
  console.log(add(1, 2)) // 3
})

Web Workers

直接导入 Web Workers:

javascript
// 标准 worker
import Worker from './worker.js?worker'
const worker = new Worker()

// 共享 worker
import SharedWorker from './worker.js?sharedworker'
const sharedWorker = new SharedWorker()

// 内联 worker
import InlineWorker from './worker.js?worker&inline'

服务器端渲染(SSR)

Vite 提供对服务器端渲染的一流支持:

javascript
// vite.config.js
export default defineConfig({
  ssr: {
    // SSR 特定选项
    external: ['some-external-dependency'],
    noExternal: ['some-dependency-to-bundle']
  }
})

基本 SSR 设置:

javascript
// server.js
import fs from 'fs'
import path from 'path'
import express from 'express'
import { createServer as createViteServer } from 'vite'

async function createServer() {
  const app = express()
  
  const vite = await createViteServer({
    server: { middlewareMode: true },
    appType: 'custom'
  })
  
  app.use(vite.middlewares)
  
  app.use('*', async (req, res) => {
    const url = req.originalUrl
    
    try {
      // 读取 index.html
      let template = fs.readFileSync(
        path.resolve(process.cwd(), 'index.html'),
        'utf-8'
      )
      
      // 应用 Vite HTML 转换
      template = await vite.transformIndexHtml(url, template)
      
      // 加载服务器入口
      const { render } = await vite.ssrLoadModule('/src/entry-server.js')
      
      // 渲染应用 HTML
      const { html: appHtml, preloadLinks } = await render(url)
      
      // 将应用渲染的 HTML 注入模板
      const html = template
        .replace(`<!--preload-links-->`, preloadLinks)
        .replace(`<!--app-html-->`, appHtml)
      
      // 发送渲染的 HTML
      res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
    } catch (e) {
      vite.ssrFixStacktrace(e)
      console.error(e)
      res.status(500).end(e.message)
    }
  })
  
  app.listen(3000)
}

createServer()

使用 Vite 进行测试

使用 Vitest 进行单元测试

Vitest 是一个 Vite 原生的单元测试框架:

bash
# 安装 Vitest
npm install -D vitest

vite.config.js 中配置 Vitest:

javascript
import { defineConfig } from 'vite'

export default defineConfig({
  test: {
    globals: true,
    environment: 'jsdom',
    coverage: {
      reporter: ['text', 'json', 'html']
    }
  }
})

编写测试:

javascript
// src/utils.test.js
import { describe, it, expect } from 'vitest'
import { sum } from './utils'

describe('sum 函数', () => {
  it('正确相加两个数字', () => {
    expect(sum(1, 2)).toBe(3)
  })
  
  it('处理负数', () => {
    expect(sum(-1, -2)).toBe(-3)
  })
})

运行测试:

bash
npx vitest

组件测试

使用 Vitest 和 Vue Test Utils 测试 Vue 组件:

bash
npm install -D @vue/test-utils jsdom
javascript
// src/components/Counter.test.js
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
import Counter from './Counter.vue'

describe('Counter.vue', () => {
  it('点击按钮时增加计数', async () => {
    const wrapper = mount(Counter)
    expect(wrapper.text()).toContain('计数: 0')
    
    await wrapper.find('button').trigger('click')
    expect(wrapper.text()).toContain('计数: 1')
  })
})

端到端测试

使用 Cypress 与 Vite:

bash
npm install -D cypress

为 Vite 配置 Cypress:

javascript
// cypress.config.js
import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:5173',
    supportFile: false
  }
})

编写 E2E 测试:

javascript
// cypress/e2e/basic.cy.js
describe('基本测试', () => {
  it('访问应用根 URL', () => {
    cy.visit('/')
    cy.contains('h1', '你好 Vite')
  })
  
  it('增加计数器', () => {
    cy.visit('/')
    cy.contains('计数: 0')
    cy.get('button').contains('增加').click()
    cy.contains('计数: 1')
  })
})

部署

静态站点部署

为生产环境构建 Vite 项目:

bash
npm run build

构建输出默认将在 dist 目录中,您可以将其部署到任何静态托管服务:

  • Netlify
  • Vercel
  • GitHub Pages
  • AWS S3 + CloudFront
  • Firebase Hosting
  • Cloudflare Pages

部署到 Netlify 的示例:

bash
# 安装 Netlify CLI
npm install -g netlify-cli

# 部署到 Netlify
netlify deploy --prod --dir=dist

基础路径配置

如果您的站点部署到子目录,请配置基础路径:

javascript
// vite.config.js
export default defineConfig({
  base: '/my-app/'
})

不同环境的环境变量

创建特定环境的文件:

.env                # 在所有环境中加载
.env.local          # 在所有环境中加载,被 git 忽略
.env.development    # 在开发模式中加载
.env.production     # 在生产模式中加载

性能优化

代码分割

Vite 自动对动态导入执行代码分割:

javascript
// 异步组件加载
const UserProfile = () => import('./components/UserProfile.vue')

// 带有注释的动态导入,用于块命名
import(/* webpackChunkName: "admin" */ './admin.js')

预加载

使用 <link rel="modulepreload"> 预加载模块:

javascript
// vite.config.js
export default defineConfig({
  build: {
    modulePreload: {
      polyfill: true
    }
  }
})

资源优化

在构建过程中优化资源:

javascript
// vite.config.js
export default defineConfig({
  build: {
    assetsInlineLimit: 4096, // 4kb
    cssCodeSplit: true,
    rollupOptions: {
      output: {
        assetFileNames: 'assets/[name].[hash].[ext]'
      }
    }
  }
})

与框架的集成

Vue

bash
# 使用 Vite 创建 Vue 项目
npm create vite@latest my-vue-app -- --template vue

vite.config.js 中配置 Vue:

javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
  plugins: [
    vue({
      reactivityTransform: true
    }),
    vueJsx()
  ]
})

React

bash
# 使用 Vite 创建 React 项目
npm create vite@latest my-react-app -- --template react

vite.config.js 中配置 React:

javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react({
      // 使用 React 插件选项
      babel: {
        plugins: ['babel-plugin-macros']
      },
      jsxImportSource: '@emotion/react'
    })
  ]
})

Svelte

bash
# 使用 Vite 创建 Svelte 项目
npm create vite@latest my-svelte-app -- --template svelte

vite.config.js 中配置 Svelte:

javascript
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
  plugins: [
    svelte({
      compilerOptions: {
        dev: !process.env.PRODUCTION
      }
    })
  ]
})

最佳实践

项目结构

组织您的 Vite 项目以提高可维护性:

src/
├── assets/         # 静态资源
├── components/     # 可重用组件
├── composables/    # 组合式 API 函数(Vue)
├── hooks/          # 自定义钩子(React)
├── layouts/        # 布局组件
├── pages/          # 页面组件
├── router/         # 路由配置
├── stores/         # 状态管理
├── styles/         # 全局样式
├── utils/          # 实用函数
└── main.js         # 入口点

性能提示

  1. 使用动态导入进行代码分割:

    javascript
    const AdminPanel = () => import('./components/AdminPanel.vue')
  2. 使用 Intersection Observer 懒加载图片

    javascript
    import { useIntersectionObserver } from '@vueuse/core'
    
    const image = ref(null)
    const isVisible = ref(false)
    
    useIntersectionObserver(image, ([{ isIntersecting }]) => {
      if (isIntersecting) {
        isVisible.value = true
      }
    })
  3. 优化依赖

    bash
    # 分析包大小
    npx vite-bundle-analyzer
  4. 使用支持树摇的导入

    javascript
    // ❌ 不好 - 导入整个库
    import lodash from 'lodash'
    
    // ✅ 好 - 只导入需要的部分
    import { debounce } from 'lodash-es'

安全最佳实践

  1. 净化用户输入以防止 XSS 攻击:

    javascript
    import DOMPurify from 'dompurify'
    
    const sanitizedHTML = DOMPurify.sanitize(userInput)
  2. 使用环境变量存储敏感信息:

    javascript
    const apiKey = import.meta.env.VITE_API_KEY
  3. 在生产环境中设置适当的 CSP 头

    javascript
    // 服务器中间件
    app.use((req, res, next) => {
      res.setHeader(
        'Content-Security-Policy',
        "default-src 'self'; script-src 'self'"
      )
      next()
    })

故障排除

常见问题和解决方案

  1. HMR 不工作

    • 检查文件是否正确导入
    • 确保模块有适当的 HMR 接受代码
    • 检查语法错误
  2. 构建错误

    • 检查循环依赖
    • 验证所有导入是否正确
    • 查找 package.json 中缺少的依赖
  3. CSS 处理问题

    • 确保已安装预处理器包
    • 检查预处理器语法
    • 验证 vite.config.js 中的配置
  4. 环境变量不工作

    • 确保变量以 VITE_ 为前缀
    • 检查 .env 文件是否在项目根目录
    • 更改 .env 文件后重启开发服务器

调试提示

  1. 启用源映射

    javascript
    // vite.config.js
    export default defineConfig({
      build: {
        sourcemap: true
      }
    })
  2. 使用 Vite 的调试日志

    bash
    # 设置 DEBUG 环境变量
    DEBUG=vite:* npm run dev
  3. 在浏览器的开发者工具中检查网络请求

  4. 通过一个一个禁用插件来检查插件冲突

常见问题解答

Vite 与 webpack 相比如何?

Vite 与 webpack 在几个关键方面有所不同:

  • Vite 在开发过程中使用原生 ES 模块,而 webpack 打包所有内容
  • Vite 具有更快的启动时间和 HMR
  • Webpack 拥有更大的生态系统和更成熟的工具
  • Vite 使用 Rollup 进行生产构建,对现代代码可能更高效

我可以在现有项目中使用 Vite 吗?

是的,您可以将现有项目迁移到 Vite:

  1. 安装 Vite 和必要的插件
  2. 创建 vite.config.js 文件
  3. 更新导入语句以使用 ES 模块语法
  4. 调整 HTML 入口点
  5. 更新 package.json 中的脚本

如何处理旧版浏览器?

使用 @vitejs/plugin-legacy 插件:

javascript
// vite.config.js
import legacy from '@vitejs/plugin-legacy'

export default defineConfig({
  plugins: [
    legacy({
      targets: ['defaults', 'not IE 11']
    })
  ]
})

如何为 monorepo 配置 Vite?

对于 monorepo,您可以使用:

  • npm/yarn/pnpm 的工作区包
  • Vite 的 optimizeDeps.include 选项包含工作区依赖
  • 使用 defineConfig 和组合共享配置
javascript
// vite.config.js
export default defineConfig({
  optimizeDeps: {
    include: ['@my-org/shared-lib']
  },
  resolve: {
    preserveSymlinks: true
  }
})

相关资源


本文档将持续更新,如有问题请通过 GitHub Issues 反馈。

vitepress开发指南