Vite 配置文件 - 业务通用型配置

5 阅读11分钟

/**

  • ============================================================
  • Vite 配置文件 - 业务通用型配置
  • ============================================================
  • 【文件用途】
  • 本配置文件提供了企业级前端项目所需的完整 Vite 配置,
  • 涵盖开发服务器、构建优化、CSS处理、代码分割等多个维度。
  • 【配置结构】
    1. 基础配置 - 插件、路径别名、环境变量
    1. 开发服务器 - 端口、代理、热更新
    1. 构建配置 - 输出、压缩、分包、sourcemap
    1. CSS配置 - 预处理器、Modules、PostCSS
    1. 依赖优化 - 预构建、预热
    1. 性能优化 - Gzip压缩、图片压缩、构建分析
  • 【使用说明】
    • 默认启用 Vue 支持,如需 React 请取消注释对应插件
    • 根据实际项目需求调整代理配置和路径别名
    • 生产环境会自动启用代码压缩和 console 清除
  • 【需要安装的依赖】
  • npm install -D vite @vitejs/plugin-vue @vitejs/plugin-react
  • npm install -D sass postcss autoprefixer
  • npm install -D vite-plugin-compression rollup-plugin-visualizer
  • npm install -D vite-plugin-imagemin
  • ============================================================ */

import { defineConfig, loadEnv } from 'vite'; // 导入 Vite 核心配置函数和环境加载函数 import vue from '@vitejs/plugin-vue'; // 导入 Vue 官方插件,提供 Vue SFC 支持 // import react from '@vitejs/plugin-react'; // React 官方插件(如需 React 请取消注释) import { resolve } from 'path'; // 导入 Node.js path 模块的 resolve 方法,用于解析路径 import viteCompression from 'vite-plugin-compression'; // 导入 Gzip 压缩插件,减小传输体积 import { visualizer } from 'rollup-plugin-visualizer'; // 导入构建分析插件,可视化查看包体积

// ============================================================ // 导出 Vite 配置(使用函数形式以支持环境变量访问) // ============================================================ export default defineConfig(({ mode, command }) => {

// ---------------------------------------------------------- // 加载环境变量 // ---------------------------------------------------------- // loadEnv 函数加载指定模式下的 .env 文件环境变量 // 第三个参数 '' 表示加载所有前缀的环境变量(不限定前缀) const env = loadEnv(mode, process.cwd(), '');

// 判断当前是否为生产环境,用于条件配置 const isProduction = mode === 'production';

// 判断当前是否为开发环境 const isDevelopment = mode === 'development';

