xpe 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/kernel/iframe.js +34 -8
- package/dist/kernel/index.js +2 -6
- package/dist/kernel/proxy.js +11 -2
- package/dist/kernel/runtime-engine.d.ts +2 -0
- package/dist/kernel/runtime-fetch.d.ts +2 -0
- package/dist/kernel/runtime-fetch.js +14 -0
- package/dist/kernel/template.d.ts +2 -0
- package/dist/kernel/template.js +9 -1
- package/package.json +1 -1
package/dist/kernel/iframe.js
CHANGED
|
@@ -415,11 +415,11 @@ export function recoverShadowRootEventListeners(iframeWindow) {
|
|
|
415
415
|
rawRemoveEventListener.call(nextElement, listener.type, listener.callback, listener.options);
|
|
416
416
|
rawAddEventListener.call(nextElement, listener.type, listener.callback, listener.options);
|
|
417
417
|
});
|
|
418
|
-
recoverFrameworkEventInvokers(nextElement);
|
|
418
|
+
recoverFrameworkEventInvokers(nextElement, elementListenerList);
|
|
419
419
|
nextElement = walker.nextNode();
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
|
-
function recoverFrameworkEventInvokers(element) {
|
|
422
|
+
function recoverFrameworkEventInvokers(element, cachedListeners) {
|
|
423
423
|
if (element.nodeType !== Node.ELEMENT_NODE)
|
|
424
424
|
return;
|
|
425
425
|
Object.getOwnPropertySymbols(element)
|
|
@@ -435,6 +435,11 @@ function recoverFrameworkEventInvokers(element) {
|
|
|
435
435
|
const eventType = toDomEventType(key);
|
|
436
436
|
if (!eventType)
|
|
437
437
|
return;
|
|
438
|
+
// A tracked Vue invoker is already restored through its realm-safe
|
|
439
|
+
// callback. Adding the raw invoker as well executes one click twice.
|
|
440
|
+
if (cachedListeners?.some((listener) => listener.type === eventType && listener.handler === invoker)) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
438
443
|
rawRemoveEventListener.call(element, eventType, invoker);
|
|
439
444
|
rawAddEventListener.call(element, eventType, invoker);
|
|
440
445
|
});
|
|
@@ -669,6 +674,10 @@ function patchNodeEffect(iframeWindow) {
|
|
|
669
674
|
const rawAppendChild = iframeWindow.Node.prototype.appendChild;
|
|
670
675
|
const rawInsertBefore = iframeWindow.Node.prototype.insertBefore;
|
|
671
676
|
const rawRemoveChild = iframeWindow.Node.prototype.removeChild;
|
|
677
|
+
const hostAppendChild = window.Node.prototype.appendChild;
|
|
678
|
+
const hostInsertBefore = window.Node.prototype.insertBefore;
|
|
679
|
+
const hostRemoveChild = window.Node.prototype.removeChild;
|
|
680
|
+
const nodeOperation = (node, iframeOperation, hostOperation) => (window.Node.prototype.isPrototypeOf(node) ? hostOperation : iframeOperation);
|
|
672
681
|
iframeWindow.Node.prototype.getRootNode = function (options) {
|
|
673
682
|
const rootNode = rawGetRootNode.call(this, options);
|
|
674
683
|
if (rootNode === sandbox.shadowRoot)
|
|
@@ -677,13 +686,15 @@ function patchNodeEffect(iframeWindow) {
|
|
|
677
686
|
return rootNode;
|
|
678
687
|
};
|
|
679
688
|
iframeWindow.Node.prototype.appendChild = function (node) {
|
|
680
|
-
const
|
|
689
|
+
const operation = nodeOperation(node, rawAppendChild, hostAppendChild);
|
|
690
|
+
const res = operation.call(this, node);
|
|
681
691
|
patchElementEffect(node, iframeWindow);
|
|
682
692
|
recoverEventListeners(this, iframeWindow);
|
|
683
693
|
return res;
|
|
684
694
|
};
|
|
685
695
|
iframeWindow.Node.prototype.insertBefore = function (node, child) {
|
|
686
|
-
const
|
|
696
|
+
const operation = nodeOperation(node, rawInsertBefore, hostInsertBefore);
|
|
697
|
+
const res = operation.call(this, node, child);
|
|
687
698
|
patchElementEffect(node, iframeWindow);
|
|
688
699
|
recoverEventListeners(this, iframeWindow);
|
|
689
700
|
return res;
|
|
@@ -691,7 +702,8 @@ function patchNodeEffect(iframeWindow) {
|
|
|
691
702
|
iframeWindow.Node.prototype.removeChild = function (node) {
|
|
692
703
|
let res;
|
|
693
704
|
try {
|
|
694
|
-
|
|
705
|
+
const operation = nodeOperation(node, rawRemoveChild, hostRemoveChild);
|
|
706
|
+
res = operation.call(this, node);
|
|
695
707
|
}
|
|
696
708
|
catch (e) {
|
|
697
709
|
console.warn(`Failed to removeChild: ${node.nodeName.toLowerCase()} is not a child of ${this.nodeName.toLowerCase()}, try again with parentNode attribute. `);
|
|
@@ -727,7 +739,11 @@ function wrapInlineScriptWithSandbox(code) {
|
|
|
727
739
|
}
|
|
728
740
|
function createExecNextScriptContent() {
|
|
729
741
|
return [
|
|
730
|
-
|
|
742
|
+
// This helper is injected as a classic script repeatedly. `const` would
|
|
743
|
+
// create a global lexical binding and fail on the second queued script
|
|
744
|
+
// (notably when Vite's dev client precedes the app entry). `var` is
|
|
745
|
+
// intentionally used so each queue step remains re-entrant.
|
|
746
|
+
"var sandbox = window.__XPE_INTERNAL_SANDBOX__;",
|
|
731
747
|
"if(sandbox.execQueue && sandbox.execQueue.length){ sandbox.execQueue.shift()()}",
|
|
732
748
|
].join("");
|
|
733
749
|
}
|
|
@@ -923,7 +939,7 @@ export function syncIframeUrlToWindow(iframeWindow) {
|
|
|
923
939
|
* @param rawElement 原始的脚本
|
|
924
940
|
*/
|
|
925
941
|
export function insertScriptToIframe(scriptResult, iframeWindow, rawElement) {
|
|
926
|
-
const { src, module, content, crossorigin, crossoriginType, async, attrs, callback, onload } = scriptResult;
|
|
942
|
+
const { src, module, isEntry, content, crossorigin, crossoriginType, async, attrs, callback, onload } = scriptResult;
|
|
927
943
|
const sandbox = getActiveSandbox(iframeWindow);
|
|
928
944
|
const container = rawDocumentQuerySelector.call(iframeWindow.document, "head");
|
|
929
945
|
const execNextScript = () => {
|
|
@@ -1001,9 +1017,19 @@ export function insertScriptToIframe(scriptResult, iframeWindow, rawElement) {
|
|
|
1001
1017
|
scriptElement.onerror = afterExecScript;
|
|
1002
1018
|
}
|
|
1003
1019
|
container.appendChild(scriptElement);
|
|
1004
|
-
|
|
1020
|
+
// Vite injects an HMR client module before the actual application entry in
|
|
1021
|
+
// development HTML. That client keeps a long-lived websocket and may not
|
|
1022
|
+
// dispatch the module load event in the sandbox, so waiting for it would
|
|
1023
|
+
// prevent the real entry module from ever being inserted. It is not an
|
|
1024
|
+
// application lifecycle module and must not participate in the serial
|
|
1025
|
+
// entry gate.
|
|
1026
|
+
const isViteClientModule = module && /(?:^|\/)@vite\/client(?:$|\?)/.test(src);
|
|
1027
|
+
if (isOutlineScript && module && isEntry && !isViteClientModule) {
|
|
1005
1028
|
waitForModuleLifecycleReady(iframeWindow, afterExecScript);
|
|
1006
1029
|
}
|
|
1030
|
+
if (isOutlineScript && isViteClientModule) {
|
|
1031
|
+
afterExecScript();
|
|
1032
|
+
}
|
|
1007
1033
|
// 调用回调
|
|
1008
1034
|
callback?.(iframeWindow);
|
|
1009
1035
|
// 执行 hooks
|
package/dist/kernel/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { XpeRuntimeError, } from "../core/index.js";
|
|
2
|
+
import { createRuntimeFetch } from "./runtime-fetch.js";
|
|
2
3
|
let runtimeEngineModule;
|
|
3
4
|
let runtimeEngineModulePromise;
|
|
4
5
|
export function createRuntimeKernel() {
|
|
@@ -46,7 +47,7 @@ function toEnginePreloadOptions(manifest) {
|
|
|
46
47
|
alive: runtime.alive,
|
|
47
48
|
sync: runtime.sync,
|
|
48
49
|
prefix: toRuntimePrefix(runtime),
|
|
49
|
-
fetch:
|
|
50
|
+
fetch: createRuntimeFetch(runtime.credentials),
|
|
50
51
|
props: {
|
|
51
52
|
appCode: manifest.appCode,
|
|
52
53
|
manifest,
|
|
@@ -82,8 +83,3 @@ function toRuntimePrefix(runtime) {
|
|
|
82
83
|
return undefined;
|
|
83
84
|
return { [runtime.name]: runtime.basename };
|
|
84
85
|
}
|
|
85
|
-
function toRuntimeFetch(credentials) {
|
|
86
|
-
if (!credentials)
|
|
87
|
-
return undefined;
|
|
88
|
-
return (input, init) => window.fetch(input, { ...init, credentials: init?.credentials ?? credentials });
|
|
89
|
-
}
|
package/dist/kernel/proxy.js
CHANGED
|
@@ -76,7 +76,14 @@ export function proxyGenerator(iframe, urlElement, mainHostPath, appHostPath) {
|
|
|
76
76
|
return new Proxy(document[propKey], {
|
|
77
77
|
apply(_createElement, _ctx, args) {
|
|
78
78
|
const rawCreateMethod = propKey === "createElement" ? rawCreateElement : rawCreateTextNode;
|
|
79
|
-
|
|
79
|
+
// Vue compiles static template blocks through one shared
|
|
80
|
+
// HTMLTemplateElement. A template created in the execution iframe
|
|
81
|
+
// exposes a fragment from that realm, which native host DOM
|
|
82
|
+
// insertion rejects. Keep templates and their content fragment in
|
|
83
|
+
// the visible host realm.
|
|
84
|
+
const element = propKey === "createElement" && String(args[0]).toLowerCase() === "template"
|
|
85
|
+
? window.document.createElement("template")
|
|
86
|
+
: rawCreateMethod.apply(iframeDocument, args);
|
|
80
87
|
patchElementEffect(element, iframeWindow);
|
|
81
88
|
return element;
|
|
82
89
|
},
|
|
@@ -276,7 +283,9 @@ export function localGenerator(iframe, urlElement, mainHostPath, appHostPath) {
|
|
|
276
283
|
const activeIframe = getActiveIframe(iframeRef);
|
|
277
284
|
const activeWindow = getIframeWindow(activeIframe);
|
|
278
285
|
const activeDocument = getIframeDocument(activeIframe);
|
|
279
|
-
const element =
|
|
286
|
+
const element = String(args[0]).toLowerCase() === "template"
|
|
287
|
+
? window.document.createElement("template")
|
|
288
|
+
: getXpeRawDocumentCreateElement(activeWindow).apply(activeDocument, args);
|
|
280
289
|
patchElementEffect(element, activeWindow);
|
|
281
290
|
return element;
|
|
282
291
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function createRuntimeFetch(runtimeCredentials, browserFetch = window.fetch.bind(window)) {
|
|
2
|
+
if (!runtimeCredentials)
|
|
3
|
+
return undefined;
|
|
4
|
+
return (input, init) => {
|
|
5
|
+
// Request objects created inside an XPE child iframe belong to another
|
|
6
|
+
// JavaScript Realm, so `input instanceof Request` is false in the Host.
|
|
7
|
+
// RequestInfo is Request|string; use the contract shape instead.
|
|
8
|
+
const requestCredentials = typeof input === "string" ? undefined : input.credentials;
|
|
9
|
+
return browserFetch(input, {
|
|
10
|
+
...init,
|
|
11
|
+
credentials: init?.credentials ?? requestCredentials ?? runtimeCredentials,
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
}
|
package/dist/kernel/template.js
CHANGED
|
@@ -212,9 +212,17 @@ export default function processTpl(tpl, baseURI, postProcessTemplate) {
|
|
|
212
212
|
return inlineScriptReplaceSymbol;
|
|
213
213
|
}
|
|
214
214
|
});
|
|
215
|
+
const entrySrc = typeof entry === "string" ? entry : entry?.src;
|
|
216
|
+
const entryIndex = entrySrc
|
|
217
|
+
? scripts.findIndex((script) => script.src === entrySrc)
|
|
218
|
+
: scripts.length - 1;
|
|
219
|
+
const scriptsWithEntry = scripts.map((script, index) => ({
|
|
220
|
+
...script,
|
|
221
|
+
isEntry: index === entryIndex,
|
|
222
|
+
}));
|
|
215
223
|
let tplResult = {
|
|
216
224
|
template,
|
|
217
|
-
scripts,
|
|
225
|
+
scripts: scriptsWithEntry,
|
|
218
226
|
styles,
|
|
219
227
|
// set the last script as entry if have not set
|
|
220
228
|
entry: entry || scripts[scripts.length - 1],
|