Vite 面试题

Vite 面试题

Vite 是新一代前端构建工具,基于原生 ES Module,以极快的启动和热更新速度著称。以下涵盖核心原理、配置、插件开发等高频面试题。


1. Vite 是什么?为什么比 Webpack 快?

Vite 是由尤雨溪开发的下一代前端构建工具,它利用浏览器原生 ES Module 支持和 esbuild 预构建,实现了极快的开发服务器启动和热更新。

arduino 复制代码
Webpack 的开发流程:
  入口 → 解析依赖 → 编译所有模块 → 打包 Bundle → 启动 Dev Server
  (全部处理完才能启动,项目越大越慢)

Vite 的开发流程:
  启动 Dev Server(极快)→ 浏览器请求模块 → 按需编译返回
  (不需要打包,请求什么编译什么)

Vite vs Webpack 速度对比:

指标 Webpack Vite
冷启动 30s-60s(大项目) ~300ms
热更新(HMR) 1-5s ~50ms
依赖预构建 每次全量 esbuild 预构建(Go 编写,极快)
生产构建 webpack + terser Rollup + esbuild

Vite 快的核心原因:

javascript 复制代码
// 1. 开发环境不打包,利用浏览器原生 ES Module
// 浏览器直接请求源文件,Vite 只做按需编译和转换

// 浏览器发起请求:
// GET /src/main.tsx
// GET /src/App.tsx
// GET /src/components/Header.tsx

// Vite Dev Server 拦截请求,编译后返回:
// main.tsx → 编译 TSX → 返回 JS(保留 import 语句)
// App.tsx → 编译 TSX → 返回 JS
// 浏览器继续按 import 请求其他模块...

// 2. 依赖预构建:用 esbuild 将 node_modules 的 CommonJS/UMD 转为 ESM
// esbuild 用 Go 编写,比 JavaScript 写的打包器快 10-100 倍

// 3. HMR 基于 ESM:只需要精确地更新变化的模块
// 不像 Webpack 需要重新构建整个 chunk

💡 面试加分点: Vite 开发环境用原生 ESM + esbuild,生产环境用 Rollup 打包。原因是浏览器在生产环境加载过多 ESM 文件会有性能问题(HTTP 请求瀑布流),所以仍需要打包。


2. Vite 的核心原理?

xml 复制代码
Vite 的三个核心机制:

1. 依赖预构建(Pre-bundling)
   ├── 首次启动时,用 esbuild 扫描并预构建 node_modules 依赖
   ├── 将 CommonJS/UMD 转为 ESM 格式
   ├── 将零散的模块合并(如 lodash-es 有 600+ 个文件 → 合并为 1 个)
   └── 结果缓存到 node_modules/.vite 目录

2. 基于 ESM 的开发服务器
   ├── 浏览器通过 <script type="module"> 加载入口
   ├── 遇到 import 语句,浏览器发起 HTTP 请求
   ├── Vite Dev Server 拦截请求,按需编译
   ├── 裸模块导入重写:import 'vue' → import '/node_modules/.vite/deps/vue.js'
   └── .vue/.tsx/.less 等文件实时编译转换

3. 基于 Rollup 的生产构建
   ├── 使用 Rollup 打包(更好的 Tree Shaking)
   ├── 用 esbuild 做代码压缩(替代 terser,快 20-40 倍)
   └── 自动处理代码分割、CSS 提取等
javascript 复制代码
// 依赖预构建过程示意
// 1. Vite 启动时扫描源码中的 import
import { createApp } from 'vue'        // 裸模块导入
import axios from 'axios'               // CommonJS 包
import { debounce } from 'lodash-es'    // 有很多子模块的包

// 2. esbuild 预构建
// vue → 预构建为 ESM,缓存到 node_modules/.vite/deps/vue.js
// axios → 从 CommonJS 转为 ESM
// lodash-es → 600+ 文件合并为 1 个文件(减少 HTTP 请求)