return { // ============================================================ // 一、基础配置 // ============================================================

// 项目根目录,默认为 process.cwd()
root: process.cwd(),

// 基础公共路径,用于部署到非根目录的情况
// 例如部署到 CDN 或子路径时设置为对应的 URL
base: env.VITE_BASE_URL || '/',

// ----------------------------------------------------------
// 插件配置
// ----------------------------------------------------------
plugins: [
  // Vue 插件 - 提供 Vue 单文件组件(SFC)支持
  // 包括模板编译、热更新、样式处理等功能
  vue(),
  
  // React 插件(如需 React 支持请取消下面注释)
  // react(),
  
  // Gzip 压缩插件配置 - 仅在生产环境启用
  // 作用:将静态资源压缩为 .gz 格式,减少传输体积约 70%
  isProduction && viteCompression({
    verbose: true,           // 是否在控制台输出压缩结果
    disable: false,          // 是否禁用压缩
    threshold: 10240,        // 只对超过 10KB 的文件进行压缩(单位:字节)
    algorithm: 'gzip',       // 压缩算法,可选 gzip/brotli
    ext: '.gz',              // 压缩后文件的扩展名
    deleteOriginFile: false, // 是否删除原始文件(建议保留,CDN 会自动选择)
  }),
  
  // 构建分析插件 - 生成可视化的包体积分析报告
  // 作用:帮助识别哪些模块占用了过多体积,指导优化方向
  // 使用方式:构建完成后会在根目录生成 stats.html
  isProduction && visualizer({
    open: false,             // 构建完成后是否自动打开浏览器
    gzipSize: true,          // 是否显示 Gzip 压缩后的大小
    brotliSize: true,        // 是否显示 Brotli 压缩后的大小
    filename: 'dist/stats.html', // 分析报告输出路径
  }),
  
  // 图片压缩插件示例(需要安装 vite-plugin-imagemin)
  // 作用:自动压缩项目中的图片资源,减小体积
  // 安装命令:npm install -D vite-plugin-imagemin
  /*
  isProduction && viteImagemin({
    gifsicle: { optimizationLevel: 7, interlaced: false },  // GIF 压缩配置
    optipng: { optimizationLevel: 7 },                      // PNG 压缩配置
    mozjpeg: { quality: 80 },                               // JPEG 压缩质量
    pngquant: { quality: [0.8, 0.9], speed: 4 },           // PNG 量化压缩
    svgo: {                                                  // SVG 优化配置
      plugins: [
        { name: 'removeViewBox' },
        { name: 'removeEmptyAttrs', active: false },
      ],
    },
  }),
  */
].filter(Boolean), // 过滤掉 false 值,避免生产环境插件在开发时加载

// ----------------------------------------------------------
// 路径别名配置
// ----------------------------------------------------------
resolve: {
  // alias 用于配置模块导入的别名,简化路径书写
  alias: {
    // @ 指向项目 src 目录,这是最常见的别名配置
    // 使用示例:import Component from '@/components/Component.vue'
    '@': resolve(__dirname, 'src'),
    
    // 其他常用别名示例(根据项目结构调整)
    '@components': resolve(__dirname, 'src/components'),  // 组件目录别名
    '@views': resolve(__dirname, 'src/views'),            // 页面目录别名
    '@utils': resolve(__dirname, 'src/utils'),            // 工具函数目录别名
    '@assets': resolve(__dirname, 'src/assets'),          // 静态资源目录别名
    '@api': resolve(__dirname, 'src/api'),                // API 接口目录别名
    '@stores': resolve(__dirname, 'src/stores'),          // 状态管理目录别名
    '@styles': resolve(__dirname, 'src/styles'),          // 样式文件目录别名
  },
},

// ----------------------------------------------------------
// 全局常量定义(define)
// ----------------------------------------------------------
// 定义全局常量,在代码中可以直接使用这些变量
// 这些变量会在构建时被替换为对应的值
define: {
  // 定义 __APP_VERSION__ 常量,值为 package.json 中的版本号
  // 使用方式:console.log(__APP_VERSION__)
  __APP_VERSION__: JSON.stringify(process.env.npm_package_version),
  
  // 定义 __BUILD_TIME__ 常量,记录构建时间
  // 使用方式:用于在页面底部显示版本构建时间
  __BUILD_TIME__: JSON.stringify(new Date().toISOString()),
  
  // 定义 __DEV__ 常量,标识是否为开发环境
  // 使用方式:在代码中判断 if (__DEV__) { ... }
  __DEV__: isDevelopment,
},

// ----------------------------------------------------------
// 环境变量前缀配置
// ----------------------------------------------------------
// 只有以指定前缀开头的环境变量才会暴露给客户端代码
// 这是安全考虑,防止敏感信息泄露到前端
envPrefix: 'VITE_',

// ----------------------------------------------------------
// JSON 配置
// ----------------------------------------------------------
json: {
  // 是否支持按名导入 JSON 数据
  // 开启后可以使用:import { name } from './package.json'
  namedExports: true,
  
  // 是否将 JSON 作为 ES 模块导出(true)或保持为字符串(false)
  // 设置为 true 时,JSON 会被解析为 JavaScript 对象
  stringify: false,
},

// ============================================================
// 二、开发服务器配置(仅开发环境生效)
// ============================================================
server: {
  // 服务器主机名,设置为 true 允许外部访问(局域网内其他设备可访问)
  // 设置为 '0.0.0.0' 或 true 可以让同局域网设备访问开发服务器
  host: true,
  
  // 开发服务器端口,默认 5173
  // 如果端口被占用,Vite 会自动尝试下一个可用端口
  port: 3000,
  
  // 端口被占用时是否自动尝试下一个端口
  strictPort: false,
  
  // 是否自动打开浏览器
  // 可以设置为具体的浏览器名称,如 'chrome'、'firefox'
  open: false,
  
  // 是否启用 HTTPS(需要配置证书)
  // https: {
  //   key: fs.readFileSync('./path/to/key.pem'),
  //   cert: fs.readFileSync('./path/to/cert.pem'),
  // },
  
  // ----------------------------------------------------------
  // CORS 跨域配置
  // ----------------------------------------------------------
  // 配置开发服务器的跨域资源共享策略
  cors: {
    // 允许的源,true 表示允许所有源(开发环境常用)
    origin: true,
    
    // 允许的 HTTP 方法
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
    
    // 允许的请求头
    allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
    
    // 是否允许携带凭证(cookies)
    credentials: true,
  },
  
  // ----------------------------------------------------------
  // 代理配置(解决开发环境跨域问题)
  // ----------------------------------------------------------
  // 将前端请求代理到后端服务器,避免浏览器的同源策略限制
  proxy: {
    // 示例 1:API 接口代理
    // 将所有以 /api 开头的请求代理到后端服务器
    '/api': {
      // 目标服务器地址(后端 API 服务器)
      target: env.VITE_API_BASE_URL || 'http://localhost:8080',
      
      // 是否改变请求的 origin 为 target 的 origin
      // 设置为 true 可以绕过一些基于 origin 的限制
      changeOrigin: true,
      
      // 路径重写规则,移除 /api 前缀
      // 例如:/api/users 会被代理为 http://localhost:8080/users
      rewrite: (path) => path.replace(/^\/api/, ''),
      
      // 代理请求配置(可选)
      configure: (proxy, options) => {
        // 可以在这里添加自定义的请求/响应处理逻辑
        proxy.on('proxyReq', (proxyReq, req, res) => {
          // 在请求头中添加自定义信息
          proxyReq.setHeader('X-Custom-Header', 'vite-proxy');
        });
      },
    },
    
    // 示例 2:上传服务代理
    // 专门处理文件上传相关的请求
    '/upload': {
      target: env.VITE_UPLOAD_URL || 'http://localhost:9000',
      changeOrigin: true,
      // 上传接口通常不需要重写路径
    },
    
    // 示例 3:WebSocket 代理(实时通信)
    '/ws': {
      target: env.VITE_WS_URL || 'ws://localhost:8080',
      changeOrigin: true,
      // 开启 WebSocket 支持
      ws: true,
    },
    
    // 示例 4:第三方服务代理(如地图服务、支付服务等)
    '/third-party': {
      target: 'https://api.third-party.com',
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/third-party/, ''),
      // 可以配置请求头,如添加认证信息
      headers: {
        'Authorization': `Bearer ${env.VITE_THIRD_PARTY_TOKEN}`,
      },
    },
  },
  
  // ----------------------------------------------------------
  // 文件预热配置(提升开发体验)
  // ----------------------------------------------------------
  // 在服务器启动时预先转换和缓存指定文件,减少首次请求的等待时间
  warmup: {
    // 需要预热的文件列表
    // 通常是应用入口和常用页面,可以显著加快首次加载速度
    clientFiles: [
      './src/main.js',           // 应用入口文件
      './src/App.vue',           // 根组件
      './src/views/**/*.vue',    // 所有页面组件
      './src/layouts/**/*.vue',  // 布局组件
    ],
  },
},

