vite打包构建时环境变量(env)生成可配置的js文件

news2024/12/28 11:57:59

现实需求

在vite开发过程中,一些变量可以放在.env(基础公共部分变量).env.dev(开发环境)、.env.production(生产环境)中管理,通常分成开发和生产两个不同的配置文件管理,方便调试和部署。但是在应用部署在若干个不同的运行环境,则需要修改.env.production中的部分变量(如api地址)重新打包会比较麻烦。

怎么样实现不重新打包的前提下修改配置呢?

答:在build打包时将.env.production和.env文件统一打包成额外的配置js文件,在通过外部挂载的方式做成全局变量即可。

文件结构如下:

1、构建脚本的文件夹结构

在这里插入图片描述

程序内部调用的文件结构

在这里插入图片描述
前提条件
.env文件

VITE_GLOB_APP_TITLE=测试平台
VITE_BASE_URL=/newpath/
VITE_GLOB_APP_SHORT_NAME=GIS_APP

.env.production文件

VITE_API_BASE_URL=/
VITE_LOGIN_API_URL=https://www.baidu.com/login

一、新建打包脚本(build.ts及依赖文件)

脚本目的是在打包目录下生成_app.config.js,效果如下:
在这里插入图片描述
_app.config.js结构如下:

window.__PRODUCTION__APP__CONF__ = {
	"VITE_GLOB_APP_TITLE": "测试平台",
    "VITE_BASE_URL":"/newpath/",
	"VITE_GLOB_APP_SHORT_NAME": "APP",
    "VITE_API_BASE_URL":"/",
	"VITE_LOGIN_API_URL": "https://www.baidu.com/login"
};
Object.freeze(window.__PRODUCTION__APP__CONF__);
Object.defineProperty(window, "__PRODUCTION__APP__CONF__", {
	configurable: false,
	writable: false,
});
1、build.ts
import { runBuildConfig } from "./buildConf"
import pkg from "../../package.json"

export const runBuild = async () => {
  try {
    const argvList = process.argv.splice(2)

    if (!argvList.includes("disabled-config")) {
      runBuildConfig()
    }

    console.log(`[${pkg.name}] - 构建成功!`)
  } catch (error) {
    console.log("虚拟构建错误:\n" + error)
    process.exit(1)
  }
}
runBuild()

2、buildConf.ts文件
/**
 * 用于打包时生成额外的配置文件。该文件可以配置一些全局变量,这样就可以直接在外部修改,而无需重新打包
 */
import fs, { writeFileSync } from "fs-extra"
import { getEnvConfig, getRootPath } from "../utils"
import { getConfigFileName } from "../getConfigFileName"
import pkg from "../../package.json"

// 打包脚本的名称
const GLOB_CONFIG_FILE_NAME = "_app.config.js"
// 输出文件的根目录
const OUTPUT_DIR = "dist"

interface CreateConfigParams {
  configName: string;
  config: any;
  configFileName?: string;
}

function createConfig(params: CreateConfigParams) {
  const { configName, config, configFileName } = params
  try {
    const windowConf = `window.${configName}`
   
    // 确保变量不会被修改
    const configStr = `${windowConf}=${JSON.stringify(config)};
      Object.freeze(${windowConf});
      Object.defineProperty(window, "${configName}", {
        configurable: false,
        writable: false,
      });
    `.replace(/\s/g, "")
    
    // 拼接新的输出根目录地址
    const filePath = `${OUTPUT_DIR}${config.VITE_BASE_URL || "/"}`

    // 创建根目录
    fs.mkdirp(getRootPath(filePath))
    writeFileSync(getRootPath(filePath + configFileName), configStr)
    
    console.log(`✨ [${pkg.name}]` + ` - 配置文件构建成功:`)
    console.log(filePath + "\n")
  } catch (error) {
    console.log("配置文件配置文件打包失败:\n" + error)
  }
}

export function runBuildConfig() {
  const config = getEnvConfig()
  const configFileName = getConfigFileName(config)
  createConfig({ config, configName: configFileName, configFileName: GLOB_CONFIG_FILE_NAME })
}
3、getConfigFileName.ts文件
/**
 * 获取配置文件变量名
 * @param env
 */
