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.pswp.cn/news/711838.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/711838.shtml
英文地址,請注明出處:http://en.pswp.cn/news/711838.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

方法區的垃圾收集

方法區的垃圾收集 主要回收兩部分內容廢棄的常量和不再使用的類型 廢棄的常量&#xff1a; 假如一個字符串“java”曾經進入常量池中&#xff0c;但是當前系統又沒有任何一個字符串對象的值是“java”&#xff0c;換句話說&#xff0c;已經沒有任何字符串對象引用常量池中的“…

三天學會阿里分布式事務框架Seata-應用seata AT模式方案解決分布式事務問題

鋒哥原創的分布式事務框架Seata視頻教程&#xff1a; 實戰阿里分布式事務框架Seata視頻教程&#xff08;無廢話&#xff0c;通俗易懂版&#xff09;_嗶哩嗶哩_bilibili實戰阿里分布式事務框架Seata視頻教程&#xff08;無廢話&#xff0c;通俗易懂版&#xff09;共計10條視頻&…

dolphinscheduler海豚調度(四)釘釘告警

在之前的博文中&#xff0c;我們已經介紹了DolphinScheduler海豚調度的基本概念和工作流程&#xff0c;以及Shell任務和SQL任務的實踐。今天&#xff0c;讓我們來學習DolphinScheduler中的另一個重要功能&#xff1a;釘釘告警。 釘釘群添加機器人 在釘釘群添加機器人&#xf…

SpringBoot 使用@Async 注解實現異步任務

前言 在現代應用程序中&#xff0c;異步編程已經成為了必備的技能。異步編程使得應用程序可以同時處理多個請求&#xff0c;從而提高了應用程序的吞吐量和響應速度。在 SpringBoot 中&#xff0c;我們可以使用 Async 注解來實現異步編程。本文將介紹 Async 注解的使用方法和注…

從http到websocket

閱讀本文之前&#xff0c;你最好已經做過一些websocket的簡單應用 從http到websocket HTTP101HTTP 輪詢、長輪詢和流化其他技術1. 服務器發送事件2. SPDY3. web實時通信 互聯網簡史web和httpWebsocket協議1. 簡介2. 初始握手3. 計算響應健值4. 消息格式5. WebSocket關閉握手 實…

Redis 緩存數據庫

redis 中文網 http://www.redis.cn/ redis.net.cn 兩種數據庫陣營 1.關系型數據庫 MySQL Oracle DB2 SQL Server 等基于二維表結構存儲數據的文件型磁盤數據庫 缺點: 因為數據庫的特征是磁盤文件型數據庫, 就造成每次查詢都有IO操作, 海量數據查詢速度較慢 2.NoSQL數據庫 …

C++中的常對象、常函數

一、常對象的概念 常對象就是用 const 修飾的對象&#xff0c;常對象必須初始化且不可被修改。 //以日期類對象為例 const Date d1(2004, 5, 25); 二、常對象只能調用常函數 常對象只能調用常函數&#xff0c;不能調用其他函數。 以日期類為例&#xff0c;類中有成員函數P…

lv20 QT 常用控件 2

1 QT GUI 類繼承簡介 布局管理器 輸出控件 輸入控件 按鈕 容器 2 按鈕示例 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QCheckBox> #include <QLineEdit> #include <QPushButton>class Widget : public QWidget {Q_OBJECTpublic…

SLAM面試代碼題:點云去畸變

題目 假設已知一幀點云每個點的時間戳和它的位姿,要求對點云去畸變 解題思路 定義一個點云的struct利用時間戳,把一幀內每個時刻的點云都變換到這一幀的起始時間處位置使用線性插值,旋轉使用球面非線性插值// 點云去畸變 #include <iostream> #include <Eigen/Co…

擊鼓傳花游戲

有N個小朋友圍成一圈玩擊鼓傳花游戲&#xff0c;將小朋友編號為1-N&#xff0c;從1號開始傳花&#xff0c;每次傳3個&#xff0c;拿到花的小朋友表演節目后退出。任給N&#xff0c;問最后一個表演的小朋友編號是多少&#xff1f;例如&#xff1a;輸入5&#xff0c;從1號開始傳花…