// ============================================================
// 三、构建配置(仅生产环境生效)
// ============================================================
build: {
  // ----------------------------------------------------------
  // 基础构建配置
  // ----------------------------------------------------------
  
  // 构建输出目录,默认 'dist'
  // 构建后的文件将输出到此目录
  outDir: 'dist',
  
  // 静态资源输出目录,相对于 outDir
  // 图片、字体等资源会输出到 dist/assets/
  assetsDir: 'assets',
  
  // 是否清空输出目录后再构建
  // 建议保持 true,避免旧文件残留
  emptyOutDir: true,
  
  // ----------------------------------------------------------
  // Sourcemap 配置
  // ----------------------------------------------------------
  // sourcemap 用于将压缩后的代码映射回原始代码,便于调试
  sourcemap: isDevelopment,  // 开发环境开启,生产环境关闭(保护源码)
  // 如需生产环境也开启(用于线上调试),可改为:sourcemap: true
  
  // ----------------------------------------------------------
  // 资源内联阈值配置
  // ----------------------------------------------------------
  // 小于此阈值的资源会被内联为 base64,减少 HTTP 请求数
  // 单位:字节(bytes),默认 4096(4KB)
  assetsInlineLimit: 4096,
  
  // ----------------------------------------------------------
  // CSS 代码分割配置
  // ----------------------------------------------------------
  // 将 CSS 从 JS 中提取出来,避免 FOUC(无样式内容闪烁)
  cssCodeSplit: true,
  
  // CSS 目标浏览器版本,用于确定需要添加哪些 CSS 前缀
  // 值越小,兼容性越好,但 CSS 体积可能越大
  cssTarget: 'chrome61',
  
  // ----------------------------------------------------------
  // Chunk 大小警告阈值
  // ----------------------------------------------------------
  // 当 chunk 超过此大小时,会在控制台发出警告
  // 单位:KB,默认 500
  chunkSizeWarningLimit: 1000,
  
  // ----------------------------------------------------------
  // 压缩配置
  // ----------------------------------------------------------
  // Vite 默认使用 esbuild 进行压缩,速度更快
  // 如需更高级的压缩(如死代码消除),可配置 terser
  minify: 'esbuild',  // 可选:'esbuild' | 'terser' | false
  
  // Terser 压缩配置(当 minify: 'terser' 时生效)
  // esbuild 压缩速度更快,但 terser 压缩率更高
  terserOptions: isProduction ? {
    compress: {
      // 是否移除 console.* 调用(生产环境建议开启)
      drop_console: true,
      // 是否移除 debugger 语句
      drop_debugger: true,
      // 是否移除 console.warn(保留 error)
      pure_funcs: ['console.log', 'console.info', 'console.warn'],
    },
    format: {
      // 是否移除注释
      comments: false,
    },
  } : {},
  
  // esbuild 压缩配置(默认使用)
  // 如需自定义 esbuild 压缩行为,可在此配置
  // esbuild: {
  //   drop: isProduction ? ['console', 'debugger'] : [],
  // },
  
  // ----------------------------------------------------------
  // Rollup 打包配置(底层使用 Rollup)
  // ----------------------------------------------------------
  rollupOptions: {
    // 入口文件配置(多页面应用时使用)
    // input: {
    //   main: resolve(__dirname, 'index.html'),
    //   admin: resolve(__dirname, 'admin.html'),
    // },
    
    // 输出配置
    output: {
      // 入口文件命名规则
      // [name] 是入口名称,[hash] 是内容哈希(用于缓存)
      entryFileNames: 'js/[name]-[hash].js',
      
      // 代码分割后的 chunk 文件命名规则
      chunkFileNames: 'js/[name]-[hash].js',
      
      // 静态资源文件命名规则
      assetFileNames: (assetInfo) => {
        // 根据资源类型分类输出到不同目录
        const info = assetInfo.name;
        // 判断是否为样式文件
        if (/\.css$/.test(info)) {
          return 'css/[name]-[hash][extname]';
        }
        // 判断是否为图片文件
        if (/\.(png|jpe?g|gif|svg|webp|ico)$/.test(info)) {
          return 'images/[name]-[hash][extname]';
        }
        // 判断是否为字体文件
        if (/\.(woff2?|eot|ttf|otf)$/.test(info)) {
          return 'fonts/[name]-[hash][extname]';
        }
        // 其他资源(如媒体文件)
        return 'assets/[name]-[hash][extname]';
      },
      
      // ----------------------------------------------------------
      // 代码分割策略(手动分块)
      // ----------------------------------------------------------
      // 作用:将代码分割成多个 chunk,实现按需加载和缓存优化
      // 原理:将不常变动的代码打包到 vendor,利用浏览器缓存
      manualChunks: (id) => {
        // id 是模块的绝对路径
        
        // 1. 将 node_modules 中的依赖打包到 vendor chunk
        // 这些依赖通常不会频繁更新,可以长期缓存
        if (id.includes('node_modules')) {
          // Vue 生态相关
          if (id.includes('vue') || id.includes('vue-router') || id.includes('pinia')) {
            return 'vendor-vue';
          }
          // UI 组件库(如 Element Plus、Ant Design 等)
          if (
            id.includes('element-plus') ||
            id.includes('ant-design') ||
            id.includes('@arco-design') ||
            id.includes('vuetify')
          ) {
            return 'vendor-ui';
          }
          // 工具库(lodash、moment、dayjs 等)
          if (
            id.includes('lodash') ||
            id.includes('moment') ||
            id.includes('dayjs') ||
            id.includes('axios')
          ) {
            return 'vendor-utils';
          }
          // 其他第三方库统一打包
          return 'vendor';
        }
        
        // 2. 将项目中的工具函数单独打包
        // 业务逻辑经常变动,但工具函数相对稳定
        if (id.includes('/src/utils/')) {
          return 'utils';
        }
        
        // 3. 将项目中的 composables/hooks 单独打包
        if (id.includes('/src/composables/') || id.includes('/src/hooks/')) {
          return 'composables';
        }
        
        // 4. 将大型页面组件单独打包(按需加载)
        // 示例:将某些大型页面单独拆分为 chunk
        if (id.includes('/src/views/large-page/')) {
          return 'large-page';
        }
        
        // 默认情况下,Rollup 会自动处理剩余代码
      },
    },
  },
  
  // 是否开启 CSS 压缩(默认开启)
  // 使用 esbuild 进行 CSS 压缩
  cssMinify: true,
  
  // 报告压缩后 chunk 的大小(默认开启)
  reportCompressedSize: true,
},

