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