Merge branch 'release/test' of http://8.163.30.128:10082/html/pda-overseas-uniapp into release/test
This commit is contained in:
@@ -54,6 +54,8 @@ npm run build:app
|
||||
|
||||
Android App 启动后会读取 `VITE_PDA_UPDATE_URL` 并检查海外 PDA 的独立更新通道,员工也可在“个人中心 → 检查更新”手动触发;H5 仅展示 App 操作提示,不执行更新。更新服务接收 `appid`、`platform`、`appVersion`、`appVersionCode`、`wgtVersion` 查询参数,无更新返回 `{ "update": false }`,有更新返回:
|
||||
|
||||
HBuilderX 真机调试及标准基座使用当前工程 `src/manifest.json` 中的 AppID、版本名和版本码模拟更新检查,避免把 HBuilderX 基座版本作为业务版本上报;正式 APK 仍使用实际安装包版本码及独立的 WGT 资源版本。调试检查同样只读取后台已发布版本,上传草稿不会触发更新;调试基座不能代替正式 APK 的覆盖安装与签名验收。
|
||||
|
||||
```json
|
||||
{
|
||||
"update": true,
|
||||
|
||||
+61
-13
@@ -1,3 +1,5 @@
|
||||
import appManifest from '@/manifest.json'
|
||||
|
||||
const updateEndpoint = String(import.meta.env.VITE_PDA_UPDATE_URL || '').trim()
|
||||
|
||||
let checking = false
|
||||
@@ -15,20 +17,40 @@ function getRuntimeInfo() {
|
||||
return
|
||||
}
|
||||
|
||||
// 标准真机基座的版本属于 HBuilderX;调试更新按当前工程版本模拟。
|
||||
const debugBase = import.meta.env.DEV || uni.getAppBaseInfo().packageName === 'io.dcloud.HBuilder'
|
||||
const runtime = {
|
||||
appid: String((debugBase ? appManifest.appid : plus.runtime.appid) || ''),
|
||||
appVersion: String((debugBase ? appManifest.versionName : plus.runtime.version) || ''),
|
||||
appVersionCode: Number(debugBase ? appManifest.versionCode : plus.runtime.versionCode)
|
||||
}
|
||||
if (!runtime.appid || !runtime.appVersion || !Number.isInteger(runtime.appVersionCode) || runtime.appVersionCode < 1) {
|
||||
reject(new Error('无法读取当前应用版本,请重新运行 App'))
|
||||
return
|
||||
}
|
||||
if (debugBase) {
|
||||
resolve({ ...runtime, wgtVersion: runtime.appVersion })
|
||||
return
|
||||
}
|
||||
|
||||
// 正式 APK 始终保留原生基座版本码,WGT 升级只改变资源版本。
|
||||
plus.runtime.getProperty(plus.runtime.appid, (properties) => {
|
||||
resolve({
|
||||
appid: plus.runtime.appid,
|
||||
appVersion: String(plus.runtime.version || ''),
|
||||
appVersionCode: Number(plus.runtime.versionCode || 0),
|
||||
wgtVersion: String(properties?.version || plus.runtime.version || '')
|
||||
})
|
||||
resolve({ ...runtime, wgtVersion: String(properties?.version || runtime.appVersion) })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function normalizeUpdate(payload, runtime) {
|
||||
const value = payload && typeof payload === 'object' ? payload : {}
|
||||
if (value.update !== true) return null
|
||||
if ('code' in value && String(value.code) !== '200') {
|
||||
const error = new Error(String(value.message || '检查更新失败,请稍后重试'))
|
||||
error.code = value.code
|
||||
error.requestId = value.requestId
|
||||
error.traceId = value.traceId
|
||||
throw error
|
||||
}
|
||||
if (typeof value.update !== 'boolean') throw new Error('更新服务返回了无效的版本信息')
|
||||
if (!value.update) return null
|
||||
|
||||
if (value.appid !== runtime.appid) throw new Error('更新包与当前应用不匹配')
|
||||
const packageType = String(value.packageType || '').toLowerCase()
|
||||
@@ -110,20 +132,45 @@ function downloadUpdate(update) {
|
||||
})
|
||||
}
|
||||
|
||||
function prepareUpdateFile(filePath, update) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fail = (cause) => {
|
||||
const error = new Error('更新包文件准备失败,请重新下载')
|
||||
error.stage = 'prepare'
|
||||
error.code = cause?.code
|
||||
reject(error)
|
||||
}
|
||||
// 下载接口以 /package 结尾,临时文件可能没有安装器要求的扩展名。
|
||||
const filename = `overseas-pda-${update.versionName}-${Date.now()}.${update.packageType}`
|
||||
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
|
||||
entry.getParent((parent) => {
|
||||
entry.moveTo(parent, filename, (file) => resolve(file.toLocalURL()), fail)
|
||||
}, fail)
|
||||
}, fail)
|
||||
})
|
||||
}
|
||||
|
||||
function installUpdate(filePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
plus.runtime.install(
|
||||
filePath,
|
||||
{ force: false },
|
||||
resolve,
|
||||
() => reject(new Error('更新包安装失败,请重新下载'))
|
||||
(cause) => {
|
||||
const code = cause?.code == null ? '' : `(${cause.code})`
|
||||
const reason = String(cause?.message || '请重新下载后重试')
|
||||
const error = new Error(`更新包安装失败${code}:${reason}`)
|
||||
error.stage = 'install'
|
||||
error.code = cause?.code
|
||||
reject(error)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function showFailure(error, mandatory) {
|
||||
const message = error?.message || '检查更新失败,请稍后重试'
|
||||
if (!mandatory) {
|
||||
if (!mandatory && error?.stage !== 'install' && error?.stage !== 'prepare') {
|
||||
uni.showToast({ title: message, icon: 'none', duration: 3000 })
|
||||
return Promise.resolve(false)
|
||||
}
|
||||
@@ -132,9 +179,9 @@ function showFailure(error, mandatory) {
|
||||
uni.showModal({
|
||||
title: '更新失败',
|
||||
content: message,
|
||||
confirmText: '重新尝试',
|
||||
confirmText: mandatory ? '重新尝试' : '知道了',
|
||||
showCancel: false,
|
||||
complete: () => resolve(true)
|
||||
complete: () => resolve(mandatory)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -145,7 +192,8 @@ async function runUpdate(update) {
|
||||
|
||||
try {
|
||||
const filePath = await downloadUpdate(update)
|
||||
await installUpdate(filePath)
|
||||
const installPath = await prepareUpdateFile(filePath, update)
|
||||
await installUpdate(installPath)
|
||||
if (update.packageType === 'wgt') {
|
||||
uni.showModal({
|
||||
title: '更新完成',
|
||||
@@ -184,7 +232,7 @@ export async function checkForAppUpdate({ manual = false } = {}) {
|
||||
})
|
||||
if (response.statusCode !== 200) throw new Error('更新服务暂时不可用')
|
||||
|
||||
const update = normalizeUpdate(response.data?.data ?? response.data, runtime)
|
||||
const update = normalizeUpdate(response.data, runtime)
|
||||
if (update && isNewerUpdate(update, runtime)) {
|
||||
await runUpdate(update)
|
||||
} else if (manual) {
|
||||
|
||||
@@ -1,9 +1,82 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import test from 'node:test'
|
||||
import { runInNewContext } from 'node:vm'
|
||||
|
||||
const read = (path) => readFile(new URL(path, import.meta.url), 'utf8')
|
||||
|
||||
async function createUpdater({ development = true, packageName = 'io.dcloud.HBuilder',
|
||||
manifest = { appid: '__UNI__936D079', versionName: '0.0.4', versionCode: 4 },
|
||||
runtime = {}, resourceVersion = '0.0.4', response = { update: false }, acceptUpdate = false,
|
||||
downloadResult = { statusCode: 200, tempFilePath: '_doc/temp/download/package' },
|
||||
fileErrorAt, installError } = {}) {
|
||||
const calls = { requests: [], modals: [], toasts: [], downloads: [], moves: [], installs: [], restarts: 0 }
|
||||
const source = (await read('../src/utils/app-update.js'))
|
||||
.replace(/^import .*$/gm, '')
|
||||
.replaceAll('import.meta.env.VITE_PDA_UPDATE_URL', 'updateUrl')
|
||||
.replaceAll('import.meta.env.DEV', 'development')
|
||||
.replace('export async function checkForAppUpdate', 'async function checkForAppUpdate')
|
||||
const updater = runInNewContext(`${source}\n;({ getRuntimeInfo, checkForAppUpdate })`, {
|
||||
appManifest: manifest, development, updateUrl: 'https://updates.example.test/pda/overseas/latest',
|
||||
plus: {
|
||||
io: {
|
||||
resolveLocalFileSystemURL(path, success, fail) {
|
||||
const fileError = { code: 10, message: 'file operation failed' }
|
||||
if (fileErrorAt === 'resolve') return fail(fileError)
|
||||
const parent = {}
|
||||
success({
|
||||
getParent(success, fail) { fileErrorAt === 'parent' ? fail(fileError) : success(parent) },
|
||||
moveTo(destination, name, success, fail) {
|
||||
assert.equal(destination, parent)
|
||||
calls.moves.push({ path, name })
|
||||
if (fileErrorAt === 'move') return fail(fileError)
|
||||
success({ toLocalURL: () => `_doc/temp/download/${name}` })
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
runtime: { appid: 'HBuilder', version: '5.24.0', versionCode: 52400,
|
||||
getProperty(_appid, callback) { callback({ version: resourceVersion }) },
|
||||
install(path, options, success, fail) {
|
||||
calls.installs.push({ path, options })
|
||||
if (installError) return fail(installError)
|
||||
if (!/\.(wgt|apk)$/.test(path)) return fail({ code: -1201, message: 'WGT/WGTU文件格式错误' })
|
||||
success()
|
||||
},
|
||||
restart() { calls.restarts += 1 }, ...runtime
|
||||
}
|
||||
},
|
||||
uni: {
|
||||
getAppBaseInfo: () => ({ packageName }),
|
||||
request(options) {
|
||||
calls.requests.push(options)
|
||||
options.success({ statusCode: 200, data: typeof response === 'function' ? response(options.data) : response })
|
||||
},
|
||||
downloadFile(options) {
|
||||
calls.downloads.push(options)
|
||||
options.success(downloadResult)
|
||||
options.complete()
|
||||
return { onProgressUpdate() {} }
|
||||
},
|
||||
showLoading() {}, hideLoading() {},
|
||||
showModal(options) {
|
||||
calls.modals.push(options)
|
||||
options.success?.({ confirm: acceptUpdate && options.confirmText === '立即更新' })
|
||||
options.complete?.()
|
||||
},
|
||||
showToast(options) { calls.toasts.push(options) }
|
||||
}
|
||||
})
|
||||
return { ...updater, calls }
|
||||
}
|
||||
|
||||
const publishedApk = { update: true, appid: '__UNI__936D079', packageType: 'apk',
|
||||
versionName: '0.0.5', versionCode: 5, minAppVersionCode: 5,
|
||||
downloadUrl: 'https://updates.example.test/overseas-0.0.5.apk', mandatory: false }
|
||||
|
||||
const publishedWgt = { ...publishedApk, packageType: 'wgt', minAppVersionCode: 4,
|
||||
downloadUrl: 'https://updates.example.test/overseas-0.0.5.wgt', releaseNotes: '更新测试' }
|
||||
|
||||
test('App-Plus checks the independent overseas update channel after launch', async () => {
|
||||
const [app, updater, env] = await Promise.all([
|
||||
read('../src/App.vue'),
|
||||
@@ -53,3 +126,148 @@ test('overseas profile exposes manual App update checking and the runtime versio
|
||||
assert.match(profile, /checkForAppUpdate\(\{ manual: true \}\)/)
|
||||
assert.match(profile, /#ifndef APP-PLUS[\s\S]*?请在 PDA App 中检查更新/)
|
||||
})
|
||||
|
||||
test('HBuilderX 0.0.4 checks the project version and offers a published 0.0.5 APK', async () => {
|
||||
const updater = await createUpdater({ response: query => query.appVersionCode < 5 ? publishedApk : { update: false } })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
const query = updater.calls.requests[0].data
|
||||
assert.equal(query.appid, '__UNI__936D079')
|
||||
assert.equal(query.appVersion, '0.0.4')
|
||||
assert.equal(query.appVersionCode, 4)
|
||||
assert.equal(query.wgtVersion, '0.0.4')
|
||||
assert.equal(updater.calls.modals[0]?.title, '发现更新 0.0.5')
|
||||
assert.equal(updater.calls.toasts.length, 0)
|
||||
})
|
||||
|
||||
test('standard HBuilder base uses project versions when running production WGT resources', async () => {
|
||||
const updater = await createUpdater({ development: false })
|
||||
const info = await updater.getRuntimeInfo()
|
||||
assert.equal(info.appid, '__UNI__936D079')
|
||||
assert.equal(info.appVersionCode, 4)
|
||||
assert.equal(info.appVersion, '0.0.4')
|
||||
})
|
||||
|
||||
test('released APK keeps its native base version after a WGT version increase', async () => {
|
||||
const updater = await createUpdater({ development: false, packageName: 'com.baiyuelogistics.pda.overseas',
|
||||
manifest: { appid: '__UNI__936D079', versionName: '0.0.5', versionCode: 5 },
|
||||
runtime: { appid: '__UNI__936D079', version: '0.0.4', versionCode: 4 }, resourceVersion: '0.0.5' })
|
||||
const info = await updater.getRuntimeInfo()
|
||||
assert.equal(info.appVersionCode, 4)
|
||||
assert.equal(info.appVersion, '0.0.4')
|
||||
assert.equal(info.wgtVersion, '0.0.5')
|
||||
})
|
||||
|
||||
test('HBuilderX 0.0.4 can detect a compatible published 0.0.5 WGT', async () => {
|
||||
const updater = await createUpdater({ response: publishedWgt })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.requests[0].data.appVersionCode, 4)
|
||||
assert.equal(updater.calls.requests[0].data.wgtVersion, '0.0.4')
|
||||
assert.equal(updater.calls.modals[0]?.title, '发现更新 0.0.5')
|
||||
assert.equal(updater.calls.modals[0]?.content, '更新测试')
|
||||
})
|
||||
|
||||
test('released APK 0.0.4 shows the published 0.0.5 WGT release notes', async () => {
|
||||
const updater = await createUpdater({ development: false, packageName: 'com.baiyuelogistics.pda.overseas',
|
||||
runtime: { appid: '__UNI__936D079', version: '0.0.4', versionCode: 4 }, response: publishedWgt })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.modals[0]?.title, '发现更新 0.0.5')
|
||||
assert.equal(updater.calls.modals[0]?.content, '更新测试')
|
||||
})
|
||||
|
||||
test('an APK 0.0.4 with WGT 0.0.5 does not offer that WGT again', async () => {
|
||||
const updater = await createUpdater({ development: false, packageName: 'com.baiyuelogistics.pda.overseas',
|
||||
runtime: { appid: '__UNI__936D079', version: '0.0.4', versionCode: 4 },
|
||||
resourceVersion: '0.0.5', response: publishedWgt })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.modals.length, 0)
|
||||
assert.equal(updater.calls.toasts[0]?.title, '当前已是最新版本')
|
||||
})
|
||||
|
||||
test('a WGT requiring APK 5 is rejected on a released APK 4 after resource updates', async () => {
|
||||
const updater = await createUpdater({ development: false, packageName: 'com.baiyuelogistics.pda.overseas',
|
||||
manifest: { appid: '__UNI__936D079', versionName: '0.0.5', versionCode: 5 },
|
||||
runtime: { appid: '__UNI__936D079', version: '0.0.4', versionCode: 4 },
|
||||
resourceVersion: '0.0.5', response: { ...publishedWgt, versionName: '0.0.6', minAppVersionCode: 5 } })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.modals.length, 0)
|
||||
assert.equal(updater.calls.toasts[0]?.title, '当前安装包不支持此热更新,请安装新版 APK')
|
||||
})
|
||||
|
||||
test('an unreadable native APK version is reported instead of claiming the latest version', async () => {
|
||||
const updater = await createUpdater({ development: false, packageName: 'com.baiyuelogistics.pda.overseas',
|
||||
runtime: { appid: '__UNI__936D079', version: '0.0.4', versionCode: 0 } })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.requests.length, 0)
|
||||
assert.equal(updater.calls.toasts[0]?.title, '无法读取当前应用版本,请重新运行 App')
|
||||
})
|
||||
|
||||
test('update service business errors are shown instead of claiming the latest version', async () => {
|
||||
const updater = await createUpdater({ response: { code: 'S0503', message: 'PDA 发布通道未初始化', data: null } })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.toasts[0]?.title, 'PDA 发布通道未初始化')
|
||||
assert.equal(updater.calls.modals.length, 0)
|
||||
})
|
||||
|
||||
test('invalid update responses are rejected instead of claiming the latest version', async () => {
|
||||
const updater = await createUpdater({ response: {} })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.toasts[0]?.title, '更新服务返回了无效的版本信息')
|
||||
})
|
||||
|
||||
test('unpublished versions remain unavailable to the device', async () => {
|
||||
const updater = await createUpdater({ response: { update: false } })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.modals.length, 0)
|
||||
assert.equal(updater.calls.toasts[0]?.title, '当前已是最新版本')
|
||||
})
|
||||
|
||||
test('a downloaded extensionless WGT is renamed before install and restarts on success', async () => {
|
||||
const updater = await createUpdater({ response: publishedWgt, acceptUpdate: true })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.downloads[0]?.url, publishedWgt.downloadUrl)
|
||||
assert.equal(updater.calls.moves[0]?.path, '_doc/temp/download/package')
|
||||
assert.match(updater.calls.moves[0]?.name, /^overseas-pda-0\.0\.5-\d+\.wgt$/)
|
||||
assert.equal(updater.calls.installs[0]?.path, `_doc/temp/download/${updater.calls.moves[0].name}`)
|
||||
assert.equal(updater.calls.installs[0]?.options.force, false)
|
||||
assert.equal(updater.calls.modals[1]?.title, '更新完成')
|
||||
assert.equal(updater.calls.restarts, 1)
|
||||
})
|
||||
|
||||
test('an extensionless APK receives the APK suffix and does not restart as a WGT', async () => {
|
||||
const updater = await createUpdater({ response: publishedApk, acceptUpdate: true })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.match(updater.calls.installs[0]?.path, /\.apk$/)
|
||||
assert.equal(updater.calls.installs[0]?.options.force, false)
|
||||
assert.equal(updater.calls.restarts, 0)
|
||||
})
|
||||
|
||||
test('native installation errors remain visible with their actual reason and code', async () => {
|
||||
const updater = await createUpdater({ response: publishedWgt, acceptUpdate: true,
|
||||
installError: { code: -1205, message: 'WGT安装包中manifest.json文件的version版本不匹配' } })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.modals[1]?.title, '更新失败')
|
||||
assert.match(updater.calls.modals[1]?.content, /-1205/)
|
||||
assert.match(updater.calls.modals[1]?.content, /version版本不匹配/)
|
||||
assert.equal(updater.calls.restarts, 0)
|
||||
assert.equal(updater.calls.installs.length, 1)
|
||||
})
|
||||
|
||||
test('unreadable or unrenamable downloads never reach the native installer', async () => {
|
||||
for (const fileErrorAt of ['resolve', 'parent', 'move']) {
|
||||
const updater = await createUpdater({ response: publishedWgt, acceptUpdate: true, fileErrorAt })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.installs.length, 0, fileErrorAt)
|
||||
assert.equal(updater.calls.restarts, 0, fileErrorAt)
|
||||
assert.equal(updater.calls.modals[1]?.title, '更新失败', fileErrorAt)
|
||||
assert.match(updater.calls.modals[1]?.content, /更新包文件准备失败/, fileErrorAt)
|
||||
}
|
||||
})
|
||||
|
||||
test('an unsuccessful HTTP download never prepares or installs an update', async () => {
|
||||
const updater = await createUpdater({ response: publishedWgt, acceptUpdate: true,
|
||||
downloadResult: { statusCode: 404, tempFilePath: '_doc/temp/download/package' } })
|
||||
await updater.checkForAppUpdate({ manual: true })
|
||||
assert.equal(updater.calls.moves.length, 0)
|
||||
assert.equal(updater.calls.installs.length, 0)
|
||||
assert.match(updater.calls.toasts[0]?.title, /下载失败(404)/)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import test from 'node:test'
|
||||
import { runInNewContext } from 'node:vm'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFile, readdir } from 'node:fs/promises'
|
||||
import { mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url'
|
||||
import { loadEnv } from 'vite'
|
||||
const read = path => readFile(new URL(path, import.meta.url), 'utf8')
|
||||
test('PDA H5 has no container publishing entry', async () => {
|
||||
const files = await readdir(new URL('../deploy/', import.meta.url))
|
||||
@@ -28,10 +32,12 @@ test('host nginx serves uploaded files and proxies only the API prefix', async (
|
||||
test('only H5 production overrides the toolchain asset base', async () => {
|
||||
const source = (await read('../vite.config.js'))
|
||||
.replace(/^import .*$/gm, '')
|
||||
.replaceAll('import.meta.url', 'configUrl')
|
||||
.replace('export default ', '')
|
||||
for (const platform of ['h5', 'app', 'app-plus', 'app-harmony', undefined]) {
|
||||
for (const mode of ['production', 'development']) {
|
||||
const factory = runInNewContext(source, {
|
||||
URL, fileURLToPath, configUrl: new URL('../vite.config.js', import.meta.url).href,
|
||||
defineConfig: value => value,
|
||||
loadEnv: () => ({}),
|
||||
uni: () => ({}),
|
||||
@@ -45,8 +51,10 @@ test('only H5 production overrides the toolchain asset base', async () => {
|
||||
})
|
||||
|
||||
test('H5 proxy uses the shared gateway prefix and preserves API suffixes', async () => {
|
||||
const source = (await read('../vite.config.js')).replace(/^import .*$/gm, '').replace('export default ', '')
|
||||
const source = (await read('../vite.config.js')).replace(/^import .*$/gm, '')
|
||||
.replaceAll('import.meta.url', 'configUrl').replace('export default ', '')
|
||||
const factory = runInNewContext(source, {
|
||||
URL, fileURLToPath, configUrl: new URL('../vite.config.js', import.meta.url).href,
|
||||
defineConfig: value => value, loadEnv: () => ({ API_PROXY_TARGET: 'https://gateway.example.com' }),
|
||||
uni: () => ({}), process: { env: { UNI_PLATFORM: 'h5' }, cwd: () => '/project' }
|
||||
})
|
||||
@@ -57,3 +65,24 @@ test('H5 proxy uses the shared gateway prefix and preserves API suffixes', async
|
||||
assert.equal(proxy['/gateway-api'].rewrite(`/gateway-api${suffix}`), `/api${suffix}`)
|
||||
}
|
||||
})
|
||||
|
||||
test('App update configuration loads from the project when HBuilderX starts elsewhere', async t => {
|
||||
const fixturePrefix = join(tmpdir(), 'overseas-pda-env-')
|
||||
const fixtureDir = await mkdtemp(fixturePrefix)
|
||||
assert.ok(resolve(fixtureDir).startsWith(resolve(fixturePrefix)))
|
||||
t.after(() => rm(fixtureDir, { recursive: true, force: true }))
|
||||
const endpoint = 'https://updates.example.test/pda/overseas/latest'
|
||||
await writeFile(join(fixtureDir, '.env.local'), `VITE_PDA_UPDATE_URL=${endpoint}\n`)
|
||||
const source = (await read('../vite.config.js')).replace(/^import .*$/gm, '')
|
||||
.replaceAll('import.meta.url', 'configUrl').replace('export default ', '')
|
||||
const factory = runInNewContext(source, {
|
||||
URL, fileURLToPath, configUrl: pathToFileURL(join(fixtureDir, 'vite.config.js')).href,
|
||||
defineConfig: value => value, loadEnv, uni: () => ({}),
|
||||
process: { env: { UNI_PLATFORM: 'app' }, cwd: () => join(fixtureDir, 'HBuilderX') }
|
||||
})
|
||||
for (const mode of ['development', 'production']) {
|
||||
const config = factory({ mode })
|
||||
assert.equal(JSON.parse(config.define['import.meta.env.VITE_PDA_UPDATE_URL']), endpoint)
|
||||
assert.equal(resolve(config.envDir), resolve(fixtureDir))
|
||||
}
|
||||
})
|
||||
|
||||
+5
-1
@@ -1,5 +1,8 @@
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import uni from '@dcloudio/vite-plugin-uni'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const projectDir = fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
function loggedProxy(name, options) {
|
||||
return {
|
||||
@@ -24,9 +27,10 @@ function loggedProxy(name, options) {
|
||||
}
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
const env = loadEnv(mode, projectDir, '')
|
||||
const apiTarget = env.API_PROXY_TARGET || 'http://127.0.0.1:9000'
|
||||
return {
|
||||
envDir: projectDir,
|
||||
base: process.env.UNI_PLATFORM === 'h5' && mode === 'production' ? '/' : undefined,
|
||||
plugins: [uni()],
|
||||
define: {
|
||||
|
||||
Reference in New Issue
Block a user