export const getConfigFileName = (env: Record<string, any>) => {
  return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || "__APP"}__CONF__`
    .toUpperCase()
    .replace(/\s/g, "")
}
4、utils.ts文件
import fs from "fs"
import path from "path"
import dotenv from "dotenv"

export function isDevFn(mode: string): boolean {
  return mode === "development"
}

export function isProdFn(mode: string): boolean {
  return mode === "production"
}

/**
 * 是否生成包预览
 */
export function isReportMode(): boolean {
  return process.env.REPORT === "true"
}

/**
 * 读取所有环境变量配置文件到process.env
 * @param envConf
 * @returns
 */
export function wrapperEnv(envConf: any) {
  const ret: any = {}

  for (const envName of Object.keys(envConf)) {
    let realName = envConf[envName].replace(/\\n/g, "\n")
    realName = realName === "true" ? true : realName === "false" ? false : realName

    if (envName === "VITE_PORT") {
      realName = Number(realName)
    }
    if (envName === "VITE_PROXY" && realName) {
      try {
        realName = JSON.parse(realName.replace(/'/g, '"'))
      } catch (error) {
        realName = ""
      }
    }
    ret[envName] = realName
    if (typeof realName === "string") {
      process.env[envName] = realName
    } else if (typeof realName === "object") {
      process.env[envName] = JSON.stringify(realName)
    }
  }
  return ret
}

/**
 * 获取当前环境下生效的配置文件名
 */
function getConfFiles() {
  const script = process.env.npm_lifecycle_script
  // eslint-disable-next-line prefer-regex-literals
  const reg = new RegExp("--mode ([a-z_\\d]+)")
  const result = reg.exec(script as string) as any
  if (result) {
    const mode = result[1] as string
    return [".env", `.env.${mode}`]
  }
  return [".env", ".env.production"]
}

/**
 * 获取以指定前缀开头的环境变量
 * @param match prefix
 * @param confFiles ext
 */
export function getEnvConfig(match = "VITE_", confFiles = getConfFiles()) {
  let envConfig = {}
  confFiles.forEach((item) => {
    try {
      const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)))
      envConfig = { ...envConfig, ...env }
    } catch (e) {
      console.error(`解析错误:${item}`, e)
    }
  })
  const reg = new RegExp(`^(${match})`)
  Object.keys(envConfig).forEach((key) => {
    if (!reg.test(key)) {
      Reflect.deleteProperty(envConfig, key)
    }
  })
  return envConfig
}

/**
 * 获取用户根目录
 * @param dir file path
 */
export function getRootPath(...dir: string[]) {
  return path.resolve(process.cwd(), ...dir)
}

二、修改vite.config.ts文件

脚本目的是将生成_app.config.js在index.html文件中添加引用,效果如下:
在这里插入图片描述

1、安装 vite-plugin-html
yarn add vite-plugin-html -D 

npm i vite-plugin-html -D
2、vite.config.ts中引用createHtmlPlugin和package.json,并添加createHtmlPlugin
import createHtmlPlugin from "vite-plugin-html"
import pkg from "./package.json"

在这里插入图片描述

  const getAppConfigSrc = () => {
    return `${ENV.VITE_BASE_URL || "/"}${GLOB_CONFIG_FILE_NAME}?v=${pkg.version}-${new Date().getTime()}`
  }

      createHtmlPlugin({
        minify: isBuild,
        inject: {
          data: {
            title: ""
          },
          // Embed the generated app.config.js file
          tags: isBuild
            ? [
              {
                tag: "script",
                attrs: {
                  src: getAppConfigSrc()
                }
              }
            ]
            : []
        }
      })

三、代码内部引用

1、env.ts文件
import { getConfigFileName } from "../../../build/getConfigFileName"
import pkg from "../../../package.json"

export function getCommonStoragePrefix() {
  const { VITE_GLOB_APP_SHORT_NAME } = getAppEnvConfig()
  return `${VITE_GLOB_APP_SHORT_NAME}__${getEnv()}`.toUpperCase()
}

/**
 * 根据版本生成缓存键
 * @returns
 */
export function getStorageShortName() {
  return `${getCommonStoragePrefix()}${`__${pkg.version}`}__`.toUpperCase()
}

export function getAppEnvConfig() {
  const ENV_NAME = getConfigFileName(import.meta.env)
  // 根据当前运行状态判断取值,如果是开发环境取.env.dev配置,如果是生产环境取_app.config.js引用的全局变量 
  const ENV = (import.meta.env.DEV ? (import.meta.env as unknown as any) : window[ENV_NAME as any]) as unknown as any
 
  // 此处可以进行过滤判断根据业务需求处理,示例未做任何处理
  const { VITE_GLOB_APP_SHORT_NAME } = ENV
  if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) {
    console.log(`VITE_GLOB_APP_SHORT_NAME变量只能是字符/下划线,请在环境变量中修改后重新运行。`)
  }

  return ENV
}

/**
 * @description: Development mode
 */
export const devMode = "development"

/**
 * @description: Production mode
 */
export const prodMode = "production"

/**
 * @description: Get environment variables
 * @returns:
 * @example:
 */
export function getEnv(): string {
  return import.meta.env.MODE
}

/**
 * @description: Is it a development mode
 * @returns:
 * @example:
 */
export function isDevMode(): boolean {
  return import.meta.env.DEV
}

/**
 * @description: Is it a production mode
 * @returns:
 * @example:
 */
export function isProdMode(): boolean {
  return import.meta.env.PROD
}

2、业务调用index.ts文件
import { getAppEnvConfig } from "@mars/hooks/setting/env"

export const useGlobSetting = (): Readonly<any> => {
  const setting = getAppEnvConfig()
  return setting
}

四、修改package.json文件build命令

1、安装cross-env和esno
yarn add cross-env -D
yarn add esno -D 

npm i cross-env -D
npm i esno -D
1、修改build命令,增加"&& esno ./build/script/postBuild.ts"
"build": "cross-env npm run lint && vite build && esno ./build/script/postBuild.ts",

五、测试命令

在命令行执行下面的语句可以测试生成_app.config.js文件

yarn esno ./build/script/postBuild.ts

以上操作就能生成外部配置并加载了,使用时在开发环境、演示环境、生产环境部署修改_app.config.js中对应的api地址即可!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1482405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AcWing 787. 归并排序 解题思路及代码

先贴个题目&#xff1a; 以及原题链接&#xff1a;787. 归并排序 - AcWing题库https://www.acwing.com/problem/content/789/纯板子题&#xff0c;先贴代码吧&#xff0c;根据代码讲思路&#xff1a; #include <iostream> using namespace std;const int N 1e5 10; in…

备战蓝桥杯---状态压缩DP基础1之棋盘问题

它只是一种手段&#xff0c;一种直观而高效地表示复杂状态的手段。 我们先来看一道比较基础的&#xff1a; 直接DFS是肯定不行&#xff0c;我们发现对某一行&#xff0c;只要它前面放的位置都一样&#xff0c;那么后面的结果也一样。 因此我们考虑用DP&#xff0c;并且只有0/…

【three.js】搭建本地静态服务器 查询API文档使用

目录 一、为什么要搭建本地静态服务器呢&#xff1f; 二、下载three.js文件包 三、vscode配置live-server插件 一、为什么要搭建本地静态服务器呢&#xff1f; 平时学习Three.js&#xff0c;如果你想预览代码3D效果、查询API文档等&#xff0c;咱们需要提供一个本地静态服务…

(每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第12章 项目质量管理(五)

博主2023年11月通过了信息系统项目管理的考试&#xff0c;考试过程中发现考试的内容全部是教材中的内容&#xff0c;非常符合我学习的思路&#xff0c;因此博主想通过该平台把自己学习过程中的经验和教材博主认为重要的知识点分享给大家&#xff0c;希望更多的人能够通过考试&a…

​​Procedural Sky - Builtin LWRP URP - Jupiter

Jupiter是一个轻量级的单通道着色器,可帮助您立即创建动态天空盒,深度关注低多边形和风格化场景,可在桌面、移动和VR应用程序上运行良好,为您节省大量时间和精力! Jupiter完全支持轻量级、通用和内置渲染管道,并提供各种设置供您自定义。这些功能可以通过简单的切换轻松打…

【OpenGL编程手册-04】详细解释着色器

着色器 目录 一、说明二、着色器语言GLSL2.1 典型的着色器代码2.2 数据类型2.2.1 向量 2.3 输入与输出2.3.1 顶点着色器2.3.2 片段着色器 2.4 Uniform2.5 函数后缀含义2 .6 更多属性&#xff01; 三、我们自己的着色器类四、从文件读取五、 编译着色器练习 一、说明 在Hello T…

IK分词器的入门使用

目录 1. 前言2. IK分词器的特点3. 引入IK分词器的依赖4. 示例代码5.结论 1. 前言 中文分词是将连续的中文文本切分成一个个独立的词语的过程&#xff0c;是中文文本处理的基础。IK分词器是一个高效准确的中文分词工具&#xff0c;采用了"正向最大匹配"算法&#xff…

ORACLE 基础

一.ORACLE简介 1.1什么是oracle ORACLE 数据库系统是美国 ORACLE 公司&#xff08;甲骨文&#xff09;提供的以分布式数据库为核心的一组软件产品&#xff0c;是目前最流行的客户/服务器(CLIENT/SERVER)或 B/S 体系结构的数据库之一。 ORACLE 通常应用于大型系统的数据库产品。…

c++_leetcode_寻找峰值

目录 一、寻找峰值的示例 二、官方实现代码及解释 1、官方测试结果&#xff1a; 2、代码解释&#xff1a; 3、解题思路&#xff1a; 三、我的暴力解决 1、测试一&#xff1a; 2、测试二&#xff1a; 3、最终“暴力求解”代码&#xff1a; 4、官网提交测试通过&#xf…

Vue中<style scoped lang=“scss“>的含义

这段代码中的<style scoped lang"scss">是HTML和Vue框架结合使用时常见的一个模式&#xff0c;具体含义如下&#xff1a; scoped&#xff1a;这是一个Vue.js特有的属性&#xff0c;用来指定样式只应用于当前组件的元素。没有这个属性时&#xff0c;样式会全局应…

Day08-【Java SE进阶】面向对象高级二——多态、final、抽象类、接口

一、多态 对象多态多态是在继承/实现情况下的一种现象&#xff0c;表现为对象多态和行为多态。 对象多态&#xff1a;一个人可以是学生也可以是老师&#xff0c;学生和老师都是人的子类&#xff0c;创建人对象让其指向不同的对象&#xff0c;称为对象多态&#xff0c;这里是向…

springcloud:3.1介绍雪崩和Resilience4j

灾难性雪崩效应 简介 服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。 原因 1.服务提供者不可用(硬件故障、程序bug、缓存击穿、用户大量请求) 2.重试加大流量(用户重试,代码逻辑重试) 3.服…

NebulaGraph入门

感谢阅读 官方文档链接NebulaGraph简介nGQLnGQL简介占位标识符和占位符值注释实列大小写区分关键字 基本概念以及相关代码实现补充说明图空间语法以及列子创建克隆官方示例代码(创建并克隆)USE语句指定图空间时查看所有SPACESPACE详情CLEAR SPACE删库跑路&#xff08;看玩笑的说…

CPU,ISA架构,CPU位数与内存

CPU&#xff08;Central Processing Unit&#xff0c;中央处理器&#xff09;是计算机系统中的主要组件之一&#xff0c;负责执行程序指令并进行数据处理。我们之前已经介绍了CPU与冯诺依曼机CPU与冯诺依曼机-CSDN博客&#xff0c;而ISA&#xff08;Instruction Set Architectu…

EasyRecovery数据恢复软件2024最新版包括Windows和Mac

EasyRecovery数据恢复软件适用于多种环境和使用场景。首先&#xff0c;它适用于各种操作系统&#xff0c;包括Windows和Mac。无论用户使用的是哪种操作系统&#xff0c;都可以使用该软件进行数据恢复。 其次&#xff0c;EasyRecovery支持从各种存储设备和媒介中恢复数据&#…

CleanMyMac X2024免费Mac电脑清理和优化工具

CleanMyMac X是一款专业的 Mac 清理和优化工具&#xff0c;它具备一系列强大的功能&#xff0c;可以帮助用户轻松管理和维护他们的 Mac 电脑。以下是一些关于 CleanMyMac X 的主要功能和特点&#xff1a; 智能清理&#xff1a;CleanMyMac X 能够智能识别并清理 Mac 上的无用文件…

WPF真入门教程30--顺风物流单据管理系统

1、教程回顾 到现在为止&#xff0c;真入门系列教程已完成了29刺由浅入深地讲解&#xff0c;当然不可能讲到了WPF的所有技能点&#xff0c;但读者看到了wpf的内部各种功能及之间的联系&#xff0c;在此基础上&#xff0c;提供一个完整有效的综合项目&#xff0c;本项目采用的是…

汽车虚拟仿真技术的实现、应用和未来

汽车虚拟仿真技术是一种利用计算机模拟汽车运行的技术&#xff0c;以实现对汽车行为的分析、评估和改进。汽车虚拟仿真技术是汽车工业中重要的开发设计和测试工具&#xff0c;可以大大缩短产品研发周期、降低研发成本和提高产品质量。本文将从汽车虚拟仿真技术的实现过程、应用…

Sora:云端启航

2024年2月16日&#xff0c;OpenAI发布了“文生视频”&#xff08;text-to-video&#xff09;的大模型工具&#xff0c;Sora&#xff08;利用自然语言描述&#xff0c;生成视频&#xff09;。王炸消息一出&#xff0c;全球都再次被OpenAI震撼了。AI视频的高度一下子被Sora拉高了…

【论文阅读】《Graph Neural Prompting with Large Language Models》

文章目录 0、基本信息1、研究动机2、创新点3、准备3.1、知识图谱3.2、多项选择问答3.3、提示词工程&#xff08;prompt engineering&#xff09; 4、具体实现4.1、提示LLMs用于问答4.2、子图检索4.3、Graph Neural Prompting4.3.1、GNN Encoder4.3.2、Cross-modality Pooling4.…