// 3. 重写导入路径
import { createApp } from '/node_modules/.vite/deps/vue.js?v=abc123'
import axios from '/node_modules/.vite/deps/axios.js?v=abc123'
import { debounce } from '/node_modules/.vite/deps/lodash-es.js?v=abc123'

// 强缓存:依赖文件使用 max-age=31536000 强缓存
// 版本号变化时自动更新缓存

3. vite.config.ts 常用配置?

typescript 复制代码
// vite.config.ts
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import react from '@vitejs/plugin-react'
import path from 'path'

export default defineConfig(({ command, mode }) => {
  // 加载环境变量
  const env = loadEnv(mode, process.cwd(), '')

  return {
    // ===== 基础配置 =====
    base: '/',                    // 公共基础路径(CDN 部署时修改)
    root: process.cwd(),          // 项目根目录
    publicDir: 'public',          // 静态资源目录

    // ===== 插件 =====
    plugins: [
      vue(),                      // Vue 支持
      // react(),                 // React 支持
    ],

    // ===== 路径别名 =====
    resolve: {
      alias: {
        '@': path.resolve(__dirname, 'src'),
        '@components': path.resolve(__dirname, 'src/components'),
        '@utils': path.resolve(__dirname, 'src/utils')
      },
      extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
    },

    // ===== CSS 配置 =====
    css: {
      // CSS Modules
      modules: {
        localsConvention: 'camelCaseOnly'
      },
      // 预处理器选项
      preprocessorOptions: {
        scss: {
          additionalData: `@import "@/styles/variables.scss";`
        },
        less: {
          javascriptEnabled: true,
          modifyVars: { '@primary-color': '#1890ff' }
        }
      },
      // PostCSS
      postcss: {
        plugins: [
          require('autoprefixer')(),
          require('tailwindcss')()
        ]
      }
    },

    // ===== 开发服务器 =====
    server: {
      host: '0.0.0.0',
      port: 3000,
      open: true,
      cors: true,
      // 代理配置
      proxy: {
        '/api': {
          target: 'http://localhost:8080',
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, '')
        }
      }
    },

    // ===== 构建配置 =====
    build: {
      target: 'es2020',           // 构建目标
      outDir: 'dist',             // 输出目录
      assetsDir: 'assets',        // 静态资源目录
      assetsInlineLimit: 4096,    // 小于 4KB 的资源内联为 base64
      sourcemap: false,           // 生产环境不生成 sourcemap
      minify: 'esbuild',         // 压缩方式:'esbuild' | 'terser' | false
      cssMinify: true,

      // Rollup 配置
      rollupOptions: {
        output: {
          // 代码分割
          manualChunks: {
            'react-vendor': ['react', 'react-dom'],
            'vue-vendor': ['vue', 'vue-router', 'pinia'],
            'lodash': ['lodash-es']
          },
          // 文件命名
          chunkFileNames: 'js/[name]-[hash].js',
          entryFileNames: 'js/[name]-[hash].js',
          assetFileNames: '[ext]/[name]-[hash].[ext]'
        }
      },

      // chunk 大小警告阈值
      chunkSizeWarningLimit: 500
    },

    // ===== 依赖预构建 =====
    optimizeDeps: {
      include: ['axios', 'dayjs'],    // 强制预构建
      exclude: ['@vueuse/core'],       // 排除预构建
      esbuildOptions: {
        target: 'es2020'
      }
    },

    // ===== 环境变量 =====
    // .env 文件中 VITE_ 开头的变量会暴露给客户端
    define: {
      __APP_VERSION__: JSON.stringify('1.0.0')
    }
  }
})

4. Vite 的 HMR(热更新)原理?

markdown 复制代码
Vite HMR 流程:

1. 文件变化 → Vite 监听文件系统(chokidar)
2. 找到变化文件对应的模块及其依赖关系
3. 通过 WebSocket 通知浏览器
4. 浏览器重新请求变化的模块(带时间戳参数避免缓存)
5. 替换旧模块,触发更新回调
typescript 复制代码
// Vite HMR API
if (import.meta.hot) {
  // 1. 接受自身更新
  import.meta.hot.accept((newModule) => {
    // newModule 是更新后的模块
    console.log('模块已更新', newModule)
  })

  // 2. 接受依赖更新
  import.meta.hot.accept('./module.ts', (newModule) => {
    // 当 ./module.ts 更新时触发
  })

  // 3. 清理副作用
  import.meta.hot.dispose((data) => {
    // 模块被替换前执行
    clearInterval(timer)
    data.savedState = currentState  // 传递状态给新模块
  })

  // 4. 精确失效(强制刷新)
  import.meta.hot.invalidate()

  // 5. 自定义事件
  import.meta.hot.on('custom-event', (data) => {
    console.log('收到自定义事件', data)
  })
}

// Vue/React 框架的 HMR 是自动的:
// - Vue:@vitejs/plugin-vue 自动处理组件 HMR
// - React:@vitejs/plugin-react 使用 React Fast Refresh
// 开发者通常不需要手动写 HMR 代码

Vite HMR vs Webpack HMR:

对比 Webpack HMR Vite HMR
更新粒度 整个 chunk 重新编译 只编译变化的文件
速度 与项目大小成正比(越大越慢) 恒定快速(与项目大小无关)
实现方式 重新打包 → 推送 ESM 重新请求变化的模块
CSS 更新 style-loader 注入 直接替换 <style> 标签

5. Vite 的环境变量和模式?

bash 复制代码
# .env                  # 所有模式共享
VITE_APP_TITLE=我的应用

# .env.development      # 开发模式
VITE_API_BASE=http://localhost:8080
VITE_DEBUG=true

# .env.production       # 生产模式
VITE_API_BASE=https://api.example.com
VITE_DEBUG=false

# .env.staging          # 自定义模式
VITE_API_BASE=https://staging-api.example.com
typescript 复制代码
// 使用环境变量(只有 VITE_ 开头的才会暴露给客户端)
console.log(import.meta.env.VITE_API_BASE)    // ✅
console.log(import.meta.env.VITE_APP_TITLE)   // ✅
console.log(import.meta.env.MODE)              // 'development' | 'production'
console.log(import.meta.env.DEV)               // true(开发模式)
console.log(import.meta.env.PROD)              // true(生产模式)
console.log(import.meta.env.BASE_URL)          // base 配置值

// TypeScript 类型声明
// env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
  readonly VITE_API_BASE: string
  readonly VITE_APP_TITLE: string
  readonly VITE_DEBUG: string
}
interface ImportMeta {
  readonly env: ImportMetaEnv
}

// 命令行指定模式
// vite --mode staging        → 加载 .env.staging
// vite build --mode staging  → 生产构建使用 staging 环境变量

// 在 vite.config.ts 中使用环境变量
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '')
  return {
    define: {
      __API_BASE__: JSON.stringify(env.VITE_API_BASE)
    }
  }
})

6. Vite 插件机制和常用插件?

typescript 复制代码
// Vite 插件兼容 Rollup 插件接口,同时扩展了 Vite 特有的钩子

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import react from '@vitejs/plugin-react'
import legacy from '@vitejs/plugin-legacy'
import { visualizer } from 'rollup-plugin-visualizer'
import { compression } from 'vite-plugin-compression2'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Icons from 'unplugin-icons/vite'
import Inspect from 'vite-plugin-inspect'

export default defineConfig({
  plugins: [
    // 1. 框架支持
    vue(),
    vueJsx(),
    // react(),

    // 2. 浏览器兼容(生成传统浏览器 polyfill)
    legacy({
      targets: ['> 1%', 'last 2 versions', 'not dead'],
      additionalLegacyPolyfills: ['regenerator-runtime/runtime']
    }),

    // 3. 自动导入 API(不需要手动 import ref, computed 等)
    AutoImport({
      imports: ['vue', 'vue-router', 'pinia'],
      resolvers: [ElementPlusResolver()],
      dts: 'src/auto-imports.d.ts'
    }),

    // 4. 组件自动注册
    Components({
      resolvers: [ElementPlusResolver()],
      dts: 'src/components.d.ts'
    }),

    // 5. 图标按需加载
    Icons({ autoInstall: true }),

    // 6. Gzip 压缩
    compression({ algorithm: 'gzip', threshold: 10240 }),

    // 7. 包体积分析
    visualizer({
      open: true,
      filename: 'stats.html',
      gzipSize: true
    }),

    // 8. 调试工具(查看插件转换中间结果)
    Inspect()
  ]
})

