mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp.git
synced 2026-08-06 02:47:25 +08:00
fix: 修复 App 端 MQTT 运行时兼容问题
- 锁定 MQTT 版本为 5.15.1 - 为 AbortController、AbortSignal 和 navigator.language 添加兼容补丁 - 新增 MQTT App 运行时测试
This commit is contained in:
173
scripts/patch-mqtt-abort.js
Normal file
173
scripts/patch-mqtt-abort.js
Normal file
@@ -0,0 +1,173 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const root = path.join(__dirname, '../node_modules/mqtt/dist')
|
||||
|
||||
const marker = '_MqttAbortControllerFallback'
|
||||
const navigatorFallback = '"zh-CN.UTF-8"'
|
||||
|
||||
const esmOriginalPattern =
|
||||
/var\{AbortController:([A-Za-z_$][\w$]*),AbortSignal:([A-Za-z_$][\w$]*)\}=typeof self<"u"\?self:typeof window<"u"\?window:void 0;/
|
||||
const esmOldPatchPattern =
|
||||
/var _mqttGlobal=typeof globalThis<"u"\?globalThis:typeof self<"u"\?self:typeof window<"u"\?window:typeof global<"u"\?global:\{\};var\{AbortController:([A-Za-z_$][\w$]*),AbortSignal:([A-Za-z_$][\w$]*)\}=_mqttGlobal;/
|
||||
|
||||
function createEsmReplacement(controllerName, signalName) {
|
||||
return `var _mqttGlobal=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{};var _MqttAbortSignalFallback=class{constructor(){this.aborted=!1;this.reason=void 0;this.onabort=null;this._listeners=[]}addEventListener(e,t,r){if(e==="abort"&&t){this._listeners.push({listener:t,once:!!(r&&r.once)})}}removeEventListener(e,t){if(e==="abort"){this._listeners=this._listeners.filter(r=>r.listener!==t)}}dispatchEvent(e){if(!e||e.type!=="abort")return!0;var t=this._listeners.slice();this._listeners=this._listeners.filter(r=>!r.once);for(var r of t){try{typeof r.listener==="function"?r.listener.call(this,e):r.listener&&typeof r.listener.handleEvent==="function"&&r.listener.handleEvent(e)}catch(n){}}return!0}throwIfAborted(){if(this.aborted)throw this.reason||new Error("Aborted")}};var ${marker}=class{constructor(){this.signal=new _MqttAbortSignalFallback}abort(e){if(this.signal.aborted)return;this.signal.aborted=!0;this.signal.reason=e;var t={type:"abort",target:this.signal};if(typeof this.signal.onabort==="function"){try{this.signal.onabort.call(this.signal,t)}catch(r){}}this.signal.dispatchEvent(t)}};var ${controllerName}=_mqttGlobal.AbortController||${marker};var ${signalName}=_mqttGlobal.AbortSignal||_MqttAbortSignalFallback;typeof _mqttGlobal.AbortController>"u"&&(_mqttGlobal.AbortController=${controllerName});typeof _mqttGlobal.AbortSignal>"u"&&(_mqttGlobal.AbortSignal=${signalName});`
|
||||
}
|
||||
|
||||
const jsOriginalPattern =
|
||||
/var \{ AbortController, AbortSignal \} = typeof self !== "undefined" \? self : typeof window !== "undefined" \? window : \(\s*\/\* otherwise \*\/\s*void 0\s*\);/
|
||||
const jsOldPatchPattern =
|
||||
/var \{ AbortController, AbortSignal \} = typeof globalThis !== "undefined" \? globalThis : typeof self !== "undefined" \? self : typeof window !== "undefined" \? window : typeof global !== "undefined" \? global : \(\s*\/\* otherwise \*\/\s*(?:void 0|\{\})\s*\);/
|
||||
|
||||
const jsReplacement = `var _mqttGlobal = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {};
|
||||
var _MqttAbortSignalFallback = class {
|
||||
constructor() {
|
||||
this.aborted = false;
|
||||
this.reason = void 0;
|
||||
this.onabort = null;
|
||||
this._listeners = [];
|
||||
}
|
||||
addEventListener(type, listener, options) {
|
||||
if (type === "abort" && listener) this._listeners.push({ listener, once: !!(options && options.once) });
|
||||
}
|
||||
removeEventListener(type, listener) {
|
||||
if (type === "abort") this._listeners = this._listeners.filter((entry) => entry.listener !== listener);
|
||||
}
|
||||
dispatchEvent(event) {
|
||||
if (!event || event.type !== "abort") return true;
|
||||
const entries = this._listeners.slice();
|
||||
this._listeners = this._listeners.filter((entry) => !entry.once);
|
||||
for (const entry of entries) {
|
||||
try {
|
||||
if (typeof entry.listener === "function") entry.listener.call(this, event);
|
||||
else if (entry.listener && typeof entry.listener.handleEvent === "function") entry.listener.handleEvent(event);
|
||||
} catch (error) {}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
throwIfAborted() {
|
||||
if (this.aborted) throw this.reason || new Error("Aborted");
|
||||
}
|
||||
};
|
||||
var ${marker} = class {
|
||||
constructor() {
|
||||
this.signal = new _MqttAbortSignalFallback();
|
||||
}
|
||||
abort(reason) {
|
||||
if (this.signal.aborted) return;
|
||||
this.signal.aborted = true;
|
||||
this.signal.reason = reason;
|
||||
const event = { type: "abort", target: this.signal };
|
||||
if (typeof this.signal.onabort === "function") {
|
||||
try { this.signal.onabort.call(this.signal, event); } catch (error) {}
|
||||
}
|
||||
this.signal.dispatchEvent(event);
|
||||
}
|
||||
};
|
||||
var AbortController = _mqttGlobal.AbortController || ${marker};
|
||||
var AbortSignal = _mqttGlobal.AbortSignal || _MqttAbortSignalFallback;
|
||||
if (typeof _mqttGlobal.AbortController === "undefined") _mqttGlobal.AbortController = AbortController;
|
||||
if (typeof _mqttGlobal.AbortSignal === "undefined") _mqttGlobal.AbortSignal = AbortSignal;`
|
||||
|
||||
function isEsmPatched(content) {
|
||||
return content.includes(marker)
|
||||
}
|
||||
|
||||
function isJsPatched(content) {
|
||||
return content.includes(marker)
|
||||
}
|
||||
|
||||
function patchEsmFile(file) {
|
||||
const filePath = path.join(root, file)
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.log(`skip ${file} (missing)`)
|
||||
return
|
||||
}
|
||||
|
||||
let content = fs.readFileSync(filePath, 'utf8')
|
||||
if (isEsmPatched(content)) {
|
||||
console.log(`skip ${file} (already patched)`)
|
||||
return
|
||||
}
|
||||
|
||||
const match = content.match(esmOriginalPattern) || content.match(esmOldPatchPattern)
|
||||
if (match) {
|
||||
content = content.replace(match[0], createEsmReplacement(match[1], match[2]))
|
||||
fs.writeFileSync(filePath, content)
|
||||
console.log(`patched ${file} (embedded AbortController fallback)`)
|
||||
return
|
||||
}
|
||||
|
||||
throw new Error(`Unable to patch ${file}: unsupported mqtt bundle format`)
|
||||
}
|
||||
|
||||
function patchJsFile() {
|
||||
const jsPath = path.join(root, 'mqtt.js')
|
||||
if (!fs.existsSync(jsPath)) {
|
||||
console.log('skip mqtt.js (missing)')
|
||||
return
|
||||
}
|
||||
|
||||
let jsContent = fs.readFileSync(jsPath, 'utf8')
|
||||
if (isJsPatched(jsContent)) {
|
||||
console.log('skip mqtt.js (already patched)')
|
||||
return
|
||||
}
|
||||
|
||||
const match = jsContent.match(jsOriginalPattern) || jsContent.match(jsOldPatchPattern)
|
||||
if (match) {
|
||||
jsContent = jsContent.replace(match[0], jsReplacement)
|
||||
fs.writeFileSync(jsPath, jsContent)
|
||||
console.log('patched mqtt.js (embedded AbortController fallback)')
|
||||
return
|
||||
}
|
||||
|
||||
throw new Error('Unable to patch mqtt.js: unsupported mqtt bundle format')
|
||||
}
|
||||
|
||||
function patchNavigatorLanguage(file) {
|
||||
const filePath = path.join(root, file)
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.log(`skip ${file} navigator patch (missing)`)
|
||||
return
|
||||
}
|
||||
|
||||
let content = fs.readFileSync(filePath, 'utf8')
|
||||
const unsafeMinified = 'LANG:navigator.language+".UTF-8"'
|
||||
const unsafePretty = 'LANG: navigator.language + ".UTF-8"'
|
||||
const safeMinified =
|
||||
`LANG:typeof navigator<"u"&&navigator.language?navigator.language+".UTF-8":${navigatorFallback}`
|
||||
const safePretty =
|
||||
`LANG: typeof navigator !== "undefined" && navigator.language ? navigator.language + ".UTF-8" : ${navigatorFallback}`
|
||||
|
||||
if (content.includes(unsafeMinified)) {
|
||||
content = content.replaceAll(unsafeMinified, safeMinified)
|
||||
fs.writeFileSync(filePath, content)
|
||||
console.log(`patched ${file} (navigator.language fallback)`)
|
||||
return
|
||||
}
|
||||
|
||||
if (content.includes(unsafePretty)) {
|
||||
content = content.replaceAll(unsafePretty, safePretty)
|
||||
fs.writeFileSync(filePath, content)
|
||||
console.log(`patched ${file} (navigator.language fallback)`)
|
||||
return
|
||||
}
|
||||
|
||||
if (content.includes(safeMinified) || content.includes(safePretty)) {
|
||||
console.log(`skip ${file} navigator patch (already patched)`)
|
||||
return
|
||||
}
|
||||
|
||||
throw new Error(`Unable to patch navigator.language in ${file}: unsupported mqtt bundle format`)
|
||||
}
|
||||
|
||||
if (!fs.existsSync(root)) {
|
||||
console.log('skip mqtt patch (mqtt dist not installed yet)')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
;['mqtt.esm.js', 'mqtt.min.js'].forEach(patchEsmFile)
|
||||
patchJsFile()
|
||||
;['mqtt.esm.js', 'mqtt.min.js', 'mqtt.js'].forEach(patchNavigatorLanguage)
|
||||
Reference in New Issue
Block a user