前言
這篇文章主要介紹uniapp
在Hbuilderx
中,通過工程化,區分不同環境、動態修改小程序appid
以及自定義條件編譯,解決代碼發布
和運行時
手動切換到問題。
背景
在企業級的應用中,通常會分為,開發、聯調、生產等多個環境,一個項目可能要發布到多個微信小程序,在工程化中,通過使用不同的打包命令設置不同的環境變量,解決不同環境各變量的內容需手動修改的問題,比如:接口、前綴、appid
等;在使用uniapp開發項目時,通常使用Hbuilder
可視化運行項目,點擊運行編譯出來都代碼環境是(development)
,點擊發布運行編譯出來的代碼是(production)
,分別對應開發和生產,使用process.env.NODE_ENV
來獲取運行環境。但是在很多企業項目中,就兩個環境,很難滿足使用場景。
為了解決以上問題,通過在package.json
中增加增加 uni-app節點
,自定義條件編譯和環境,通過modifyManifest.js
重寫appid
,擴展vue.config.js
配置,用環境標識區分接口
一、自定義條件編譯
以微信小程序為例,在做條件編譯時候,只有一種判斷條件
<!-- #ifdef MP-WEIXIN -->
<view>我是微信</view>
<!-- #endif -->
<!-- #ifdef H5 -->
<view>我是后</view>
<!-- #endif -->
但實際情況是,我們有兩個微信主體,希望在不同主體展示不同信息:
<!-- #ifdef MP-CJN -->
<view>我是CJN</view>
<!-- #endif -->
<!-- #ifdef MP-YYT -->
<view>我是YYT</view>
<!-- #endif -->
在package.json
中新增uni-app
官網自定義配置;
實際使用時,刪除掉文件中所有的注釋信息,否則編譯時會報錯。
{
"uni-app": {
"scripts": {
"cjnDev": {
"title":"小程序1-聯調環境",
"env": {
"UNI_PLATFORM": "mp-weixin",
"NAME": "cjnDev"
},
"define": {
"MP-CJN": true
}
},
"cjnTest": {
"title":"小程序1-測試環境",
"env": {
"UNI_PLATFORM": "mp-weixin",
"NAME": "cjnTest"
},
"define": {
"MP-CJN": true
}
},
"cjnProd": {
"title":"小程序1-生產環境",
"env": {
"UNI_PLATFORM": "mp-weixin",
"NAME": "cjnProd"
},
"define": {
"MP-CJN": true
}
},
"yytDev": {
"title":"小程序2-聯調環境",
"env": {
"UNI_PLATFORM": "mp-weixin",
"NAME": "yytDev"
},
"define": {
"MP-YYT": true
}
},
"yytTest": {
"title":"小程序2-測試環境",
"env": {
"UNI_PLATFORM": "mp-weixin",
"NAME": "yytTest"
},
"define": {
"MP-YYT": true
}
},
"yytProd": {
"title":"小程序2-生產環境",
"env": {
"UNI_PLATFORM": "mp-weixin",
"NAME": "yytProd"
},
"define": {
"MP-YYT": true
}
}
}
}
}
注意:盡量保證yytProd和NAME值保持一致
以上代碼以微信小程序在不同主體的展示為例,分別為小程序1(MP-CJN)、小程序2(MP-YYT)
,同時區分了三個環境,聯調、測試和生產,配置好以后,我們在Hbuilder中點擊運行和發行可以看到下面效果
這時就可以使用<!-- #ifdef MP-YYT -->
來實現在微信平臺,區分不同主體的條件編譯,通過環境變量process.env.NAME
取得配置文件中NAME
的信息
二、配置其他變量
創建`env.js`,存放相關環境變量的信息;我是在common中創建的,可以根據自己項目實際情況選擇目錄
module.exports = {
// 小程序1聯調環境
cjnDev: {
requestUrl: 'https://mp.com',
appid: '小程序appid'
},
// 小程序1測試環境
cjnTest: {
requestUrl: '接口地址',
appid: '小程序appid'
},
// 小程序1線上環境
cjnProd: {
requestUrl: '接口地址',
appid: '小程序appid'
}
// 小程序2聯調環境
yytDev: {
requestUrl: '接口地址',
appid: '小程序appid'
},
// 小程序2測試環境
yytTest: {
requestUrl: '接口地址',
appid: '小程序appid'
},
// 小程序2線上環境
yytProd: {
requestUrl: '接口地址',
appid: '小程序appid'
}
}
其中變量名 cjnDev
、cjnTest
、cjnProd
等要跟package.json
中的NAME
一致,方便后續通過變量名取值。
在根目錄下創建vue.config.js
let configUrl = require('./common/env.js');
// 動態修改appid,調試環境時,可以先注釋掉
require('./src/modifyManifest.js');
module.exports = {
chainWebpack: config => {
config
.plugin('define')
.tap(args => {
args[0]['process.env.config'] = JSON.stringify(configUrl)
return args
})
}
}
通過定義一個全局的變量process.env.config
存儲的就是env.js
中的全部變量信息,此時就可以直接獲取到當前運行所對應的配置信息
// 運行小程序1-聯調環境 獲得:https://mp.com
le url = process.env.config[process.env.NAME].requestUrl
動態修appid
appid
在項目根目錄的manifest.json
內,動態修改邏輯是使用nodejs
的fs
模塊,通過方法readFileSync
讀取文件,然后跟進當前環境對內容進行修改,最后通過writeFileSync
寫入到manifest.json
中
在src
目錄下創建modifyManifest.js
,劃重點:一定得是在src目錄下
let configUrl = require('../common/env.js');
const fs = require('fs');
// 讀取 manifest.json
const manifestPath = `${process.env.UNI_INPUT_DIR}/manifest.json`
let Manifest = fs.readFileSync(manifestPath, { encoding: 'utf-8' })
/**
* 替換 manifest.json 文件內容
* @param {String} path 目標元素的鍵
* @param {String} value 目標元素的值
*/
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')
}
// 替換appid
const appid = configUrl[process.env.UNI_SCRIPT].appid;
replaceManifest('mp-weixin.appid', appid);
// 文件輸出
fs.writeFileSync(manifestPath, Manifest, {
"flag": "w"
})
關于環境變量,此時獲取不到process.env.NAME
,通過打印可以看到process.env.UNI_SCRIPT
與NAME的值一致,這也是為什么我們前面強調:‘盡量保證yytProd
和NAME
值保持一致’的原因。
三、使用方式
1. 本地調試運行:Hbuilder->運行,選擇對應的自定義環境執行
2. 上線發布:Hbuilder->發行->自定義發行,選擇對應的自定義環境執行
3. 業務開發通過`process.env.config[process.env.NAME]`獲取對應環境的變量對象