7. 如何手写一个 Vite 插件?

typescript 复制代码
// Vite 插件是一个返回对象的函数,对象包含插件名和各种钩子

import type { Plugin, ResolvedConfig } from 'vite'

// ========== 示例1:自动添加版本号 ==========
function vitePluginVersion(version: string): Plugin {
  return {
    name: 'vite-plugin-version',  // 必须:插件名称
    enforce: 'pre',               // 可选:'pre' | 'post'(执行顺序)

    // 解析配置后调用
    configResolved(config) {
      console.log(`当前模式: ${config.mode}`)
    },

    // 转换 HTML
    transformIndexHtml(html) {
      return html.replace(
        '</head>',
        `<meta name="version" content="${version}">\n</head>`
      )
    }
  }
}

// ========== 示例2:虚拟模块 ==========
function vitePluginVirtualModule(): Plugin {
  const virtualModuleId = 'virtual:my-module'
  const resolvedVirtualModuleId = '\0' + virtualModuleId

  return {
    name: 'vite-plugin-virtual-module',

    resolveId(id) {
      if (id === virtualModuleId) {
        return resolvedVirtualModuleId
      }
    },

    load(id) {
      if (id === resolvedVirtualModuleId) {
        return `
          export const buildTime = '${new Date().toISOString()}'
          export const env = '${process.env.NODE_ENV}'
        `
      }
    }
  }
}

// 使用虚拟模块
// import { buildTime, env } from 'virtual:my-module'

// ========== 示例3:自动生成路由 ==========
function vitePluginAutoRoutes(): Plugin {
  return {
    name: 'vite-plugin-auto-routes',

    // 开发服务器配置钩子
    configureServer(server) {
      // 监听文件变化
      server.watcher.on('add', (filePath) => {
        if (filePath.includes('src/pages/') && filePath.endsWith('.vue')) {
          console.log('新页面文件:', filePath)
          // 触发 HMR 更新
          const mod = server.moduleGraph.getModulesByFile(filePath)
          if (mod) {
            server.ws.send({ type: 'full-reload' })
          }
        }
      })
    },

    // 代码转换钩子
    transform(code, id) {
      if (id.endsWith('.vue')) {
        // 可以在这里修改 Vue SFC 的代码
        return code
      }
    }
  }
}

// ========== 示例4:API Mock 插件 ==========
function vitePluginMock(): Plugin {
  return {
    name: 'vite-plugin-mock',
    apply: 'serve',  // 只在开发环境生效

    configureServer(server) {
      server.middlewares.use('/api/users', (req, res) => {
        res.setHeader('Content-Type', 'application/json')
        res.end(JSON.stringify([
          { id: 1, name: '张三' },
          { id: 2, name: '李四' }
        ]))
      })
    }
  }
}

// 使用插件
export default defineConfig({
  plugins: [
    vitePluginVersion('1.0.0'),
    vitePluginVirtualModule(),
    vitePluginAutoRoutes(),
    vitePluginMock()
  ]
})

Vite 插件钩子执行顺序:

lua 复制代码
config → configResolved → configureServer → buildStart
→ resolveId → load → transform → buildEnd → closeBundle

💡 面试加分点: Vite 插件和 Rollup 插件的区别------Vite 额外提供了 configconfigResolvedconfigureServertransformIndexHtmlhandleHotUpdate 等钩子。enforce: 'pre' 的插件先执行,enforce: 'post' 的后执行。


8. Vite 的 CSS 处理方式?

typescript 复制代码
// Vite 内置了对 CSS 的处理,无需额外配置

// ========== 1. 原生 CSS 导入 ==========
import './styles.css'  // 自动注入到页面

