FORMA

部署实践

Vite 项目的 CI/CD、多环境、CDN、Legacy 与体积预算等工程化要点。环境变量见 env;构建见 生产构建

一、CI / CD 优化

CI 环境通常需要快速、可复用的构建流程,避免不必要的重复工作。

1. 缓存 node_modules.vite 目录

  • node_modules:依赖安装结果,可通过 CI 的缓存机制保留(如 GitHub Actions actions/cache、GitLab CI cache)。
  • .vite 目录:包含依赖预构建产物(node_modules/.vite/deps)和 vite 缓存,可大幅加速启动和构建。
yaml
# GitHub Actions 示例
- name: Cache node_modules
  uses: actions/cache@v3
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}

- name: Cache Vite deps
  uses: actions/cache@v3
  with:
    path: node_modules/.vite
    key: ${{ runner.os }}-vite-${{ hashFiles('package-lock.json') }}

2. vite build 前设置 CI=true 避免交互式提示

CI 环境应设置环境变量 CI=true,防止某些插件或工具输出交互式提示。

bash
export CI=true
npm run build

3. 使用 --emptyOutDir 控制输出目录清理

构建时默认会清空输出目录(outDir),可通过 --emptyOutDir 控制是否清空。CI 中通常保持默认清空,也可显式设置为 true

bash
vite build --emptyOutDir

或在配置文件中指定:

js
build: {
  emptyOutDir: true;
}

二、多环境配置拆分

不同环境(开发、测试、预发、生产)需要不同的 API 地址、CDN 路径、调试开关等。

1. 通过 modedefine / import.meta.env 注入环境变量

使用 .env.[mode] 文件存储环境特定变量,Vite 会自动加载并以 VITE_ 前缀暴露。

text
# .env.production
VITE_API_BASE=https://api.prod.com
VITE_CDN_BASE=https://cdn.prod.com

# .env.staging
VITE_API_BASE=https://api.staging.com

在代码中使用:

js
const apiUrl = import.meta.env.VITE_API_BASE;

2. 配置 config 钩子动态修改配置(如不同环境使用不同 CDN 路径)

如果需要在构建时根据环境改变 Vite 配置(如 base 路径、rollup 选项),可以在 vite.config.js 中使用 config 钩子或直接导出函数。

js
export default ({ mode, command }) => {
  const isProd = mode === "production";
  return {
    base: isProd ? "https://cdn.example.com/" : "/",
    define: {
      __CDN_BASE__: JSON.stringify(isProd ? "https://cdn.example.com" : ""),
    },
    // 其他配置...
  };
};

也可以使用插件修改配置:

js
{
  name: 'dynamic-config',
  config(config, env) {
    if (env.mode === 'production') {
      config.base = 'https://cdn.prod.com/';
    }
  }
}

三、CDN 与资源上传

1. 使用 vite-plugin-cdn-import 自动替换外部依赖为 CDN

该插件将指定的依赖(如 vuereactaxios)替换为 CDN 链接,减少打包体积并利用浏览器缓存。

js
import { defineConfig } from "vite";
import cdnImport from "vite-plugin-cdn-import";

export default {
  plugins: [
    cdnImport({
      modules: [
        { name: "vue", var: "Vue", path: "https://unpkg.com/vue@3/dist/vue.global.js" },
        { name: "axios", var: "axios", path: "https://unpkg.com/axios/dist/axios.min.js" },
      ],
    }),
  ],
};

注意:需要确保 CDN 资源可用,并在 rollupOptions.external 中声明外部依赖。

2. 构建后通过插件(如 vite-plugin-s3)上传静态文件

dist 目录中的资源自动上传到云存储(如 AWS S3、OSS)可搭配插件完成。

js
import s3Plugin from "vite-plugin-s3";

export default {
  plugins: [
    s3Plugin({
      bucket: "my-bucket",
      region: "us-east-1",
      acl: "public-read",
      basePath: "/static",
    }),
  ],
};

也可以编写自定义插件,在 writeBundle 钩子中实现上传逻辑。

四、Legacy 浏览器支持

通过 @vitejs/plugin-legacy 可以支持较旧的浏览器(如 IE 11 或旧版 Chrome/Firefox),同时不为现代浏览器加载多余 polyfill。

1. 使用 @vitejs/plugin-legacy 生成传统 chunk 和 polyfill

该插件会根据 browserslist 配置生成现代 + legacy 两套产物,并根据用户代理动态加载。

bash
npm install -D @vitejs/plugin-legacy terser
js
// vite.config.js
import legacy from "@vitejs/plugin-legacy";

export default {
  plugins: [
    legacy({
      targets: ["defaults", "not IE 11"], // 或使用 browserslist
      additionalLegacyPolyfills: ["regenerator-runtime/runtime"],
      modernPolyfills: true,
    }),
  ],
};

2. 使用 browserslist 指定目标

package.json 中添加 browserslist 字段或单独的 .browserslistrc 文件。

json
"browserslist": [
  "> 0.5%",
  "last 2 versions",
  "not dead",
  "not ie 11"
]

3. 动态加载 legacy 产物,保证现代浏览器性能不收损

@vitejs/plugin-legacy 会在 HTML 中插入类似以下代码:

  • 通过 <script type="module"> 加载现代 build。
  • 通过 <script nomodule> 加载 legacy polyfill 和传统 build(仅在不支持 module 的浏览器执行)。

现代浏览器只加载现代 bundle,性能不受影响。

五、性能预算监控

持续监控产物体积,防止退化。

1. 集成 bundlesize 或自定义 CI 脚本

使用 bundlesize(适用于任何构建工具):

全局安装 bundlesize 并在 package.json 中配置:

json
{
  "bundlesize": [
    {
      "path": "./dist/assets/*.js",
      "maxSize": "200 kB",
      "compression": "gzip"
    },
    {
      "path": "./dist/assets/*.css",
      "maxSize": "50 kB"
    }
  ]
}

在 CI 中运行:

bash
npx bundlesize

自定义 CI 脚本: 使用 vite build --report(通过 rollup-plugin-visualizer)生成体积报告,然后用 Node 脚本读取并比较阈值。

js
// scripts/check-size.js
const fs = require("fs");
const path = require("path");
const files = fs.readdirSync("dist/assets");
let totalSize = 0;
files.forEach((file) => {
  if (file.endsWith(".js")) {
    totalSize += fs.statSync(path.join("dist/assets", file)).size;
  }
});
if (totalSize > 500 * 1024) {
  console.error(`Bundle size exceeded: ${totalSize} bytes`);
  process.exit(1);
}

2. 在 CI 中集成体积检查

  • GitHub Actions:使用 actions/upload-artifact 保存体积报告,或直接运行检查脚本。
  • GitLab CI:在 after_script 中执行大小检查,并将报告作为 artifacts。

示例 GitHub Action

yaml
- name: Build
  run: npm run build

- name: Check bundle size
  run: node scripts/check-size.js

总结

实践方向核心措施
CI/CD 优化缓存 node_modules.vite;设置 CI=true;控制输出目录清理
多环境配置使用 .env.[mode]import.meta.envconfig 钩子动态调整配置
CDN 与上传vite-plugin-cdn-import 替换依赖;插件自动上传产物至云存储
Legacy 支持@vitejs/plugin-legacy + browserslist;动态加载策略
性能预算监控bundlesize 或自定义脚本;CI 中集成体积检查并设置告警阈值

将这些实践纳入工程流程,可显著提升构建效率、产物质量及浏览器兼容性,同时长期保障应用性能不超标。

参考文献

以下链接在编写时均可正常访问:

Series

vite

4 / 6