// ============================================================
// 四、CSS 配置
// ============================================================
css: {
  // ----------------------------------------------------------
  // CSS Modules 配置
  // ----------------------------------------------------------
  // CSS Modules 允许以模块化的方式使用 CSS,避免类名冲突
  modules: {
    // 生成的类名格式
    // [name] 文件名,[local] 原始类名,[hash] 哈希值
    // 开发环境使用完整类名便于调试,生产环境使用短哈希
    generateScopedName: isDevelopment
      ? '[name]__[local]___[hash:base64:5]'
      : '[hash:base64:8]',
    
    // 全局 CSS Modules 配置(对所有 CSS 文件生效)
    // scopeBehaviour: 'local', // 'local' 或 'global'
    
    // 自定义哈希字符串生成
    // hashPrefix: 'prefix',
    
    // 是否对 @import 的文件也启用 CSS Modules
    // localsConvention: 'camelCaseOnly',
  },
  
  // ----------------------------------------------------------
  // CSS 预处理器配置
  // ----------------------------------------------------------
  preprocessorOptions: {
    // SCSS/Sass 配置
    scss: {
      // 全局变量注入
      // 在每个 SCSS 文件顶部自动添加这些导入
      // 用于定义全局变量、mixins、functions
      additionalData: `
        @use "@/styles/variables.scss" as *;
        @use "@/styles/mixins.scss" as *;
      `,
      
      // 使用现代 Sass API(Dart Sass)
      api: 'modern-compiler',
      
      // 是否启用 Sass 的静默弃用警告
      silenceDeprecations: ['legacy-js-api'],
    },
    
    // Less 配置(如使用 Less)
    less: {
      // 全局变量注入
      // additionalData: `@import "@/styles/variables.less";`,
      
      // 是否启用 JavaScript 计算
      javascriptEnabled: true,
      
      // 数学计算模式
      math: 'always',
    },
    
    // Stylus 配置(如使用 Stylus)
    stylus: {
      // 全局变量注入
      // define: {
      //   '$primary-color': '#1890ff',
      // },
    },
  },
  
  // ----------------------------------------------------------
  // PostCSS 配置
  // ----------------------------------------------------------
  // PostCSS 用于转换 CSS,如添加浏览器前缀、使用未来 CSS 语法
  // Vite 会自动读取项目根目录的 postcss.config.js 或 postcss.config.cjs
  // 也可以在这里直接配置
  postcss: {
    plugins: [
      // Autoprefixer 插件 - 自动添加浏览器前缀
      // 安装命令:npm install -D autoprefixer
      // 需要在项目根目录创建 postcss.config.js 文件
    ],
  },
  
  // 是否将开发期间的 CSS 提取到单个文件(默认 false)
  // 开发时保持 false 以支持热更新
  devSourcemap: isDevelopment,
},