// ========== 2. CSS Modules ==========
// 文件名以 .module.css 结尾即可
import styles from './Button.module.css'
// styles.button → 生成唯一类名如 _button_1a2b3_1

// ========== 3. CSS 预处理器(自动支持,只需安装依赖)==========
// npm install -D sass
import './styles.scss'

// npm install -D less
import './styles.less'

// npm install -D stylus
import './styles.styl'

// ========== 4. PostCSS ==========
// 自动读取 postcss.config.js
// postcss.config.js
module.exports = {
  plugins: [
    require('autoprefixer'),
    require('tailwindcss'),
    require('postcss-nesting')
  ]
}

// ========== 5. CSS 代码分割 ==========
// 异步导入的模块中的 CSS 会自动生成独立的 CSS chunk
const LazyComponent = () => import('./LazyComponent.vue')
// LazyComponent 的 CSS 会被单独提取

// ========== 6. Tailwind CSS 集成 ==========
// vite.config.ts
export default defineConfig({
  css: {
    postcss: {
      plugins: [
        require('tailwindcss'),
        require('autoprefixer')
      ]
    }
  }
})

// ========== 7. CSS-in-JS ==========
// Vite 原生支持 @emotion/react、styled-components 等
// 配合 @vitejs/plugin-react 的 babel 配置

9. Vite 的 SSR(服务端渲染)支持?

typescript 复制代码
// Vite 内置了 SSR 支持,提供了 ssrLoadModule 等 API

// server.js(Node.js 服务端)
import express from 'express'
import { createServer as createViteServer } from 'vite'

async function createServer() {
  const app = express()

  // 创建 Vite 开发服务器
  const vite = await createViteServer({
    server: { middlewareMode: true },
    appType: 'custom'
  })
  app.use(vite.middlewares)

  app.get('*', async (req, res) => {
    const url = req.originalUrl

    try {
      // 1. 读取 HTML 模板
      let template = await vite.transformIndexHtml(url,
        `<!DOCTYPE html>
         <html>
           <head><title>SSR</title></head>
           <body>
             <div id="app"><!--ssr-outlet--></div>
             <script type="module" src="/src/entry-client.ts"></script>
           </body>
         </html>`)

      // 2. 加载服务端入口模块
      const { render } = await vite.ssrLoadModule('/src/entry-server.ts')

      // 3. 渲染应用,获取 HTML
      const appHtml = await render(url)

      // 4. 替换占位符
      const html = template.replace('<!--ssr-outlet-->', appHtml)

      res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
    } catch (e) {
      vite.ssrFixStacktrace(e as Error)
      res.status(500).end((e as Error).message)
    }
  })

  app.listen(3000, () => console.log('http://localhost:3000'))
}
createServer()

// entry-server.ts(服务端入口)
import { createApp } from './app'
import { renderToString } from 'vue/server-renderer'

export async function render(url: string) {
  const { app, router } = createApp()
  await router.push(url)
  await router.isReady()
  return await renderToString(app)
}

// entry-client.ts(客户端入口)
import { createApp } from './app'
const { app, router } = createApp()
router.isReady().then(() => app.mount('#app'))

💡 面试加分点: 实际项目中更推荐使用 Nuxt3(Vue)或 Next.js(React)等 SSR 框架,它们基于 Vite/Webpack 封装了完整的 SSR 能力。Vite 的 SSR 支持更偏底层。


10. Vite vs Webpack 全面对比?

对比维度 Vite Webpack
开发启动速度 毫秒级(不打包) 秒级-分钟级(需打包)
HMR 速度 ~50ms(精确更新) 秒级(chunk 重编译)
生产构建 Rollup Webpack
配置复杂度 简单(约定优于配置) 复杂(需要大量配置)
生态系统 较新但快速增长 最成熟、最丰富
插件 Rollup 兼容 + Vite 扩展 独立的 Plugin 体系
CSS 处理 内置 需要 loader 配置
TypeScript 内置(esbuild 编译) 需要 ts-loader/babel
JSON 导入 内置 需要配置
静态资源 内置 需要 loader 配置
Module Federation 需要社区插件 原生支持
代码分割 Rollup 自动分割 SplitChunksPlugin
旧浏览器兼容 @vitejs/plugin-legacy babel-loader
适用场景 新项目(强烈推荐) 老项目、复杂定制需求
javascript 复制代码
// Vite 开箱即用 vs Webpack 需要配置

