
1. 項目概述為什么環境變量是跨端開發的“命門”最近在帶幾個新人做UniApp項目發現一個挺普遍的問題大家本地開發跑得好好的一到測試或生產環境接口地址、AppID、密鑰這些就全亂套了要么就是打包后配置沒生效要么就是不同環境配置混在一起。追根溯源問題往往出在環境變量配置這個基礎環節上。很多人覺得這不過是幾個配置文件照著教程配一下就行但真到了多環境、跨平臺H5、小程序、App的UniApp Vue3 Vite項目里這里面的門道可不少。環境變量本質上是一套“運行時注入”的配置管理方案。它允許我們將與環境相關的配置如API基地址、調試開關、第三方密鑰從代碼中剝離出來實現“一份代碼多處部署”。對于UniApp這種一次開發、多端發布的框架來說這一點尤為重要。想象一下你的應用需要對接的后端API在開發時可能是http://localhost:3000測試環境是https://test-api.example.com而上線后則是https://api.example.com。如果這些地址硬編碼在代碼里每次切換環境都得改代碼、重新打包不僅效率低下而且極易出錯。Vue3 Vite的組合為現代前端開發帶來了極致的開發體驗其基于ES模塊的原生支持使得模塊熱更新HMR速度飛快。Vite在處理環境變量時也有一套自己的約定和構建時替換機制。但UniApp作為一個上層框架它對構建流程有自己的一套封裝和擴展特別是在處理多平臺如微信小程序、App時其構建目標和過程與純Web項目有所不同。這就導致了一個常見的困境直接套用Vite或Vue CLI那套環境變量配置方法在UniApp里可能行不通或者只在H5端生效到了小程序和App端就“失靈”了。因此理清在UniApp Vue3 Vite技術棧下環境變量如何正確配置、如何在代碼中安全獲取、以及如何適配多端構建就成了一個必須扎實掌握的核心技能。這不僅僅是配幾個文件那么簡單它關系到項目的可維護性、團隊協作的規范性以及最終交付的可靠性。接下來我就結合最近幾個項目的實戰經驗把這套配置體系的思路、具體做法和踩過的坑系統地梳理一遍。2. 環境變量配置的核心思路與方案選型在開始動手寫配置之前我們必須先想清楚目標我們需要一套怎樣的環境變量管理方案結合UniApp多端發行的特點我認為一個理想的方案需要滿足以下幾個核心需求環境隔離清晰地區分開發development、測試staging、生產production等不同環境互不干擾。多端一致配置方案需要在H5、各家小程序微信、支付寶等、AppiOS/Android等所有UniApp支持的目標平臺上都生效。安全可控敏感信息如密鑰不應出現在前端代碼倉庫中而應通過安全的渠道注入。開發友好在開發時能方便地切換和預覽不同環境的效果且支持熱更新。構建集成能無縫融入Vite的構建流程并正確參與UniApp特有的編譯過程。基于這些需求直接使用Vite原生環境變量.env文件是起點但并非終點。Vite使用dotenv從項目根目錄的.env文件中加載環境變量并通過import.meta.env對象暴露給客戶端代碼。這是Vite的標準做法在純Web項目中工作良好。然而UniApp的構建過程比純Web項目復雜。當你運行npm run dev:mp-weixin開發微信小程序時UniApp CLI會調用Vite如果你配置了Vite模式進行源碼編譯但最終生成的是小程序的代碼結構。在這個過程中Vite的環境變量替換是發生在源碼編譯階段的。問題在于UniApp編譯到不同平臺時可能會對源碼進行特定的轉換和封裝import.meta.env這個ES模塊的元屬性在某些平臺特別是小程序環境其JavaScript運行環境并非標準的瀏覽器或Node可能無法被正確識別或訪問。因此更穩健的方案是采用一種“雙軌制”或“適配層”的思路構建時注入利用Vite的define配置將環境變量在構建時靜態替換為具體的值。這樣最終生成的代碼里直接就是字符串常量不依賴于運行時的import.meta.env對象兼容性最好。運行時封裝同時我們也可以創建一個統一的配置模塊根據構建模式或平臺特性安全地讀取環境變量并提供統一的API給業務代碼使用。經過多個項目的實踐我總結出一套以“Vite環境變量文件為源通過define進行構建時替換并輔以統一配置模塊”為核心的配置方案。這套方案能較好地平衡靈活性、兼容性和安全性。2.1 方案對比與決策在具體實施前我們簡單對比幾種常見做法方案優點缺點適用場景純import.meta.envVite原生支持簡單直接在小程序/App端可能無法訪問變量值在構建后仍可能被查看非敏感信息可接受純H5項目或僅用于非敏感、非關鍵的配置Vitedefine替換構建時靜態替換生成字面量兼容性極佳可混淆敏感值需要預先明確所有變量名熱更新需要重啟服務修改.env文件時UniApp多端項目推薦尤其適合需要跨平臺穩定運行的配置運行時HTTP請求加載配置可動態更新無需重新打包增加首屏加載依賴和復雜度需要處理加載失敗和等待狀態配置需要頻繁變動的后臺管理系統或微前端場景平臺條件編譯UniApp原生支持可針對不同平臺寫死不同配置配置散落在代碼中難以維護無法根據構建環境dev/prod切換僅用于平臺特性差異極大的配置不推薦用于環境變量對于大多數UniApp項目“Vitedefine替換”為主“統一配置模塊”為輔的方案是最佳實踐。它確保了配置在構建階段就被確定并固化到產物中避免了運行時的兼容性問題同時通過配置模塊提供了清晰的接口。3. 項目結構與環境變量文件設計明確了方案我們先來規劃項目的目錄結構和環境變量文件。一個清晰的結構是后續一切操作的基礎。3.1 目錄結構規劃我建議在項目根目錄下創建env文件夾或直接放在根目錄專門管理環境變量相關文件。一個典型的結構如下your-uniapp-project/ ├── env/ # 環境變量目錄 │ ├── .env.development # 開發環境 │ ├── .env.staging # 測試環境 │ ├── .env.production # 生產環境 │ └── .env # 所有環境的默認值可選 ├── src/ ├── vite.config.ts # Vite 配置文件 ├── manifest.json # UniApp 應用配置 └── package.json注意.env文件通常包含敏感信息務必將其添加到.gitignore中避免提交到代碼倉庫。可以將.env.example或.env.local僅包含變量名不含真實值提交供團隊成員參考。3.2 環境變量文件內容示例每個.env.[mode]文件對應一種構建模式mode。Vite默認會根據你運行的命令如vite、vite build自動加載對應的文件。在UniApp中我們需要在package.json的 scripts 里指定模式。env/.env.development(開發環境)# 開發環境配置 VITE_APP_TITLE 我的應用(開發版) VITE_API_BASE_URL https://dev-api.example.com VITE_APP_DEBUG true VITE_WEIXIN_APPID wx1234567890abcdef # 開發用小程序AppIDenv/.env.staging(測試環境)# 測試環境配置 VITE_APP_TITLE 我的應用(測試版) VITE_API_BASE_URL https://staging-api.example.com VITE_APP_DEBUG true VITE_WEIXIN_APPID wxstaging1234567890env/.env.production(生產環境)# 生產環境配置 VITE_APP_TITLE 我的應用 VITE_API_BASE_URL https://api.example.com VITE_APP_DEBUG false VITE_WEIXIN_APPID wxproduction1234567890關鍵規則說明變量命名為了在客戶端代碼中能夠被Vite捕獲并處理自定義環境變量必須以VITE_開頭。這是Vite的強制約定否則變量不會被載入import.meta.env。值類型等號右邊的值會被解析為字符串。true或false在代碼中獲取時會是字符串true或false需要自行轉換。模式覆蓋Vite啟動時會先加載.env文件所有模式共享然后根據--mode指定的模式加載對應的.env.[mode]文件后者會覆蓋前者的同名變量。4. 核心配置Vite與UniApp的融合這是整個配置過程中最關鍵的一步我們需要修改vite.config.ts文件讓Vite在構建UniApp時正確地將環境變量“注入”到最終代碼中。4.1 修改vite.config.ts配置文件首先需要安裝types/node以便在Vite配置中使用process等Node.js模塊如果尚未安裝npm install -D types/node然后在vite.config.ts中我們需要做兩件事使用loadEnv函數加載指定模式的環境變量。通過define選項將環境變量定義為全局常量。// vite.config.ts import { defineConfig, loadEnv } from vite; import uni from dcloudio/vite-plugin-uni; import path from path; // https://vitejs.dev/config/ export default defineConfig(({ mode, command }) { // 1. 加載環境變量 // process.cwd() 返回項目根目錄 // 第三個參數 表示加載所有以 VITE_ 開頭的變量 const env loadEnv(mode, process.cwd() /env, ); // 注意我們指定了env目錄 // 2. 準備需要注入的 define 對象 const define {} as Recordstring, any; // 遍歷所有以 VITE_ 開頭的環境變量將其注入 for (const key in env) { if (key.startsWith(VITE_)) { // 注意這里值需要 JSON.stringify因為 define 是做字符串替換 // 例如VITE_API_BASE_URL: https://api.com 會被替換為 https://api.com define[import.meta.env.${key}] JSON.stringify(env[key]); } } // 也可以注入一些通用的、非 VITE_ 前綴的變量或方便使用的別名 define[import.meta.env.MODE] JSON.stringify(mode); define[import.meta.env.PROD] JSON.stringify(command build); define[import.meta.env.DEV] JSON.stringify(command ! build); return { plugins: [uni()], // 3. 定義全局常量替換 define, // 其他配置如resolve.alias... resolve: { alias: { : path.resolve(__dirname, src), }, }, }; });這段配置的核心邏輯解釋loadEnv(mode, process.cwd() /env, )從項目根目錄下的/env文件夾中加載對應模式mode的環境變量。作為第三個參數意味著我們只加載前綴為即所有的變量但實際上我們后續通過if (key.startsWith(VITE_))進行了過濾這是一種更靈活的控制方式。你也可以直接寫loadEnv(mode, process.cwd() /env, VITE_)來只加載VITE_開頭的變量。define對象這是Vite的配置項它會在構建階段將代碼中出現的define對象的鍵如import.meta.env.VITE_API_BASE_URL直接替換為對應的值如https://api.example.com。這是一個靜態文本替換的過程替換后的代碼里不再有import.meta.env這個引用因此兼容性極高。JSON.stringify()這是必須的。因為define是做簡單的字符串替換。如果不加JSON.stringify()假設env[key]是https://api.com替換后代碼會變成import.meta.env.VITE_API_BASE_URL https://api.com這缺少引號會導致語法錯誤。經過JSON.stringify()后值變成了https://api.com帶雙引號的字符串替換后代碼語法正確。4.2 修改package.json的 scripts接下來我們需要修改package.json中的啟動和構建腳本通過--mode參數指定要使用的環境模式。{ scripts: { dev:h5: uni -p h5 --mode development, build:h5: uni build -p h5 --mode production, dev:mp-weixin: uni -p mp-weixin --mode development, build:mp-weixin: uni build -p mp-weixin --mode production, dev:app: uni -p app --mode development, build:app: uni build -p app --mode production, // 可以添加自定義模式如測試環境 build:staging:h5: uni build -p h5 --mode staging, build:staging:mp-weixin: uni build -p mp-weixin --mode staging } }關鍵點--mode development告訴Vite使用development模式從而加載env/.env.development文件。--mode production對應加載env/.env.production。--mode staging對應加載env/.env.staging這是我們自定義的模式。現在當你運行npm run dev:mp-weixin時Vite就會加載開發環境的變量并注入到代碼中。5. 在代碼中安全、優雅地使用環境變量配置好了構建過程接下來就是在業務代碼中使用了。雖然經過define替換后我們可以直接使用import.meta.env.VITE_XXX但為了更好的類型提示、默認值處理和統一管理我強烈建議創建一個專門的配置模塊。5.1 創建統一的環境配置模塊在src目錄下創建config文件夾并新建env.ts文件// src/config/env.ts /** * 應用運行環境類型 */ export type AppEnv development | staging | production; /** * 獲取當前構建模式 * 通過 import.meta.env.MODE 獲取該值已在 vite.config.ts 中通過 define 注入 */ export const getEnvMode (): AppEnv { const mode import.meta.env.MODE as string; if ([development, staging, production].includes(mode)) { return mode as AppEnv; } // 默認返回生產環境確保線上安全 return production; }; /** * 應用配置對象 * 所有環境變量在此集中定義并提供類型安全和默認值 */ const appConfig { // 應用標題 title: import.meta.env.VITE_APP_TITLE || UniApp, // API 基礎地址 apiBaseUrl: import.meta.env.VITE_API_BASE_URL || , // 是否調試模式 isDebug: (import.meta.env.VITE_APP_DEBUG || false) true, // 微信小程序 AppID (如果需要) weixinAppId: import.meta.env.VITE_WEIXIN_APPID || , // 當前環境模式 mode: getEnvMode(), // 是否是生產環境 isProd: import.meta.env.PROD true, // 是否是開發環境 isDev: import.meta.env.DEV true, } as const; // 導出一個凍結的對象防止意外修改 export default Object.freeze(appConfig);這個模塊的優勢類型安全為配置對象提供了明確的類型定義。默認值處理避免了環境變量未定義導致的undefined錯誤。邏輯轉換將字符串類型的VITE_APP_DEBUG轉換為布爾值isDebug使用起來更直觀。集中管理所有配置在一個地方方便查找和修改。只讀保證通過Object.freeze防止運行時意外修改配置。5.2 在業務代碼中使用配置現在在Vue組件、Composables或工具函數中你可以像下面這樣使用script setup langts import { ref, onMounted } from vue; import envConfig from /config/env; // 使用別名指向src // 直接使用配置 const appTitle ref(envConfig.title); const apiBaseUrl envConfig.apiBaseUrl; onMounted(() { console.log(當前環境: ${envConfig.mode}); console.log(API地址: ${apiBaseUrl}); if (envConfig.isDebug) { console.warn(當前處于調試模式請注意控制臺信息。); } // 發起網絡請求示例 fetch(${apiBaseUrl}/user/profile) .then(res res.json()) .then(data console.log(data)); }); /script template view text{{ appTitle }}/text !-- ... -- /view /template5.3 處理平臺特定配置有時某些配置可能因平臺而異。例如微信小程序的AppID在H5環境下是無用的。我們可以在配置模塊中增加平臺判斷邏輯。UniApp提供了uni.getSystemInfoSync().platform或條件編譯。方法一運行時判斷適用于邏輯簡單的場景// 在 env.ts 中補充 import { getSystemInfoSync } from uni-get-system-info; // 或使用 uni.getSystemInfoSync const systemInfo getSystemInfoSync(); const isWeixinMiniProgram systemInfo.platform devtools || systemInfo.platform wechat; // 需精確判斷 export const platformConfig { // 可以在這里根據平臺返回不同的值 getAppId() { if (isWeixinMiniProgram) { return envConfig.weixinAppId; } return ; } };方法二條件編譯更徹底代碼更清晰條件編譯是UniApp的強項適合平臺差異大的配置。// src/config/env.ts let platformSpecificApi ; // #ifdef H5 platformSpecificApi /h5-api-proxy; // #endif // #ifdef MP-WEIXIN platformSpecificApi https://api.weixin.qq.com; // #endif // #ifdef APP platformSpecificApi envConfig.apiBaseUrl; // App可能用同一個 // #endif const appConfig { // ... 其他配置 platformApi: platformSpecificApi, };重要提示條件編譯的注釋 (// #ifdef) 是UniApp編譯器識別的特殊注釋它們會在編譯到特定平臺時被保留或移除。這確保了最終每個平臺的代碼只包含自己需要的部分。6. 多環境構建與部署實戰配置寫好了最終我們要打包部署。不同環境對應不同的命令和產物。6.1 配置 package.json scripts如前所述我們在package.json中已經配置了不同模式和平臺的腳本。例如開發微信小程序npm run dev:mp-weixin(使用.env.development)構建生產環境H5npm run build:h5(使用.env.production)構建測試環境微信小程序npm run build:staging:mp-weixin(使用.env.staging)6.2 構建產物驗證構建完成后如何確認環境變量正確注入了呢由于define是靜態替換我們可以檢查構建出的代碼文件。對于H5檢查dist/build/h5目錄下的.js文件。搜索你定義的變量名例如VITE_API_BASE_URL你應該會發現它已經被替換成了具體的字符串值而不是import.meta.env.VITE_API_BASE_URL。對于小程序檢查dist/dev/mp-weixin或dist/build/mp-weixin目錄下的.js文件如app.js或頁面js。同樣搜索變量名確認已被替換。一個快速驗證的方法在你的配置模塊env.ts中添加一個在控制臺打印配置的語句僅在開發環境if (import.meta.env.DEV) { console.log([Env Config], appConfig); }在開發時瀏覽器或開發者工具控制臺會輸出完整的配置對象。在構建生產包時由于import.meta.env.DEV被替換為false這段代碼不會被執行不會泄露信息。6.3 敏感信息處理與安全建議絕對不要將真實的密鑰、密碼等敏感信息提交到代碼倉庫即使是測試環境的。使用.env.local或個人環境文件創建.env.local文件并加入.gitignore。在vite.config.ts中可以調整loadEnv邏輯優先加載本地覆蓋文件。// 簡化示例Vite本身支持 .env.local 覆蓋 .env // 確保 .gitignore 包含 .env.local const env loadEnv(mode, process.cwd() /env, );CI/CD 管道注入在 Jenkins、GitLab CI、GitHub Actions 等持續集成/部署平臺中將敏感信息設置為流水線的“機密變量”。在構建腳本中通過命令行參數或環境變量動態生成.env.production文件。# 示例在CI腳本中 echo VITE_API_BASE_URL$PRODUCTION_API_URL ./env/.env.production echo VITE_APP_KEY$PRODUCTION_APP_KEY ./env/.env.production npm run build:h5后端代理與鑒權最安全的做法是所有涉及敏感操作或數據的請求都不應該依賴前端環境變量中的密鑰。前端只持有用于標識自身如AppID的非敏感信息具體的密鑰應由后端服務器保管前端通過安全的鑒權流程如OAuth 2.0獲取訪問令牌。7. 常見問題、排查技巧與實戰心得在實際項目中環境變量配置看似簡單卻容易遇到各種“坑”。下面是我總結的一些典型問題及解決方法。7.1 問題排查清單問題現象可能原因排查步驟與解決方案環境變量undefined1. 變量名不是以VITE_開頭。2..env文件未放在正確目錄或文件名與--mode不匹配。3.vite.config.ts中的loadEnv路徑或前綴參數錯誤。4.define配置未正確注入該變量。1. 檢查變量名確保以VITE_開頭。2. 檢查package.json腳本中的--mode參數確認對應的.env.[mode]文件存在且路徑正確。3. 在vite.config.ts中console.log(env)打印加載的環境變量對象確認是否加載成功。4. 檢查define對象中是否包含了該變量的鍵值對。H5正常小程序/App異常1. 代碼中直接使用import.meta.env.VITE_XXX但該對象在小程序環境不可用。2. 未使用define進行構建時替換。確保使用了define配置。這是解決多端兼容性的關鍵。構建后檢查小程序產物的js文件確認變量已被替換為字面量。修改.env文件后熱更新不生效Vite 的環境變量熱更新僅在服務啟動時讀取。define配置的替換是靜態的。重啟開發服務器。修改.env文件后需要停止并重新運行npm run dev:*命令。類型錯誤import.meta.env上不存在屬性TypeScript 無法識別自定義的VITE_變量。在src目錄下創建env.d.ts文件進行類型聲明interface ImportMetaEnv { readonly VITE_APP_TITLE: string; readonly VITE_API_BASE_URL: string; }構建后代碼中仍存在process.env項目中可能混用了Webpack或Node.js的process.env寫法。UniApp Vite 項目應統一使用import.meta.env。全局搜索process.env并替換。Vite的define也可以用于替換process.env.NODE_ENV等。不同開發者本地環境不一致.env.development文件被意外提交并覆蓋或者各自本地有未跟蹤的配置。1.確保.env*.local和.env.development等在.gitignore中。2. 提交一個.env.example文件列出所有需要的變量名不含值供團隊成員復制參考。3. 考慮使用dotenv庫在代碼中顯式加載指定路徑的文件但不如Vite集成方案優雅。7.2 實戰心得與技巧環境變量命名規范化團隊內部制定規范例如VITE_APP_前綴表示應用級配置VITE_API_前綴表示接口相關VITE_THIRD_表示第三方服務。一目了然便于管理。為配置模塊編寫單元測試雖然配置簡單但寫個簡單的測試用例來驗證getEnvMode()函數在不同import.meta.env.MODE值下的返回以及配置對象的默認值邏輯能有效防止后續修改時引入錯誤。善用條件編譯處理平臺差異對于真正因平臺而異的配置如圖片上傳的API、社交分享的SDK初始化參數使用// #ifdef條件編譯比在運行時通過if-else判斷更干凈還能減少無用代碼被打包到其他平臺。構建腳本自動化在package.json的 scripts 中可以組合命令。例如先清理舊構建產物再執行構建scripts: { clean: rimraf dist, build:prod:h5: npm run clean uni build -p h5 --mode production, }需要安裝rimraf包npm i -D rimraf關注vite.config.ts的緩存有時修改了vite.config.ts但感覺沒生效可能是Vite的緩存問題。可以嘗試在啟動命令后加上--force選項或者刪除node_modules/.vite緩存目錄。7.3 類型聲明的完善為了讓TypeScript更好地支持我們的環境變量創建src/env.d.ts文件// src/env.d.ts /// reference typesvite/client / // 擴展 ImportMetaEnv 接口定義自定義環境變量的類型 interface ImportMetaEnv { // 每個變量都應該是只讀的 readonly VITE_APP_TITLE: string readonly VITE_API_BASE_URL: string readonly VITE_APP_DEBUG: string // 注意從.env讀取的是字符串 readonly VITE_WEIXIN_APPID: string // 添加更多變量... } interface ImportMeta { readonly env: ImportMetaEnv }完成這一步后你在代碼中鍵入import.meta.env.IDE就會自動提示出VITE_APP_TITLE等變量并且有正確的類型約束。經過以上從思路到實踐從配置到排查的完整梳理相信你已經能夠駕馭UniApp Vue3 Vite項目中的環境變量配置了。這套方案的核心在于理解Vite的構建時替換機制并利用它來規避UniApp多端運行時環境的差異。記住好的配置管理是項目工程化的基石花時間把它搭建穩健能為后續的開發、測試和部署省去無數麻煩。如果在實踐中遇到新的問題不妨回頭檢查一下構建產物的代碼看看變量是否被正確替換這往往是定位問題的捷徑。