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

现实需求

在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 } = paramstry {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 : realNameif (envName === "VITE_PORT") {realName = Number(realName)}if (envName === "VITE_PROXY" && realName) {try {realName = JSON.parse(realName.replace(/'/g, '"'))} catch (error) {realName = ""}}ret[envName] = realNameif (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-literalsconst reg = new RegExp("--mode ([a-z_\\d]+)")const result = reg.exec(script as string) as anyif (result) {const mode = result[1] as stringreturn [".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 filetags: 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 } = ENVif (!/^[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.hqwc.cn/news/503463.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

助力智能化农田作物除草,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建农田作物场景下玉米苗、杂草检测识别分析系统

在我们前面的系列博文中&#xff0c;关于田间作物场景下的作物、杂草检测已经有过相关的开发实践了&#xff0c;结合智能化的设备可以实现只能除草等操作&#xff0c;玉米作物场景下的杂草检测我们则少有涉及&#xff0c;这里本文的主要目的就是想要基于DETR模型来开发构建玉米…

好用且简单的本地大模型聊天工具LM Studio

先看效果&#xff1a; LM Studio是我目前见到最好用&#xff0c;也是最简单的本地测试AI模型的工具&#xff0c;不需要安装python环境以及众多的组件&#xff0c;加载模型、启用GPU、聊天都非常简单。而且可以切换很多不同类型的大语言模型&#xff0c;同时支持在Windows和MA…

在学习云原生的时候,一直会报错ImagePullBackOff Back-off pulling image

在学习云原生的时候&#xff0c;一直会报错 &#xff08;见最后几张图&#xff09; ImagePullBackOff Back-off pulling image 然后我就在像。这个配置的镜像是不是可以自己直接下载&#xff0c;但是好像不怎么搜索得到 然后就在想&#xff0c;这个lfy_k8s_images到底是个啥玩…

SINAMICS V90 PN 指导手册 第6章 BOP面板 LED灯、基本操作、辅助功能

概述 使用BOP可进行以下操作&#xff1a; 独立调试诊断参数查看参数设置SD卡驱动重启 SINAMICS V90 PN 基本操作面板 LED灯 共有两个LED状态指示灯&#xff0c;(RDY和COM)可用来显示驱动状态&#xff0c;两个LED灯都为三色(绿色/红色/黄色) LED灯状态 状态指示灯的颜色、状…

【软考】数据结构之队列和栈

目录 1.例题一1.1题目1.2 题目截图1.3 题目分析 1.例题一 1.1题目 输出受限的双端队列是指元素可以从队列的两端输入&#xff0c;但只能从队列的一端输出&#xff0c;如下图所示&#xff0c;若有e1&#xff0c;e2&#xff0c;e3&#xff0c;e4依次进入输出受限的双端队列&…

解决OriginPro2024学生版本的更改中文change language灰色无法更改语言的问题,超级简单,小白轻松上手

origin2024学生版 1. 成功方法1. 在win窗口点击卸载2. 点击修改3. 更改序列号&#xff0c;将序列号GL3S4-开头&#xff0c;改为DL2W8-开头的。4. 必须重新激活(否则依旧改不了&#xff09;5. 可以更改语言了 这是我的另一种失败方法&#xff0c;不必尝试&#xff08;更改序列表…

React之数据绑定以及表单处理

一、表单元素 像<input>、<textarea>、<option>这样的表单元素不同于其他元素&#xff0c;因为他们可以通过用户交互发生变化。这些元素提供的界面使响应用户交互的表单数据处理更加容易 交互属性&#xff0c;用户对一下元素交互时通过onChange回调函数来监听…

基于Springboot的高校实习信息发布网站的设计与实现(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的高校实习信息发布网站的设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xf…

Leetcode 剑指 Offer II 067.数组中两个数的最大异或值

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个整数数组 nums &#xff0c;返回 nums[i] XOR nums[j] 的…

Java玩转《啊哈算法》之模拟链表

人应该支配习惯&#xff0c;而绝不是让习惯支配人。一个人要是不能改掉坏习惯&#xff0c;那么他就一文不值。 目录 缘代码地址模拟链表创建遍历打印插入插入优化 完整代码 缘 各位小伙伴们好呀&#xff01;本人最近看了下《啊哈算法》&#xff0c;写的确实不错。 但稍显遗憾…

C#,K-均值(K-Means)聚类算法的核心源代码

一、詹姆斯麦昆&#xff08;James MacQueen&#xff09; IMS研究员詹姆斯B麦昆于2014年7月15日病逝&#xff0c;享年85岁。他的妻子安和他们的三个孩子唐纳德、凯特和玛丽以及五个孙子孙女幸存下来。 从1962年到去世&#xff0c;麦昆教授一直在加州大学洛杉矶分校管理研究生院…

软考 系统分析师系列知识点之需求获取(7)

所属章节&#xff1a; 第11章. 软件需求工程 第2节. 需求获取 需求获取是一个确定和理解不同的项目干系人的需求和约束的过程。需求获取是一件看上去很简单、做起来却很难的事情。需求获取是否科学、准备是否充分&#xff0c;对获取出来的结果影响很大&#xff0c;这是因为大部…