xpe 1.0.4 → 1.0.6

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.
@@ -21,30 +21,13 @@ function patchCustomEvent(e, elementGetter) {
21
21
  /**
22
22
  * 手动触发事件回调
23
23
  */
24
- function manualInvokeElementEvent(element, event, sandboxId) {
25
- // 动态 link/script 节点由子应用 realm 创建,但被 XPE 转发到宿主
26
- // shadowRoot。此时节点上的原生 dispatchEvent 可能无法命中由子应用
27
- // Node.prototype.addEventListener 注册的回调。事件代理已经把回调保存在
28
- // sandbox 的缓存中,优先从缓存派发,保证 Vite 的 load/error Promise 收敛。
24
+ function manualInvokeElementEvent(element, event) {
29
25
  const customEvent = new CustomEvent(event);
30
26
  const patchedEvent = patchCustomEvent(customEvent, () => element);
31
- const hasPropertyHandler = isFunction(element[`on${event}`]);
32
- if (hasPropertyHandler) {
27
+ if (isFunction(element[`on${event}`])) {
33
28
  element[`on${event}`](patchedEvent);
34
29
  }
35
- const listeners = sandboxId
36
- ? getSandboxById(sandboxId)?.elementEventCacheMap.get(element)
37
- : undefined;
38
- const cachedListeners = listeners?.filter((listener) => listener.type === event) ?? [];
39
- if (cachedListeners.length) {
40
- cachedListeners.forEach((listener) => {
41
- if (typeof listener.callback === "function")
42
- listener.callback.call(element, patchedEvent);
43
- else
44
- listener.callback.handleEvent(patchedEvent);
45
- });
46
- }
47
- else if (!hasPropertyHandler) {
30
+ else {
48
31
  element.dispatchEvent(patchedEvent);
49
32
  }
50
33
  }
@@ -252,7 +235,7 @@ export function deferStyleSheetByHref(opts) {
252
235
  const target = element;
253
236
  finalize();
254
237
  if (target)
255
- manualInvokeElementEvent(target, "error", sandboxId);
238
+ manualInvokeElementEvent(target, "error");
256
239
  }, DEFER_STYLE_HREF_TIMEOUT);
257
240
  }
258
241
  function rewriteAppendOrInsertChild(opts) {
@@ -313,12 +296,12 @@ function rewriteAppendOrInsertChild(opts) {
313
296
  rawDOMAppendOrInsertBefore.call(this, stylesheetElement, refChild);
314
297
  // 处理样式补丁
315
298
  handleStylesheetElementPatch(stylesheetElement, latestContext.sandbox);
316
- manualInvokeElementEvent(linkElement, "load", sandboxId);
299
+ manualInvokeElementEvent(linkElement, "load");
317
300
  }
318
301
  if (element === linkElement)
319
302
  element = null;
320
303
  }, () => {
321
- manualInvokeElementEvent(linkElement, "error", sandboxId);
304
+ manualInvokeElementEvent(linkElement, "error");
322
305
  if (element === linkElement)
323
306
  element = null;
324
307
  }));
@@ -363,7 +346,7 @@ function rewriteAppendOrInsertChild(opts) {
363
346
  if (!latestContext)
364
347
  return warn(XPE_TIPS_REPEAT_RENDER);
365
348
  const onload = () => {
366
- manualInvokeElementEvent(element, "load", sandboxId);
349
+ manualInvokeElementEvent(element, "load");
367
350
  element = null;
368
351
  };
369
352
  insertScriptToIframe({ ...scriptResult, onload }, latestContext.iframeWindow, element);
@@ -390,7 +373,7 @@ function rewriteAppendOrInsertChild(opts) {
390
373
  if (!execQueueLength)
391
374
  sandbox.execQueue.shift()();
392
375
  }, () => {
393
- manualInvokeElementEvent(element, "error", sandboxId);
376
+ manualInvokeElementEvent(element, "error");
394
377
  element = null;
395
378
  }));
396
379
  });