// ============================================================
// 五、依赖优化配置
// ============================================================
optimizeDeps: {
  // ----------------------------------------------------------
  // 强制预构建的依赖
  // ----------------------------------------------------------
  // 这些依赖会在服务器启动时进行预构建,提升页面加载速度
  // 适用于 CJS 格式的依赖或含有大量内部模块的依赖
  include: [
    // Vue 生态
    'vue',
    'vue-router',
    'pinia',
    
    // 常用工具库
    'axios',
    'dayjs',
    'lodash-es',
    
    // UI 组件库(按需引入时可能需要)
    // 'element-plus',
    // '@arco-design/web-vue',
    
    // 其他可能需要预构建的依赖
    // 当控制台提示 "dependency to pre-bundle" 时,将对应包添加到这里
  ],
  
  // ----------------------------------------------------------
  // 排除预构建的依赖
  // ----------------------------------------------------------
  // 这些依赖不会进行预构建,保持原样
  // 适用于原生 ESM 格式的依赖或需要特殊处理的依赖
  exclude: [
    // 如果某些包导致预构建问题,可以在此排除
    // 'some-problematic-package',
  ],
  
  // 是否强制重新预构建(默认 false)
  // 设置为 true 会在每次启动时重新预构建
  force: false,
  
  // 自定义 esbuild 选项用于依赖预构建
  esbuildOptions: {
    // 目标平台
    platform: 'browser',
    
    // 目标浏览器版本
    target: 'es2020',
    
    // 支持的文件格式
    loader: {
      '.js': 'jsx',
    },
  },
},