// ===== Vite 零配置即可启动 =====
// npm create vite@latest my-app -- --template vue-ts
// cd my-app && npm install && npm run dev
// 就这样!不需要任何额外配置

// ===== Webpack 需要手动配置 =====
// 需要安装和配置:
// webpack, webpack-cli, webpack-dev-server,
// babel-loader, @babel/core, @babel/preset-env,
// css-loader, style-loader, html-webpack-plugin,
// ts-loader 或 @babel/preset-typescript...

11. Vite 的依赖预构建机制详解?

typescript 复制代码
// 预构建的三个目的:
// 1. CommonJS/UMD → ESM(浏览器只能加载 ESM)
// 2. 合并小模块(减少 HTTP 请求)
// 3. 缓存(加速后续启动)

// vite.config.ts 预构建配置
export default defineConfig({
  optimizeDeps: {
    // 强制预构建这些依赖(即使 Vite 没有自动发现)
    include: [
      'axios',
      'dayjs',
      'lodash-es',
      // 深层导入也可以
      'vue > @vue/compiler-sfc'
    ],

    // 排除预构建(如已经是 ESM 的包)
    exclude: ['@vueuse/core'],

    // esbuild 配置
    esbuildOptions: {
      target: 'es2020',
      plugins: [/* 自定义 esbuild 插件 */]
    }
  }
})

// 预构建缓存位置:node_modules/.vite/deps/
// 缓存失效条件:
// 1. package.json 的 dependencies 变化
// 2. lockfile(package-lock.json 等)变化
// 3. vite.config.ts 中相关配置变化

// 手动清除缓存:
// npx vite --force      // 强制重新预构建
// 或删除 node_modules/.vite 目录

12. Vite 的多页面应用(MPA)配置?

typescript 复制代码
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path'

export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        // 多个入口
        main: resolve(__dirname, 'index.html'),
        admin: resolve(__dirname, 'admin/index.html'),
        login: resolve(__dirname, 'login/index.html')
      }
    }
  }
})

// 项目结构:
// ├── index.html           → /
// ├── admin/
// │   └── index.html       → /admin/
// ├── login/
// │   └── index.html       → /login/
// └── src/
//     ├── main/
//     │   └── main.ts
//     ├── admin/
//     │   └── main.ts
//     └── login/
//         └── main.ts

13. Vite 如何处理静态资源?

typescript 复制代码
// ========== 1. 导入资源获取 URL ==========
import imgUrl from './img.png'       // 获取解析后的 URL
document.getElementById('hero-img').src = imgUrl

// ========== 2. 导入为字符串 ==========
import text from './shader.glsl?raw'  // 获取文件原始内容

// ========== 3. 导入为 Worker ==========
import Worker from './worker?worker'
const worker = new Worker()

// ========== 4. 特殊后缀 ==========
import svgUrl from './icon.svg?url'        // 强制作为 URL
import svgRaw from './icon.svg?raw'        // 强制作为字符串
import svgComponent from './icon.svg?component'  // 作为 Vue 组件(需插件)

// ========== 5. public 目录 ==========
// public/ 下的文件不会被处理,直接复制到 dist 根目录
// 引用方式:使用绝对路径
// <img src="/favicon.ico" />

// ========== 6. 动态导入 ==========
// Glob 导入(批量导入)
const modules = import.meta.glob('./modules/*.ts')
// 等同于:
// {
//   './modules/a.ts': () => import('./modules/a.ts'),
//   './modules/b.ts': () => import('./modules/b.ts'),
// }

// 即时加载(非懒加载)
const modules = import.meta.glob('./modules/*.ts', { eager: true })

// 导入为字符串
const htmls = import.meta.glob('./*.html', { query: '?raw', import: 'default' })