@@ -191,7 +191,8 @@ export default function importHTML(params) {
191
191
  .then((response) => {
192
192
  if (response.status >= 400) {
193
193
  error(XPE_TIPS_HTML_ERROR_REQUESTED, { url, response });
194
- throw new Error(XPE_TIPS_HTML_ERROR_REQUESTED);
194
+ loadError?.(url, new Error(XPE_TIPS_HTML_ERROR_REQUESTED));
195
+ return "";
195
196
  }
196
197
  return response.text();
197
198
  })
@@ -923,7 +923,7 @@ export function syncIframeUrlToWindow(iframeWindow) {
923
923
  * @param rawElement 原始的脚本
924
924
  */
925
925
  export function insertScriptToIframe(scriptResult, iframeWindow, rawElement) {
926
- const { src, module, content, crossorigin, crossoriginType, async, attrs, callback, onload } = scriptResult;
926
+ const { src, module, isEntry, content, crossorigin, crossoriginType, async, attrs, callback, onload } = scriptResult;
927
927
  const sandbox = getActiveSandbox(iframeWindow);
928
928
  const container = rawDocumentQuerySelector.call(iframeWindow.document, "head");
929
929
  const execNextScript = () => {
@@ -1001,7 +1001,7 @@ export function insertScriptToIframe(scriptResult, iframeWindow, rawElement) {
1001
1001
  scriptElement.onerror = afterExecScript;
1002
1002
  }
1003
1003
  container.appendChild(scriptElement);
1004
- if (isOutlineScript && module) {
1004
+ if (isOutlineScript && module && isEntry) {
1005
1005
  waitForModuleLifecycleReady(iframeWindow, afterExecScript);
1006
1006
  }
1007
1007
  // 调用回调
@@ -26,10 +26,10 @@ function loadRuntimeEngine() {
26
26
  if (runtimeEngineModule)
27
27
  return Promise.resolve(runtimeEngineModule);
28
28
  if (!runtimeEngineModulePromise) {
29
- // 保持字面量动态 import:Vite/Rollup 等消费方只有在构建期看见静态 specifier,
30
- // 才会把懒加载内核生成成可部署 chunk。通过变量 import 会在 npm 消费方产物中
31
- // 留下 ./runtime-engine.js,并错误解析到 Host 自己的 /assets 目录。
32
- // @ts-expect-error Vite/Rollup 会解析查询参数并生成独立 chunk,TypeScript 不解析该运行时 specifier。
29
+ // Keep a literal dynamic import so Vite/Rollup bundles the runtime engine
30
+ // into a deployable child chunk instead of leaving a missing relative URL
31
+ // in the host's optimized dependency directory.
32
+ // @ts-expect-error Vite/Rollup resolves the query-suffixed runtime chunk at build time.
33
33
  runtimeEngineModulePromise = import("./runtime-engine.js?xpe-runtime").then((module) => {
34
34
  runtimeEngineModule = module;
35
35
  return runtimeEngineModule;
@@ -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 */
@@ -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.4",
3
+ "version": "1.0.6",
4
4
  "description": "下一代微前端应用运行底座",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -46,12 +46,11 @@
46
46
  "check:example-build": "pnpm run typecheck:browser-smoke && pnpm run build:example",
47
47
  "check:host-child-smoke": "node scripts/check-host-child-smoke.mjs",
48
48
  "check:dist-surface": "node scripts/check-dist-surface.mjs",
49
- "check:vite-consumer-build": "node scripts/check-vite-consumer-build.mjs",
50
49
  "check:kernel-surface": "node scripts/check-kernel-surface.mjs",
51
50
  "check:pack": "pnpm pack --dry-run",
52
51
  "check:public-surface": "node scripts/check-public-surface.mjs",
53
52
  "check:release-metadata": "node scripts/check-release-metadata.mjs",
54
- "verify": "pnpm run check:release-metadata && pnpm run typecheck && pnpm test && pnpm run build && pnpm run check:vite-consumer-build && pnpm run check:pack",
53
+ "verify": "pnpm run check:release-metadata && pnpm run typecheck && pnpm test && pnpm run build && pnpm run check:pack",
55
54
  "prepack": "pnpm run build",
56
55
  "prepublishOnly": "pnpm run verify",
57
56
  "test": "vitest run",