// ============================================================
// 六、预览配置(vite preview 命令)
// ============================================================
// 用于预览生产构建结果
preview: {
  // 预览服务器端口
  port: 4173,
  
  // 是否自动打开浏览器
  open: true,
  
  // 代理配置(与 server.proxy 相同)
  proxy: {
    '/api': {
      target: env.VITE_API_BASE_URL || 'http://localhost:8080',
      changeOrigin: true,
      rewrite: (path) => path.replace(/^\/api/, ''),
    },
  },
},

// ============================================================
// 七、SSR 配置(服务端渲染,可选)
// ============================================================
// 如需 SSR,取消下面的注释
/*
ssr: {
  // 指定 SSR 入口
  // entry: './src/entry-server.js',
  
  // 是否生成 SSR 清单
  // noExternal: true,
  
  // 指定哪些依赖需要外部化
  // external: ['some-package'],
},
*/

// ============================================================
// 八、Worker 配置(Web Worker)
// ============================================================
worker: {
  // Worker 打包格式
  // iife 兼容性最好,es 模块更现代
  format: 'iife',
  
  // Worker 插件(与主配置共享)
  // plugins: [],
  
  // 是否将 Worker 内联为 base64
  // inline: false,
  
  // Worker 的 rollup 选项
  // rollupOptions: {},
},

// ============================================================
// 九、日志配置
// ============================================================
logLevel: 'info',  // 可选:'info' | 'warn' | 'error' | 'silent'

// 是否清空终端屏幕(默认 true)
clearScreen: true,

// 自定义日志记录器
// customLogger: {},

// ============================================================
// 十、实验性功能(根据 Vite 版本可能变化)
// ============================================================
experimental: {
  // 启用渲染优化(Vite 4.3+)
  // renderBuiltUrl: (filename, { hostType }) => {
  //   // 自定义构建后的资源 URL
  //   return { relative: true };
  // },
},

}; });

/**

  • ============================================================
  • 配套配置文件说明
  • ============================================================
    1. postcss.config.js(与 vite.config.js 同级)
  • 作用:配置 PostCSS 插件,如 autoprefixer
  • 示例内容:
  • module.exports = {
  •  plugins: {
    
  •    autoprefixer: {},
    
  •  },
    
  • };
    1. .env / .env.development / .env.production
  • 作用:配置不同环境的环境变量
  • 示例内容:
  • VITE_API_BASE_URL=http://localhost:8080
  • VITE_APP_TITLE=My App
    1. tsconfig.json(TypeScript 项目)
  • 需要配置 paths 以支持路径别名的类型提示:
  • "compilerOptions": {
  •  "paths": {
    
  •    "@/*": ["./src/*"]
    
  •  }
    
  • }
  • ============================================================
  • 常用命令
  • ============================================================
  • 开发模式:npm run dev 或 vite
  • 生产构建:npm run build 或 vite build
  • 预览构建:npm run preview 或 vite preview
  • 构建分析:npm run build(生成 dist/stats.html)
  • ============================================================ */