基于springboot+vue的共享汽車管理系統(前后端分離)

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

Linux中的echo命令

echo?命令是在Linux系統中常用的用于輸出文本或變量內容的命令。它可以將指定的文本或變量的值輸出到終端上。下面是關于 ?echo?命令的使用說明和示例&#xff1a; 1. 基本語法&#xff1a; echo [選項] [字符串或變量] 2. 使用示例&#xff1a; 輸出文本內容&#xff1…

3d模型版本轉換器注意事項---模大獅模型網

在使用3D模型版本轉換器時&#xff0c;有一些注意事項可以幫助您順利完成模型轉換并避免不必要的問題&#xff1a; 數據完整性&#xff1a;在進行模型轉換之前&#xff0c;確保您的原始3D模型文件沒有損壞或缺失數據。損壞的文件可能導致轉換器無法正常處理或輸出錯誤的結果。 …

力扣經典題目解析--滑動窗口最大值

原題地址: . - 力扣&#xff08;LeetCode&#xff09; 給你一個整數數組 nums&#xff0c;有一個大小為 k 的滑動窗口從數組的最左側移動到數組的最右側。你只可以看到在滑動窗口內的 k 個數字。滑動窗口每次只向右移動一位。 返回 滑動窗口中的最大值 。 示例 1&#xff1a;…

小程序自定義組件

自定義組件 1. 創建-注冊-使用組件 組件介紹 小程序目前已經支持組件化開發&#xff0c;可以將頁面中的功能模塊抽取成自定義組件&#xff0c;以便在不同的頁面中重復使用&#xff1b; 也可以將復雜的頁面拆分成多個低耦合的模塊&#xff0c;有助于代碼維護。 開發中常見的…

111790-37-5 ,生物素-氨基,一種生物素化合物,可與-NHS、-COOH反應

您好&#xff0c;歡迎來到新研之家 文章關鍵詞&#xff1a;111790-37-5 &#xff0c;生物素-氨基&#xff0c;生物素氨基&#xff0c;Biotin-NH2&#xff0c;Biotin-amine 一、基本信息 【產品簡介】&#xff1a;Biotin-NH2 provides a convenient biotinylation method for…

OSCP靶場--DVR4

OSCP靶場–DVR4 考點(1.windows&#xff1a;路徑遍歷獲取私鑰getshell 2.ssh shell中runas切換用戶) 1.nmap掃描 ┌──(root?kali)-[~/Desktop] └─# nmap -sV -sC -p- 192.168.161.179 --min-rate 2000 Starting Nmap 7.92 ( https://nmap.org ) at 2024-02-29 07:14 EST…

Springboot接口參數校驗

在設計接口時我們通常需要對接口中的非法參數做校驗&#xff0c;以降低在程序運行時因為一些非法參數而導致程序發生異常的風險&#xff0c;例如登錄的時候需要校驗用戶名密碼是否為空&#xff0c;創建用戶的時候需要校驗郵件、手機號碼格式是否準確。如果在代碼中對接口參數一…

系統集成Prometheus+Grafana

根據產品需求在自己的系統中添加一個系統監控的頁面&#xff0c;其中有主機信息的顯示&#xff0c;也有一些業務信息的顯示。調研后的方案是 主機信息通過Prometheus采集和存儲&#xff0c;業務信息通過自己系統的調度任務統計后存儲在Mysql中&#xff0c;使用Grafana對接Prome…

Java必須掌握的繼承的特點和繼承體系的設計(含面試大廠題和源碼)

Java繼承是面向對象編程的一個基本特性&#xff0c;它允許一個類繼承另一個類的屬性和方法。設計良好的繼承體系是高質量軟件開發的關鍵。在大廠面試中&#xff0c;面試官可能會詢問關于Java繼承特點及如何設計一個合理的繼承體系的問題&#xff0c;以評估你的面向對象設計能力…