背景
在企業級項目開發中,一般都會分為開發、測試、預發布、生產等多個環境,在工程化中使用不同的打包命令改變環境變量解決不同環境各種變量需要手動修改的問題,比如接口請求地址,不同環境的請求路徑前綴都是不同的。在使用uni-app
開發項目時,一般都是選擇使用HbuilderX
可視化創建項目,也不建議使用cli
工程化方式創建uni-app
項目。在HbuilderX
中,默認只支持開發和生產兩個環境,點擊“運行”編譯出來的代碼是開發環境(development
),點擊“發行”編譯出來的代碼是生產環境(production
),可以通過process.env.NODE_ENV
獲取當前環境。但在很多企業中,可能就2個環境并不能滿足實際場景,同時在開發微信小程序時,測試和生產都是不同的appid
,每次部署都要手動修改切換很容易出現問題。為了解決上述問題,通過在package.json
中增加uni-app
擴展節點,實現自定義條件編譯平臺,讓每種編譯具有不同環境標識。再擴展vite.config.js
配置文件,用環境標識判斷重寫文件中的appid
。
解決方案
一、創建基礎項目
選擇默認模板,注意vue版本選擇3
二、增加擴展節點
根據官方文檔說明,擴展節點配置說明如下:
{/*** package.json其它原有配置 * 拷貝代碼后請去掉注釋!*/"uni-app": {// 擴展配置"scripts": {"custom-platform": { //自定義編譯平臺配置,可通過cli方式調用"title":"自定義擴展名稱", // 在HBuilderX中會顯示在 運行/發行 菜單中"browser":"", //運行到的目標瀏覽器,僅當UNI_PLATFORM為h5時有效"env": {//環境變量"UNI_PLATFORM": "", //基準平臺"MY_TEST": "", // ... 其他自定義環境變量},"define": { //自定義條件編譯"CUSTOM-CONST": true //自定義條件編譯常量,建議為大寫}}}}
}
注意:
UNI_PLATFORM
僅支持填寫uni-app
默認支持的基準平臺,目前僅限如下枚舉值:h5
、mp-weixin
、mp-alipay
、mp-baidu
、mp-toutiao
、mp-qq
browser
僅在UNI_PLATFORM
為h5
時有效,目前僅限如下枚舉值:chrome
、firefox
、ie
、edge
、safari
、hbuilderx
package.json
文件中不允許出現注釋,否則擴展配置無效vue-cli
需更新到最新版,HBuilderX需升級到 2.1.6+
實際使用時,暫時不用的變量直接刪除,新建package.json
文件,代碼如下:
{"uni-app": {"scripts": {"wx-test": {"title":"微信小程序 測試環境","env": {"UNI_PLATFORM": "mp-weixin","NAME": "test"}},"wx-prod": {"title":"微信小程序 生產環境","env": {"UNI_PLATFORM": "mp-weixin","NAME": "production"}},"h5-dev": {"title":"H5 開發環境","browser":"chrome","env": {"UNI_PLATFORM": "h5","NAME": "development"}},"h5-test": {"title":"H5 測試環境","browser":"chrome","env": {"UNI_PLATFORM": "h5","NAME": "test"}},"h5-prod": {"title":"H5 生產環境","browser":"chrome","env": {"UNI_PLATFORM": "h5","NAME": "production"}}}}
}
上面代碼片段只以微信小程序和H5
兩個端為例,其中只增加了常量NAME
用于區分當前環境,類似于process.env.NODE_ENV
獲取環境變量的作用。一般小程序也就測試和生產兩個環境,環境太多都要重新申請賬號也麻煩。H5
按照常規的配置本地開發、測試、生產三個環境。配置好后我們點擊頂部菜單欄的“運行”和“發行”即可看到效果。
當在業務里需要使用添加的NAME
變量時,直接通過process.env.NAME
即可獲取。
四、配置其他變量
根目錄下新建config
目錄,用于放一些業務配置項,再新建環境相關變量配置文件env.js
,代碼如下:
// 不同的環境變量配置
const development = {requestBaseUrl: 'http://development', appid: '',
}const test = {requestBaseUrl: 'http://test',appid: 'wxd5xxxxee0fce1c81',
}const production = {requestBaseUrl: 'http://production',appid: 'wx3xxxx1ce403cab3',
}export default {development,test,production
}
其中變量對象名稱development
、test
、production
要和package.json
文件中定義的NAME
保持一致,方便后續通過對象方式直接取值。變量對象中添加的是需要根據不同環境配置的變量,比如后端服務請求地址,小程序appid
和一些別的插件key
。配置后我們就可以配合環境NAME
獲取到不同環境的其他變量了,簡單使用方式如下:
import ENV_CONFIG from '@/config/env.js'
console.log(ENV_CONFIG[process.env.NAME].requestBaseUrl) // 運行H5 開發環境結果 http://development
每次引入獲取方式肯定不夠友好,在uni-app
中還可以通過修改vite
配置添加全局變量,更方便在全局使用。
首先根目錄下新建vite.config.js
文件,內容如下:
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import ENV_CONFIG from './env/index.js'export default defineConfig({plugins: [uni()],define: {'process.env.config': ENV_CONFIG,},
});
通過定義一個全局變量process.env.config
,賦值為ENV_CONFIG
,process.env.config
可以改為任何一個字符串,這里主要是為了保持和默認通過process.env
獲取環境變量的語義一致性。此時使用時就無需在業務中單獨引入,從全局對象process.env.config
上取值即可:
console.log(process.env.config[process.env.NAME].requestBaseUrl) // 運行H5 開發環境結果 http://development
五、動態修改小程序appid
appid
是在根目錄下的manifest.json
文件中,點擊后最下面有源碼視圖。修改的方式就是運用node
的fs
模塊,先讀取manifest.json
文件,然后根據當前環境,動態替換掉appid
或者其他參數,最后重新寫入到當前目錄下。具體也是在vite.config.js
中處理:
import { defineConfig } from 'vite';
import uni from '@dcloudio/vite-plugin-uni';
import ENV_CONFIG from './config/env.js'// 引入fs模塊
import fs from 'fs'// 讀取 manifest.json ,修改后重新寫入
const manifestPath = `${__dirname}/manifest.json`;
let Manifest = fs.readFileSync(manifestPath, { encoding: 'utf-8' });
function replaceManifest(path, value) {const arr = path.split('.');const len = arr.length;const lastItem = arr[len - 1]; let i = 0;let ManifestArr = Manifest.split(/\n/);for (let index = 0; index < ManifestArr.length; index++) {const item = ManifestArr[index];if (new RegExp(`"${arr[i]}"`).test(item)) ++i;if (i === len) {const hasComma = /,/.test(item);ManifestArr[index] = item.replace(new RegExp(`"${lastItem}"[\\s\\S]*:[\\s\\S]*`),`"${lastItem}": ${typeof value === 'string'? '"'+value+'"' : value}${hasComma ? ',' : ''}`);break;}}Manifest = ManifestArr.join('\n');
}
// 具體使用,找到對應key值替換為新的值
// replaceManifest('app-plus.usingComponents', false);const appid = ENV_CONFIG[JSON.parse(process.env.UNI_CUSTOM_DEFINE).NAME].appid
replaceManifest('mp-weixin.appid', appid);fs.writeFileSync(manifestPath, Manifest, { flag: 'w' });export default defineConfig({plugins: [uni()],define: {'process.env.config': ENV_CONFIG,},
});
這個修改方案是根據官方提供的代碼片段修改,其中進行了一些變動:
manifest.json
文件路徑由相對路徑改為__dirname
獲取的絕對路徑replaceManifest
方法中的value進行了typeof
類型判斷,如果是字符串加上雙引號。因為測試時傳個字符串會替換成沒引號的變量或者數字
同時關于當前環境變量的獲取,此時通過process.env.NAME
是獲取不到package.json
配置的NAME
的,通過打印process.env
可以發現此時它是個包含很多變量的json
,在UNI_CUSTOM_DEFINE
下面是可以找到NAME
,這樣就能根據不同環境獲取不同的appid
。
然后也可以用下面這種更容易理解的方式修改manifest.json
,但是修改后內容排在一行,想要美觀還需要手動格式化。
// appid獲取只做參考,這里只是說明簡單的只有兩個環境,可以直接取process.env.NODE_ENV判斷
let appid = process.env.NODE_ENV == "production" ? '生產的appid' : "開發的appid"
// manifest.json 路徑
let manifestFileUrl = `${__dirname}/manifest.json`
// 讀取文件數據
let manifestFileData = fs.readFileSync(manifestFileUrl, { encoding: 'utf8' });
// 移除// 和 /* */注釋
manifestFileData = manifestFileData.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) => g ? "" : m)
// // 將txt轉成obj
let manifestFileDataObj = JSON.parse(manifestFileData)
// 修改指定key對應的valuemanifestFileDataObj['mp-weixin']['appid'] = appid
// 把修改后的對象以json寫入文件
fs.writeFileSync(manifestFileUrl, JSON.stringify(manifestFileDataObj), { encoding: 'utf8' })
六、使用方式
- 需要本地調試時,點擊工具欄“運行”,選擇自定義的對應開發或測試環境;
- 業務中通過
process.env.config[process.env.NAME]
獲取配置的變量對象; - 上線時,點擊工具欄“發行”,選擇自定義的對應測試或生產環境;
運行環境
以上代碼是運行在Hbuilderx 3.7.9
版本,項目為vue3
版本,基于vite
構建。如在vue2
版本上使用,請按照vite.config.js
邏輯自行探索配置vue.config.js
文件。