// ========== 7. JSON 导入 ==========
import json from './data.json'               // 整个 JSON
import { name, version } from './package.json'  // 具名导入(Tree Shaking)

💡 面试加分点: import.meta.glob 是 Vite 独有的功能,它在构建时会被转换为动态 import() 调用,非常适合用于自动加载路由、Store 模块等场景。


14. Vite 在大型项目中的最佳实践?

typescript 复制代码
// ========== 1. 合理的代码分割策略 ==========
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          // 将 node_modules 中的大型依赖单独拆分
          if (id.includes('node_modules')) {
            if (id.includes('vue') || id.includes('@vue')) return 'vue-vendor'
            if (id.includes('element-plus')) return 'element-plus'
            if (id.includes('echarts')) return 'echarts'
            if (id.includes('lodash')) return 'lodash'
            return 'vendor'  // 其他第三方库
          }
        }
      }
    }
  }
})

// ========== 2. 按需导入 UI 组件库 ==========
// 使用 unplugin-vue-components 自动按需导入
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  plugins: [
    Components({
      resolvers: [ElementPlusResolver()]
    })
  ]
})

// ========== 3. 构建分析 ==========
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true
    })
  ]
})

// ========== 4. 预加载策略 ==========
// Vite 会自动为入口 chunk 的直接导入生成 <link rel="modulepreload">
// 自定义预加载
export default defineConfig({
  build: {
    modulePreload: {
      polyfill: true  // 为不支持 modulepreload 的浏览器添加 polyfill
    }
  }
})

// ========== 5. Worker 处理 ==========
// 将 CPU 密集型任务移到 Worker
const worker = new Worker(
  new URL('./heavy-task.worker.ts', import.meta.url),
  { type: 'module' }
)

// ========== 6. 合理使用 define 替代运行时判断 ==========
export default defineConfig({
  define: {
    __DEV__: JSON.stringify(process.env.NODE_ENV !== 'production')
  }
})
// 代码中的 if (__DEV__) {} 在生产构建时会被 Tree Shaking 移除

15. Vite 5 / Vite 6 有哪些新特性?

typescript 复制代码
// ========== Vite 5 新特性 ==========
// 1. Rollup 4(比 Rollup 3 快 2 倍)
// 2. 弃用 CJS Node API(完全拥抱 ESM)
// 3. 运行时 API 优化
// 4. 改进的 define 处理
// 5. 更好的 SSR 外部化

// vite.config.ts 必须使用 ESM 格式
// "type": "module" 或使用 .mts 扩展名

// ========== Vite 6 新特性 ==========
// 1. Environment API(多环境支持)
// 同时处理客户端、SSR、RSC 等不同运行环境
export default defineConfig({
  environments: {
    client: {
      build: { outDir: 'dist/client' }
    },
    ssr: {
      build: { outDir: 'dist/server' }
    }
  }
})

// 2. 更好的 CSS 支持
// 改进的 CSS 预处理器性能

// 3. 实验性 Oxc 集成
// 使用 Oxc(Rust 编写)替代部分 esbuild 工作

// 4. JSON 的 Tree Shaking 更完善
import { version } from './package.json'  // 只包含 version 字段

// 5. 改进的预构建
// 更智能的依赖发现,减少不必要的预构建

💡 面试加分点: Vite 的未来方向------Rolldown(Rust 写的 Rollup 替代品,由 Vite 团队开发)将用于替代 esbuild + Rollup 的双引擎架构,实现开发和生产使用同一个打包器,彻底解决开发/生产行为不一致的问题。

相关推荐
再吃一根胡萝卜4 小时前
08 · 前端:Vue3 + SSE 流式与执行链路可视化
面试
再吃一根胡萝卜4 小时前
03 · 后端:FastAPI 与分层架构
面试
mldong6 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排6 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60617 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角8 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!8 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰8 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
Interview Aid1129 小时前
Walmart Global Tech SDE 三轮面经|基础、并发、压力面
面试·职场和发展
mayaairi10 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js