xpe 1.0.11 → 1.0.12

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.
@@ -727,7 +727,11 @@ function wrapInlineScriptWithSandbox(code) {
727
727
  }
728
728
  function createExecNextScriptContent() {
729
729
  return [
730
- "const sandbox = window.__XPE_INTERNAL_SANDBOX__;",
730
+ // This helper is injected as a classic script repeatedly. `const` would
731
+ // create a global lexical binding and fail on the second queued script
732
+ // (notably when Vite's dev client precedes the app entry). `var` is
733
+ // intentionally used so each queue step remains re-entrant.
734
+ "var sandbox = window.__XPE_INTERNAL_SANDBOX__;",
731
735
  "if(sandbox.execQueue && sandbox.execQueue.length){ sandbox.execQueue.shift()()}",
732
736
  ].join("");
733
737
  }
@@ -923,7 +927,7 @@ export function syncIframeUrlToWindow(iframeWindow) {
923
927
  * @param rawElement 原始的脚本
924
928
  */
925
929
  export function insertScriptToIframe(scriptResult, iframeWindow, rawElement) {
926
- const { src, module, content, crossorigin, crossoriginType, async, attrs, callback, onload } = scriptResult;
930
+ const { src, module, isEntry, content, crossorigin, crossoriginType, async, attrs, callback, onload } = scriptResult;
927
931
  const sandbox = getActiveSandbox(iframeWindow);
928
932
  const container = rawDocumentQuerySelector.call(iframeWindow.document, "head");
929
933
  const execNextScript = () => {
@@ -1001,9 +1005,19 @@ export function insertScriptToIframe(scriptResult, iframeWindow, rawElement) {
1001
1005
  scriptElement.onerror = afterExecScript;
1002
1006
  }
1003
1007
  container.appendChild(scriptElement);
1004
- if (isOutlineScript && module) {
1008
+ // Vite injects an HMR client module before the actual application entry in
1009
+ // development HTML. That client keeps a long-lived websocket and may not
1010
+ // dispatch the module load event in the sandbox, so waiting for it would
1011
+ // prevent the real entry module from ever being inserted. It is not an
1012
+ // application lifecycle module and must not participate in the serial
1013
+ // entry gate.
1014
+ const isViteClientModule = module && /(?:^|\/)@vite\/client(?:$|\?)/.test(src);
1015
+ if (isOutlineScript && module && isEntry && !isViteClientModule) {
1005
1016
  waitForModuleLifecycleReady(iframeWindow, afterExecScript);
1006
1017
  }
1018
+ if (isOutlineScript && isViteClientModule) {
1019
+ afterExecScript();
1020
+ }
1007
1021
  // 调用回调
1008
1022
  callback?.(iframeWindow);
1009
1023
  // 执行 hooks
@@ -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: toRuntimeFetch(runtime.credentials),
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
- }
@@ -8,6 +8,8 @@ export interface ScriptObjectLoader {
8
8
  src?: string;
9
9
  /** 脚本是否为module模块 */
10
10
  module?: boolean;
11
+ /** 是否为应用入口脚本。仅入口模块需要等待 XPE 生命周期挂载。 */
12
+ isEntry?: boolean;
11
13
  /** 脚本是否为async执行 */
12
14
  async?: boolean;
13
15
  /** 脚本是否设置crossorigin */
@@ -0,0 +1,2 @@
1
+ import type { RuntimeCredentials } from "../core/index.js";
2
+ export declare function createRuntimeFetch(runtimeCredentials: RuntimeCredentials | undefined, browserFetch?: typeof fetch): ((input: RequestInfo, init?: RequestInit) => Promise<Response>) | undefined;
@@ -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
+ }
@@ -11,6 +11,8 @@ export interface ScriptBaseObject {
11
11
  defer?: boolean;
12
12
  /** 脚本是否为module模块 */
13
13
  module?: boolean;
14
+ /** 是否为应用入口脚本。仅入口模块需要等待 XPE 生命周期挂载。 */
15
+ isEntry?: boolean;
14
16
  /** 脚本是否设置crossorigin */
15
17
  crossorigin?: boolean;
16
18
  /** 脚本crossorigin的类型 */
@@ -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],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xpe",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "下一代微前端应用运行底座",
5
5
  "type": "module",
6
6
  "license": "MIT",