自定义VITE插件,生成可修改配置项,用于不同项目部署

背景

我们做产品开发,经常遇见部署不同的项目,尤其是部署项目后后期免不了也要修改配置项,如果我们都写入环境变量中,每次都需要 前端 npm run build:XXX发版

此文章基于vite ,就是解决这个痛点的,方法如下 1:我们根据不同的项目,创建不同的打包命令,在package.json中增加不同项目的打包命令 如下

js 复制代码
"scripts": {
    "dev": "vite",
    "start": "vite --mode zhongyuan",
    "build:130": "vite build --mode 130",
    "build:182": "vite build --mode 182",
    "build:zhongyuan": "vite build --mode zhongyuan",
    "build:deyang": "vite build --mode deyang",
    "build:sjz": "vite build --mode sjz",
  },

"build:130""build:182" 等 就是不同项目的环境变量

2: 根目录创建 对应的环境变量配置文件 如 .env.130 .env.182, 如下

3: vite打包生成 setting.json,默认值就是上述的环境变量

4: 在页面初始化(我得是在axios实例中,get请求这个setting.json,修改全局配置)

为了实现上述功能需要以下步骤来实现

创建vite插件,生成 setting.json

基于你已经在package.json中增加不同项目的打包命令,也创建了不同的.env环境配置

创建 global-api.ts 用于获取全环境配置

js 复制代码
// 定义 Indexable 类型
type Indexable<T> = {
  [key: string]: T;
};

// 定义 GlobalAPI 对象
const GlobalAPI: Indexable<any> = {
  config: {}, // 用于存储环境变量
};

const devConfig: Indexable<any> = {};
for (const key in import.meta.env) {
  if (key.startsWith("VITE_")) {
    devConfig[key] = import.meta.env[key];
  }
}
GlobalAPI.config = devConfig;

export { GlobalAPI };

其他组件使用 GlobalAPI

js 复制代码
import { GlobalAPI } from "@/constants"; // 换成你得暴露地址
document.title = GlobalAPI?.config?.VITE_SYSTEM_TITLE || "政务知识助手";

创建 vite-plugin-generate-settings.js vite插件

js 复制代码
// vite-plugin-generate-settings.js
import fs from 'fs';
import path from 'path';
import { loadEnv } from 'vite';

/**
 * @param {object} options
 * @param {string} options.mode - Vite build mode
 * @param {string} options.envDir - Directory where .env files are located
 * @param {string | string[]} [options.prefixes=['VITE_']] - Prefixes to filter
 * @returns {import('vite').Plugin}
 */
function generateSettingsPlugin(options) { // 接收一个 options 对象
  const { mode, envDir, prefixes = ['VITE_'] } = options; // 解构参数

  if (!mode || !envDir) {
     // 在配置阶段就进行检查,确保必要参数已提供
     throw new Error('[Generate Settings] Missing required options: mode and envDir');
  }

  let viteConfig;
  let settings = {};

  return {
    name: 'vite-plugin-generate-settings',
    apply: 'build',

    configResolved(resolvedConfig) {
      viteConfig = resolvedConfig;
      // 使用传入的 mode 和 envDir
      const env = loadEnv(mode, envDir, '');

      settings = {};
      const VITE_PREFIXES = Array.isArray(prefixes) ? prefixes : [prefixes];

      for (const envKey in env) {
        if (VITE_PREFIXES.some(prefix => envKey.startsWith(prefix))) {
          settings[envKey] = env[envKey];
        }
      }
       console.log('\n[Generate Settings] Filtered settings:', settings);
    },

    writeBundle(options) {
       // ... (writeBundle 逻辑保持不变)
       if (!viteConfig) {
         console.error('[Generate Settings] Vite config not resolved.');
         return;
       }
       if (Object.keys(settings).length === 0) {
         console.warn('[Generate Settings] No variables starting with VITE_ found. settings.json will be empty or not generated.');
       }

      const outDir = options.dir || viteConfig.build.outDir || 'dist';
      const filePath = path.resolve(outDir, 'setting.json');

      try {
        if (!fs.existsSync(outDir)) {
          fs.mkdirSync(outDir, { recursive: true });
        }
        fs.writeFileSync(filePath, JSON.stringify(settings, null, 2));
        console.log(`\n[Generate Settings] Successfully generated setting.json at: ${filePath}`);
      } catch (error) {
        console.error(`[Generate Settings] Error writing setting.json: ${error}`);
      }
    }
  };
}

