首頁 > 軟體

uni-app多環境部署解決方案詳解

2022-11-17 14:00:45

前言

最近幾周都在處理公司的移動業務,而為在後期能統一多端,解放自己,迎合公司的技術棧;選用了 uni-app 來開發。開發前期重新對公司移動業務做深入瞭解,重構大部分業務邏輯,也抽離出基礎元件;但實際到部署的時候,出現來問題;由於現在只考慮 H5 端,部署和測試會出現多環境設定,但是我使用的 HBuilderX 工具建立的工程,所以只存在開發環境:development 和生產環境:production

嘗試幾種方式

查詢官網和論壇並沒有很好的設定方案;官網的一些設定可以提供參考。

  • package.json

對於根目錄下 package.json 裡可以提供對不同平臺的編譯處理,這裡指不同平臺並不是不同環境,環境還是隻有開發和生產兩種環境

  • vue.config.js

由於沒有使用 VUE3 來開發,所以預設的設定項還是基於 webpack。如果專案根目錄沒有該設定項,可以自行建立 vue.config.js 檔案,但是很遺憾還是沒有可以處理多種環境下的一個設定。而且它還存在一些約束:

不過它可以新增一些自定義的變數

const webpack = require('webpack')

module.exports = {
  chainWebpack: config => {
    config
      .plugin('define')
      .tap(args => {
        args[0]['process.env'].VUE_APP_TEST = '"test"'
        return args
      })
  }
}

解決方案

多環境部署,實際是需要對應自己部署環境,存在不同設定項。而實際業務中存在的環境可以是無限的,一般最基礎而言需要三種:

  • 開發環境

  • 測試環境

  • 生產環境

對於公司現有業務,只針對 H5 端,需要的設定可能只有:

  • 介面:開發、測試、生產對應的介面設定不同

  • 部署路徑:測試、開發對應的部署路徑不同

如果我們解決這兩個,那部署方案實現一大半。對於環境設定,從 vue-cli 中可以看到很多;cli 設定基於 .env.x 不同檔案來獲取不同設定項,這裡我們可以參考它來自己實現獲取設定項。

部署方式

部署方式,通過命令列來解決;後續可以更好的對接自動化部署,而專案中通過 HBuilderX 工具建立,需要使用它的 cli 程式,它支援常見的三端打包;H5 端打包命令,在 package.json 設定:

"build": "cli publish --platform h5 --project 專案名稱",

獲取介面

專案根目錄建立不同環境下需要的設定:.env.test.env.prod

# .env.test
NODE_ENV=test
BASE_API = '/test'
h5.router.base_config = '/h5/'
h5.title_config = 'h5'

實際上我們只需要測試和生產兩種設定,開發設定項在程式碼內部修改,這樣可以增加效率,不用每次修改後,再重啟專案。

設定項對應不同環境,而環境可以通過在 package.json 中設定不同引數來區分;

	"scripts": {
		"build:config:test": "node ./deploy/index --mode=test",
		"build:config:prod": "node ./deploy/index --mode=prod",
	},

可以獲取 process.argv 變數讀取到設定的環境;後續還想設定什麼變數也可以在後面直接新增,類似:--test=test

// yargs.js
module.exports = function() {
	let args = process.argv;
	let argv = {};
	for (let i = 2; i < args.length; ++i) {
		let cur = args[i];
		if (/^(--)(S*)(=)/.test(cur)) {
			const keys = cur.split('=')
			argv[keys[0].slice(2)] = keys[1];
		}
	}
	return argv
}

/**
 * {
 *      mode: 'test'
 * }
 */

獲取設定後,需要讀取設定,這裡直接使用 nodefs 模組讀取檔案內容

const fs = require('fs')
const path = require('path')
// 解析函數
function parse() {
    ...
}

module.exports = function() {
    // 獲取環境
	const config = yargs();
	
	const env = config.mode;
	const envPath = path.resolve(__dirname, '../../') + '/.env.' + env
	
	try{
		const data = fs.readFileSync(envPath, 'utf8')
        // 解析檔案
		return parse(data)
	}catch(e){
		console.log('讀取env出錯:' + JSON.stringify(e));
	}
}

其中解析函數,由於不想新增依賴增加專案負擔,直接參考 dotenv 的 parse 函數解析出檔案內容;得到類似的物件:

{
    NODE_ENV: 'test',
    BASE_API: '/test',
    // ...
}

解析出設定內容,接下來動態組態檔;由於專案存在可能部署在客戶內網環境下,這裡採用動態生產一個共用的組態檔,在專案獲取該設定項;後續運維人員可以想設定什麼就設定什麼。

// 寫入 /static/global.js
writeGlobalConfig()

function writeGlobalConfig() {
	const _global = {}
	for (let key in config) {
		if (key.includes('_API')) {
			_global[key] = config[key]
		}
	}
	const data = `window._GLOBAL__ = ${JSON.stringify(_global)}`
	fs.writeFileSync(path.resolve(__dirname, '../static/global.js'), data)
}

在專案中生產環境下取公用設定項

const NODE_ENV = process.env.NODE_ENV;

/// 預設根目錄模板 tempalte.h5 模板引入全域性介面 static/global.js
const GLOBAL_CONFIG = window._GLOBAL__ || {};

const defaultAPI = {
	BASE_API: {
		development: ['/test'],
		production: GLOBAL_CONFIG.BASE_API,
	},
	SOCKET_API_BIDDIGN: {
		development: ['ws://test'],
		production: GLOBAL_CONFIG.SOCKET_API_BIDDIGN,
	},
    // ...
}

部署路徑

PC 端或者是 H5 測試和生產環境上的部署路徑可能會不同;由於建立專案使用其開發工具建立,需要統一工具和更方便的更新 uni-app,不考慮使用 vue-cli 方式。只能動態修改 manifest.json 檔案。

uni-app 的部署路徑是修改 manifest.jsonh5.router.base。對應 Router 中的 base

// manifest.js
const fs = require('fs')
const path = require('path')

const manifestPath = path.resolve(__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}": ${value}${hasComma ? ',' : ''}`)
      break;
    }
  }

  Manifest = ManifestArr.join('n')
}
module.exports = function(options) {
	for (let key in options) {
		replaceManifest(key, `"${options[key]}"`)
	}
	fs.writeFileSync(manifestPath, Manifest, {
	  "flag": "w"
	})
}

前面我們已經獲取到組態檔內容,這裡可以直接修改檔案;這裡需要給一個標明這是修改 manifest.json 的字尾。

h5.router.base_config = '/h5/'
h5.title_config = 'h5'

這裡設定項如果 _confg 結束的變數就是修改 manifest.json

const path = require('path')
const fs = require('fs')
const env = require('./modules/readEnv')
const parseManifest = require('./modules/manifest')
const config = env();

function writeManifest() {
	const _global = {}
	for (let key in config) {
		if (key.includes('_config')) {
			const k = key.slice(0, -7)
			_global[k] = config[key]
		}
	}
	parseManifest(_global);
}

命令列

準備工作完成後,可以編寫對應的命令,來簡化我們的操作;

	"scripts": {
		"build": "cli publish --platform h5 --project test-h5",
		"build:config:test": "node ./deploy/index --mode=test",
		"build:config:prod": "node ./deploy/index --mode=prod",
		"build:prod": "npm run build:config:prod && npm run build",
		"deploy:test": "npm run build:config:test && npm run build && fd-cli"
	},

&& 符號是序列命令;& 是並行命令,其中 fd-cli 是個部署命令,也是我以前基於業務需要開發的一個前端簡易部署命令。

其他

這裡只針對 H5 端做了處理,如果需要做多平臺,也可以在命令列後面接不同平臺引數,然後在部署打包前處理好邏輯;比如在打包前根據自己定義的環境變數新增引數

// vue.config.js
const webpack = require('webpack')

// 生成不同環境不同平臺的設定
const config = require('./config')

module.exports = {
  chainWebpack: config => {
    config
      .plugin('define')
      .tap(args => {
        // config.VUE_APP_TEST
        for(let key in config) {
            args[0]['process.env'][key] = `"${config.VUE_APP_TEST}"`
        }
        return args
      })
  }
}

總結

在開發階段完成後,需要特別注意一些重複的步驟或者是需要手動修改的操作,只要是手動修改,就會增加上線分險,特別是後來者接受專案的時候。當然也要檔案齊全

相關原始碼:地址

到此這篇關於uni-app多環境部署解決的文章就介紹到這了,更多相關uni-app多環境部署內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com