export default generateSettingsPlugin;

此插件的作用就是,获取当前的环境变量已 VITE_开头的,并且生成对用的 setting.json

vite.config.ts 引用此插件

js 复制代码
export default defineConfig(({ command, mode }) => {
  const root = process.cwd();
  return {
    plugins: [
      generateSettingsPlugin({
        mode: mode,               // 传递当前的 mode
        envDir: root,             // 显式传递 env 文件目录 (通常是项目根目录)
     })
    ],
  }
})
...你的其余配置

执行 npm run build:xxx

执行 npm run build:xxx 默认会在dist文件目录中生成, setting.json

js 复制代码
{
  "VITE_SYSTEM_TITLE1": "系统名称1",
  "VITE_SYSTEM_TITLE2": "系统名称2",
  "VITE_SYSTEM_TITLE3": "系统名称3",
  "VITE_SYSTEM_TITLE4": "系统名称4",
}

初始化的时候重新获取 setting.json更改配置 (我的是在axios中)

鉴于我们全局有请求接口,如获取用户信息的,我们在axios中,重新设置配置项

js 复制代码
class Request<R = any, D = any> {

constructor(config: InstanceRequestConfig<D, R>) {
    this.config = config;
    // 在此动态获取及配置
    if (config?.serverConfig && typeof config?.serverConfig === 'object') {
      const xhr = new XMLHttpRequest();
      // 此处注意路径
      xhr.open('get', `/setting.json`, false);
      xhr.onreadystatechange = () => {
        if (xhr.status === 200 && xhr.readyState === 4) {
          const responseJson = JSON.parse(xhr.responseText);
          Object.assign(GlobalAPI?.config, responseJson);
        }
      };
      xhr.send();
    }
    this.instance = axios.create(config);
    this.registerInterceptors();
    config.generateRequestKey &&
      (this.generateRequestKey = config.generateRequestKey);
  }

}


// 应用class

const request = new Request<Service.RequestResult>({
  timeout: 300000, // 超时五分钟
  baseURL: import.meta.env.VITE_BASE_API,
  withCredentials: false,
  // 取消重复请求
  cancelDuplicateRequest: false,
  
  // 开发环境不设置仅用默认值   生产环境设置动态设置
  serverConfig: import.meta.env.DEV ? undefined: GlobalAPI.config,
  
  })

部署成功后,修改 setting.json,此时我们动态修改一个数据,刷新页面 页面的 GlobalAPI已经生效

总结

以上是适用于多个项目部署 以及部署后有修改配置需求的, 当然你也可以不自定义插件,将 setting.json存放于服务器的任何一个目录,动态请求即可,

注意: 请求setting.json的时机,对于静态的 import 极大概率在你获取到配置项之前就生效了,有好的交换setting.json时机,也可以在评论告知下,仅供参考

相关推荐
ElasticPDF-新国产PDF编辑器8 分钟前
Vue 项目 PDF 批注插件库在线版 API 示例教程
前端·vue.js·pdf
拉不动的猪15 分钟前
react基础2
前端·javascript·面试
kovlistudio15 分钟前
红宝书第二十九讲:详解编辑器和IDE:VS Code与WebStorm
开发语言·前端·javascript·ide·学习·编辑器·webstorm
拉不动的猪17 分钟前
react基础1
前端·javascript·面试
烛阴32 分钟前
从零到RESTful API:Express路由设计速成手册
javascript·后端·express
ElasticPDF-新国产PDF编辑器1 小时前
Vue PDF Annotation plugin library online API examples
javascript·vue.js·pdf
鱼樱前端1 小时前
Vite 工程化深度解析与最佳实践
前端·javascript
鱼樱前端1 小时前
Webpack 在前端工程化中的核心应用解析-构建老大
前端·javascript
Moment1 小时前
多人协同编辑算法 —— CRDT 算法 🐂🐂🐂
前端·javascript·面试
小付同学呀1 小时前
前端快速入门学习4——CSS盒子模型、浮动、定位
前端·css·学习