xpe 0.0.0-alpha.1 → 1.0.0

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.
Files changed (214) hide show
  1. package/README.md +627 -71
  2. package/dist/child/app-client.d.ts +44 -0
  3. package/dist/child/app-client.js +151 -0
  4. package/dist/child/index.d.ts +3 -0
  5. package/dist/child/index.js +3 -0
  6. package/dist/child/lifecycle.d.ts +12 -0
  7. package/dist/child/lifecycle.js +47 -0
  8. package/dist/child/mock-host.d.ts +8 -0
  9. package/dist/child/mock-host.js +41 -0
  10. package/dist/core/bridge.d.ts +28 -0
  11. package/dist/core/bridge.js +19 -0
  12. package/dist/core/events.d.ts +13 -0
  13. package/dist/core/events.js +56 -0
  14. package/dist/core/index.d.ts +3 -0
  15. package/dist/core/index.js +3 -0
  16. package/dist/core/types.d.ts +102 -0
  17. package/dist/core/types.js +20 -0
  18. package/dist/dev-shell/index.d.ts +26 -0
  19. package/dist/dev-shell/index.js +56 -0
  20. package/dist/host/app-path-router.d.ts +33 -0
  21. package/dist/host/app-path-router.js +183 -0
  22. package/dist/host/host-runtime.d.ts +29 -0
  23. package/dist/host/host-runtime.js +176 -0
  24. package/dist/host/index.d.ts +1 -0
  25. package/dist/host/index.js +1 -0
  26. package/dist/host/xpe-host.d.ts +41 -0
  27. package/dist/host/xpe-host.js +61 -0
  28. package/dist/index.d.ts +4 -0
  29. package/dist/index.js +4 -0
  30. package/dist/kernel/common.d.ts +62 -0
  31. package/dist/kernel/common.js +207 -0
  32. package/dist/kernel/constant.d.ts +26 -0
  33. package/dist/kernel/constant.js +42 -0
  34. package/dist/kernel/effect.d.ts +32 -0
  35. package/dist/kernel/effect.js +529 -0
  36. package/dist/kernel/entry.d.ts +43 -0
  37. package/dist/kernel/entry.js +224 -0
  38. package/dist/kernel/event.d.ts +22 -0
  39. package/dist/kernel/event.js +120 -0
  40. package/dist/kernel/iframe.d.ts +141 -0
  41. package/dist/kernel/iframe.js +1104 -0
  42. package/dist/kernel/index.d.ts +25 -0
  43. package/dist/kernel/index.js +86 -0
  44. package/dist/kernel/plugin.d.ts +36 -0
  45. package/dist/kernel/plugin.js +68 -0
  46. package/dist/kernel/proxy.d.ts +17 -0
  47. package/dist/kernel/proxy.js +440 -0
  48. package/dist/kernel/runtime-engine.d.ts +154 -0
  49. package/dist/kernel/runtime-engine.js +209 -0
  50. package/dist/kernel/sandbox.d.ts +235 -0
  51. package/dist/kernel/sandbox.js +879 -0
  52. package/dist/kernel/shadow.d.ts +64 -0
  53. package/dist/kernel/shadow.js +385 -0
  54. package/dist/kernel/sync.d.ts +21 -0
  55. package/dist/kernel/sync.js +185 -0
  56. package/dist/kernel/template.d.ts +67 -0
  57. package/dist/kernel/template.js +226 -0
  58. package/dist/kernel/tracker.d.ts +44 -0
  59. package/dist/kernel/tracker.js +92 -0
  60. package/dist/kernel/utils.d.ts +100 -0
  61. package/dist/kernel/utils.js +325 -0
  62. package/dist/kernel/xpe-bridge.d.ts +27 -0
  63. package/dist/kernel/xpe-bridge.js +205 -0
  64. package/dist/shared/index.d.ts +1 -0
  65. package/dist/shared/index.js +3 -0
  66. package/package.json +79 -57
  67. package/LICENSE +0 -21
  68. package/framework/es/core/Application.d.ts +0 -126
  69. package/framework/es/core/Command/Command.d.ts +0 -7
  70. package/framework/es/core/Container/Container.d.ts +0 -80
  71. package/framework/es/core/Contracts/AxiosAdapter.d.ts +0 -12
  72. package/framework/es/core/Helper/Helper.d.ts +0 -43
  73. package/framework/es/core/Helper/Storage/WebStorage.d.ts +0 -71
  74. package/framework/es/core/Libs/Exception.d.ts +0 -24
  75. package/framework/es/core/Libs/Lib.d.ts +0 -72
  76. package/framework/es/core/Provider/CommandProvider.d.ts +0 -4
  77. package/framework/es/core/Provider/HelperProvider.d.ts +0 -4
  78. package/framework/es/core/Provider/HttpProvider.d.ts +0 -13
  79. package/framework/es/core/Provider/ServiceProvider.d.ts +0 -15
  80. package/framework/es/core/Service/HttpService.d.ts +0 -133
  81. package/framework/es/core/Service/Service.d.ts +0 -6
  82. package/framework/es/core/Spanner/RESTful.d.ts +0 -30
  83. package/framework/es/core/Transformer/Transformer.d.ts +0 -46
  84. package/framework/es/core/Type/adapters.d.ts +0 -25
  85. package/framework/es/core/Type/types.d.ts +0 -161
  86. package/framework/es/core/TypeFunc/index.d.ts +0 -6
  87. package/framework/es/core/Wrenches/EventBus.d.ts +0 -56
  88. package/framework/es/core/Wrenches/is.d.ts +0 -19
  89. package/framework/es/ege.js +0 -4
  90. package/framework/es/ege.js.map +0 -1
  91. package/framework/es/index.d.ts +0 -13
  92. package/framework/es/pdd.js +0 -4
  93. package/framework/es/pdd.js.map +0 -1
  94. package/framework/es/src/core/Application.d.ts +0 -127
  95. package/framework/es/src/core/Application.d.ts.map +0 -1
  96. package/framework/es/src/core/Command/Command.d.ts +0 -8
  97. package/framework/es/src/core/Command/Command.d.ts.map +0 -1
  98. package/framework/es/src/core/Container/Container.d.ts +0 -81
  99. package/framework/es/src/core/Container/Container.d.ts.map +0 -1
  100. package/framework/es/src/core/Contracts/AxiosAdapter.d.ts +0 -13
  101. package/framework/es/src/core/Contracts/AxiosAdapter.d.ts.map +0 -1
  102. package/framework/es/src/core/Helper/Helper.d.ts +0 -45
  103. package/framework/es/src/core/Helper/Helper.d.ts.map +0 -1
  104. package/framework/es/src/core/Helper/Storage/WebStorage.d.ts +0 -72
  105. package/framework/es/src/core/Helper/Storage/WebStorage.d.ts.map +0 -1
  106. package/framework/es/src/core/Libs/Exception.d.ts +0 -25
  107. package/framework/es/src/core/Libs/Exception.d.ts.map +0 -1
  108. package/framework/es/src/core/Libs/Lib.d.ts +0 -73
  109. package/framework/es/src/core/Libs/Lib.d.ts.map +0 -1
  110. package/framework/es/src/core/Provider/CommandProvider.d.ts +0 -5
  111. package/framework/es/src/core/Provider/CommandProvider.d.ts.map +0 -1
  112. package/framework/es/src/core/Provider/HelperProvider.d.ts +0 -5
  113. package/framework/es/src/core/Provider/HelperProvider.d.ts.map +0 -1
  114. package/framework/es/src/core/Provider/HttpProvider.d.ts +0 -14
  115. package/framework/es/src/core/Provider/HttpProvider.d.ts.map +0 -1
  116. package/framework/es/src/core/Provider/ServiceProvider.d.ts +0 -16
  117. package/framework/es/src/core/Provider/ServiceProvider.d.ts.map +0 -1
  118. package/framework/es/src/core/Service/HttpService.d.ts +0 -128
  119. package/framework/es/src/core/Service/HttpService.d.ts.map +0 -1
  120. package/framework/es/src/core/Service/Service.d.ts +0 -7
  121. package/framework/es/src/core/Service/Service.d.ts.map +0 -1
  122. package/framework/es/src/core/Spanner/RESTful.d.ts +0 -32
  123. package/framework/es/src/core/Spanner/RESTful.d.ts.map +0 -1
  124. package/framework/es/src/core/Transformer/Transformer.d.ts +0 -47
  125. package/framework/es/src/core/Transformer/Transformer.d.ts.map +0 -1
  126. package/framework/es/src/core/Type/adapters.d.ts +0 -26
  127. package/framework/es/src/core/Type/adapters.d.ts.map +0 -1
  128. package/framework/es/src/core/Type/types.d.ts +0 -186
  129. package/framework/es/src/core/Type/types.d.ts.map +0 -1
  130. package/framework/es/src/core/TypeFunc/index.d.ts +0 -8
  131. package/framework/es/src/core/TypeFunc/index.d.ts.map +0 -1
  132. package/framework/es/src/core/Wrenches/EventBus.d.ts +0 -57
  133. package/framework/es/src/core/Wrenches/EventBus.d.ts.map +0 -1
  134. package/framework/es/src/core/Wrenches/is.d.ts +0 -20
  135. package/framework/es/src/core/Wrenches/is.d.ts.map +0 -1
  136. package/framework/es/src/index.d.ts +0 -14
  137. package/framework/es/src/index.d.ts.map +0 -1
  138. package/framework/es/src/utils.d.ts +0 -17
  139. package/framework/es/src/utils.d.ts.map +0 -1
  140. package/framework/es/utils.d.ts +0 -16
  141. package/framework/umd/core/Application.d.ts +0 -126
  142. package/framework/umd/core/Command/Command.d.ts +0 -7
  143. package/framework/umd/core/Container/Container.d.ts +0 -80
  144. package/framework/umd/core/Contracts/AxiosAdapter.d.ts +0 -12
  145. package/framework/umd/core/Helper/Helper.d.ts +0 -43
  146. package/framework/umd/core/Helper/Storage/WebStorage.d.ts +0 -71
  147. package/framework/umd/core/Libs/Exception.d.ts +0 -24
  148. package/framework/umd/core/Libs/Lib.d.ts +0 -72
  149. package/framework/umd/core/Provider/CommandProvider.d.ts +0 -4
  150. package/framework/umd/core/Provider/HelperProvider.d.ts +0 -4
  151. package/framework/umd/core/Provider/HttpProvider.d.ts +0 -13
  152. package/framework/umd/core/Provider/ServiceProvider.d.ts +0 -15
  153. package/framework/umd/core/Service/HttpService.d.ts +0 -133
  154. package/framework/umd/core/Service/Service.d.ts +0 -6
  155. package/framework/umd/core/Spanner/RESTful.d.ts +0 -30
  156. package/framework/umd/core/Transformer/Transformer.d.ts +0 -46
  157. package/framework/umd/core/Type/adapters.d.ts +0 -25
  158. package/framework/umd/core/Type/types.d.ts +0 -161
  159. package/framework/umd/core/TypeFunc/index.d.ts +0 -6
  160. package/framework/umd/core/Wrenches/EventBus.d.ts +0 -56
  161. package/framework/umd/core/Wrenches/is.d.ts +0 -19
  162. package/framework/umd/ege.js +0 -4
  163. package/framework/umd/ege.js.map +0 -1
  164. package/framework/umd/index.d.ts +0 -13
  165. package/framework/umd/pdd.js +0 -4
  166. package/framework/umd/pdd.js.map +0 -1
  167. package/framework/umd/src/core/Application.d.ts +0 -127
  168. package/framework/umd/src/core/Application.d.ts.map +0 -1
  169. package/framework/umd/src/core/Command/Command.d.ts +0 -8
  170. package/framework/umd/src/core/Command/Command.d.ts.map +0 -1
  171. package/framework/umd/src/core/Container/Container.d.ts +0 -81
  172. package/framework/umd/src/core/Container/Container.d.ts.map +0 -1
  173. package/framework/umd/src/core/Contracts/AxiosAdapter.d.ts +0 -13
  174. package/framework/umd/src/core/Contracts/AxiosAdapter.d.ts.map +0 -1
  175. package/framework/umd/src/core/Helper/Helper.d.ts +0 -45
  176. package/framework/umd/src/core/Helper/Helper.d.ts.map +0 -1
  177. package/framework/umd/src/core/Helper/Storage/WebStorage.d.ts +0 -72
  178. package/framework/umd/src/core/Helper/Storage/WebStorage.d.ts.map +0 -1
  179. package/framework/umd/src/core/Libs/Exception.d.ts +0 -25
  180. package/framework/umd/src/core/Libs/Exception.d.ts.map +0 -1
  181. package/framework/umd/src/core/Libs/Lib.d.ts +0 -73
  182. package/framework/umd/src/core/Libs/Lib.d.ts.map +0 -1
  183. package/framework/umd/src/core/Provider/CommandProvider.d.ts +0 -5
  184. package/framework/umd/src/core/Provider/CommandProvider.d.ts.map +0 -1
  185. package/framework/umd/src/core/Provider/HelperProvider.d.ts +0 -5
  186. package/framework/umd/src/core/Provider/HelperProvider.d.ts.map +0 -1
  187. package/framework/umd/src/core/Provider/HttpProvider.d.ts +0 -14
  188. package/framework/umd/src/core/Provider/HttpProvider.d.ts.map +0 -1
  189. package/framework/umd/src/core/Provider/ServiceProvider.d.ts +0 -16
  190. package/framework/umd/src/core/Provider/ServiceProvider.d.ts.map +0 -1
  191. package/framework/umd/src/core/Service/HttpService.d.ts +0 -128
  192. package/framework/umd/src/core/Service/HttpService.d.ts.map +0 -1
  193. package/framework/umd/src/core/Service/Service.d.ts +0 -7
  194. package/framework/umd/src/core/Service/Service.d.ts.map +0 -1
  195. package/framework/umd/src/core/Spanner/RESTful.d.ts +0 -32
  196. package/framework/umd/src/core/Spanner/RESTful.d.ts.map +0 -1
  197. package/framework/umd/src/core/Transformer/Transformer.d.ts +0 -47
  198. package/framework/umd/src/core/Transformer/Transformer.d.ts.map +0 -1
  199. package/framework/umd/src/core/Type/adapters.d.ts +0 -26
  200. package/framework/umd/src/core/Type/adapters.d.ts.map +0 -1
  201. package/framework/umd/src/core/Type/types.d.ts +0 -186
  202. package/framework/umd/src/core/Type/types.d.ts.map +0 -1
  203. package/framework/umd/src/core/TypeFunc/index.d.ts +0 -8
  204. package/framework/umd/src/core/TypeFunc/index.d.ts.map +0 -1
  205. package/framework/umd/src/core/Wrenches/EventBus.d.ts +0 -57
  206. package/framework/umd/src/core/Wrenches/EventBus.d.ts.map +0 -1
  207. package/framework/umd/src/core/Wrenches/is.d.ts +0 -20
  208. package/framework/umd/src/core/Wrenches/is.d.ts.map +0 -1
  209. package/framework/umd/src/index.d.ts +0 -14
  210. package/framework/umd/src/index.d.ts.map +0 -1
  211. package/framework/umd/src/utils.d.ts +0 -17
  212. package/framework/umd/src/utils.d.ts.map +0 -1
  213. package/framework/umd/utils.d.ts +0 -16
  214. package/index.d.ts +0 -724
@@ -0,0 +1,154 @@
1
+ export { clearAssetsCache } from "./entry.js";
2
+ import { StyleObject, ScriptAttributes } from "./template.js";
3
+ import { lifecycle } from "./sandbox.js";
4
+ import { EventBus } from "./event.js";
5
+ export declare const bus: EventBus;
6
+ export interface ScriptObjectLoader {
7
+ /** 脚本地址,内联为空 */
8
+ src?: string;
9
+ /** 脚本是否为module模块 */
10
+ module?: boolean;
11
+ /** 脚本是否为async执行 */
12
+ async?: boolean;
13
+ /** 脚本是否设置crossorigin */
14
+ crossorigin?: boolean;
15
+ /** 脚本crossorigin的类型 */
16
+ crossoriginType?: "anonymous" | "use-credentials" | "";
17
+ /** 脚本原始属性 */
18
+ attrs?: ScriptAttributes;
19
+ /** 内联script的代码 */
20
+ content?: string;
21
+ /** 执行回调钩子 */
22
+ callback?: (appWindow: Window) => any;
23
+ /** 子应用加载完毕事件 */
24
+ onload?: Function;
25
+ }
26
+ export interface plugin {
27
+ /** 处理html的loader */
28
+ htmlLoader?: (code: string) => string;
29
+ /** js排除列表 */
30
+ jsExcludes?: Array<string | RegExp>;
31
+ /** js忽略列表 */
32
+ jsIgnores?: Array<string | RegExp>;
33
+ /** 处理js加载前的loader */
34
+ jsBeforeLoaders?: Array<ScriptObjectLoader>;
35
+ /** 处理js的loader */
36
+ jsLoader?: (code: string, url: string, base: string) => string;
37
+ /** 处理js加载后的loader */
38
+ jsAfterLoaders?: Array<ScriptObjectLoader>;
39
+ /** css排除列表 */
40
+ cssExcludes?: Array<string | RegExp>;
41
+ /** css忽略列表 */
42
+ cssIgnores?: Array<string | RegExp>;
43
+ /** 处理css加载前的loader */
44
+ cssBeforeLoaders?: Array<StyleObject>;
45
+ /** 处理css的loader */
46
+ cssLoader?: (code: string, url: string, base: string) => string;
47
+ /** 处理css加载后的loader */
48
+ cssAfterLoaders?: Array<StyleObject>;
49
+ /** 子应用 window addEventListener 钩子回调 */
50
+ windowAddEventListenerHook?: eventListenerHook;
51
+ /** 子应用 window removeEventListener 钩子回调 */
52
+ windowRemoveEventListenerHook?: eventListenerHook;
53
+ /** 子应用 document addEventListener 钩子回调 */
54
+ documentAddEventListenerHook?: eventListenerHook;
55
+ /** 子应用 document removeEventListener 钩子回调 */
56
+ documentRemoveEventListenerHook?: eventListenerHook;
57
+ /** 子应用 向body、head插入元素后执行的钩子回调 */
58
+ appendOrInsertElementHook?: <T extends Node>(element: T, iframeWindow: Window) => void;
59
+ /** 子应用劫持元素的钩子回调 */
60
+ patchElementHook?: <T extends Node>(element: T, iframeWindow: Window) => void;
61
+ /** 用户自定义覆盖子应用 window 属性 */
62
+ windowPropertyOverride?: (iframeWindow: Window) => void;
63
+ /** 用户自定义覆盖子应用 document 属性 */
64
+ documentPropertyOverride?: (iframeWindow: Window) => void;
65
+ }
66
+ type eventListenerHook = (iframeWindow: Window, type: string, handler: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions) => void;
67
+ export type loadErrorHandler = (url: string, e: Error) => any;
68
+ type baseOptions = {
69
+ /** 唯一性用户必须保证 */
70
+ name: string;
71
+ /** 需要渲染的url */
72
+ url: string;
73
+ /** 需要渲染的html, 如果已有则无需从url请求 */
74
+ html?: string;
75
+ /** 代码替换钩子 */
76
+ replace?: (code: string) => string;
77
+ /** 自定义fetch */
78
+ fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
79
+ /** 注入给子应用的属性 */
80
+ props?: {
81
+ [key: string]: any;
82
+ };
83
+ /** 自定义运行iframe的属性 */
84
+ attrs?: {
85
+ [key: string]: any;
86
+ };
87
+ /** 自定义降级渲染iframe的属性 */
88
+ degradeAttrs?: {
89
+ [key: string]: any;
90
+ };
91
+ /** 子应用采用fiber模式执行 */
92
+ fiber?: boolean;
93
+ /** 子应用保活,state不会丢失 */
94
+ alive?: boolean;
95
+ /** 子应用采用降级iframe方案 */
96
+ degrade?: boolean;
97
+ /** 子应用插件 */
98
+ plugins?: Array<plugin>;
99
+ /** 子应用window监听事件 */
100
+ iframeAddEventListeners?: Array<string>;
101
+ /** 子应用iframe on事件 */
102
+ iframeOnEvents?: Array<string>;
103
+ /** 子应用生命周期 */
104
+ beforeLoad?: lifecycle;
105
+ beforeMount?: lifecycle;
106
+ afterMount?: lifecycle;
107
+ beforeUnmount?: lifecycle;
108
+ afterUnmount?: lifecycle;
109
+ activated?: lifecycle;
110
+ deactivated?: lifecycle;
111
+ loadError?: loadErrorHandler;
112
+ };
113
+ export type preOptions = Omit<baseOptions, "url"> & {
114
+ /** 预执行 */
115
+ exec?: boolean;
116
+ url?: string;
117
+ };
118
+ export type startOptions = baseOptions & {
119
+ /** 渲染的容器 */
120
+ el: HTMLElement | string;
121
+ /**
122
+ * 路由同步开关
123
+ * 如果false,子应用跳转主应用路由无变化,但是主应用的history还是会增加
124
+ * https://html.spec.whatwg.org/multipage/history.html#the-history-interface
125
+ */
126
+ sync?: boolean;
127
+ /** 子应用短路径替换,路由同步时生效 */
128
+ prefix?: {
129
+ [key: string]: string;
130
+ };
131
+ /** 子应用加载时loading元素 */
132
+ loading?: HTMLElement;
133
+ };
134
+ type optionProperty = "url" | "el";
135
+ /**
136
+ * 合并 preOptions 和 startOptions,并且将 url 和 el 变成可选
137
+ */
138
+ export type cacheOptions = Omit<preOptions & startOptions, optionProperty> & Partial<Pick<startOptions, optionProperty>>;
139
+ /**
140
+ * 缓存子应用配置
141
+ */
142
+ export declare function setupApp(options: cacheOptions): void;
143
+ /**
144
+ * 运行子应用
145
+ */
146
+ export declare function startApp(startOptions: startOptions): Promise<Function | void>;
147
+ /**
148
+ * 预加载 XPE 子应用
149
+ */
150
+ export declare function preloadApp(preOptions: preOptions): void;
151
+ /**
152
+ * 销毁子应用
153
+ */
154
+ export declare function destroyApp(id: string): Promise<void>;
@@ -0,0 +1,209 @@
1
+ import importHTML, { processCssLoader } from "./entry.js";
2
+ export { clearAssetsCache } from "./entry.js";
3
+ import RuntimeSandbox from "./sandbox.js";
4
+ import { defineRuntimeWebComponent, addLoading, removeLoading } from "./shadow.js";
5
+ import { getPlugins } from "./plugin.js";
6
+ import { runtimeDomSupport, mergeOptions, isFunction, requestIdleCallback, isMatchSyncQueryById, getContainer, warn, stopMainAppRun, } from "./utils.js";
7
+ import { getSandboxById, getOptionsById, addSandboxCacheWithOptions } from "./common.js";
8
+ import { EventBus } from "./event.js";
9
+ import { XPE_TIPS_NOT_SUPPORTED } from "./constant.js";
10
+ import { getXpeInternalSandbox, getXpeMount, isPoweredByXpe } from "./xpe-bridge.js";
11
+ export const bus = new EventBus(Date.now().toString());
12
+ /**
13
+ * 强制中断主应用运行
14
+ * 如果当前运行在 XPE 子应用 iframe 中,但 runtime 尚未完成启动标记,
15
+ * 说明主应用代码在 iframe loading 阶段混入进来了,必须中断执行。
16
+ */
17
+ if (getXpeInternalSandbox(window) && !isPoweredByXpe(window)) {
18
+ stopMainAppRun();
19
+ }
20
+ // 处理子应用链接跳转
21
+ // 定义webComponent容器
22
+ defineRuntimeWebComponent();
23
+ // 如果不支持则告警
24
+ if (!runtimeDomSupport)
25
+ warn(XPE_TIPS_NOT_SUPPORTED);
26
+ /**
27
+ * 缓存子应用配置
28
+ */
29
+ export function setupApp(options) {
30
+ if (options.name)
31
+ addSandboxCacheWithOptions(options.name, options);
32
+ }
33
+ /**
34
+ * 运行子应用
35
+ */
36
+ export async function startApp(startOptions) {
37
+ const sandbox = getSandboxById(startOptions.name);
38
+ const cacheOptions = getOptionsById(startOptions.name);
39
+ // 合并缓存配置
40
+ const options = mergeOptions(startOptions, cacheOptions);
41
+ const { name, url, html, replace, fetch, props, attrs, degradeAttrs, fiber, alive, degrade, sync, prefix, el, loading, plugins, lifecycles, iframeAddEventListeners, iframeOnEvents, } = options;
42
+ // 已经初始化过的应用,快速渲染
43
+ if (sandbox) {
44
+ sandbox.plugins = getPlugins(plugins);
45
+ sandbox.lifecycles = lifecycles;
46
+ if (sandbox.preload) {
47
+ await sandbox.preload;
48
+ }
49
+ const iframeWindow = sandbox.getLifecycleWindow();
50
+ if (alive) {
51
+ // 保活
52
+ await sandbox.active({ url, sync, prefix, el, props, alive, fetch, replace });
53
+ const activeWindow = sandbox.getLifecycleWindow();
54
+ if (!activeWindow)
55
+ return () => sandbox.destroy();
56
+ // 预加载但是没有执行的情况
57
+ if (!sandbox.execFlag) {
58
+ sandbox.lifecycles?.beforeLoad?.(activeWindow);
59
+ const { getExternalScripts } = await importHTML({
60
+ url,
61
+ html,
62
+ opts: {
63
+ fetch: fetch || window.fetch,
64
+ plugins: sandbox.plugins,
65
+ loadError: sandbox.lifecycles.loadError,
66
+ fiber,
67
+ },
68
+ });
69
+ await sandbox.start(getExternalScripts);
70
+ }
71
+ sandbox.lifecycles?.activated?.(activeWindow);
72
+ return () => sandbox.destroy();
73
+ }
74
+ else if (iframeWindow && isFunction(getXpeMount(iframeWindow))) {
75
+ /**
76
+ * 子应用切换会触发webcomponent的disconnectedCallback调用sandbox.unmount进行实例销毁
77
+ * 此处是防止没有销毁webcomponent时调用startApp的情况,需要手动调用unmount
78
+ */
79
+ await sandbox.unmount({ preserveLifecycle: true });
80
+ await sandbox.active({ url, sync, prefix, el, props, alive, fetch, replace });
81
+ const activeWindow = sandbox.getLifecycleWindow();
82
+ if (!activeWindow)
83
+ return () => sandbox.destroy();
84
+ // 正常加载的情况,先注入css,最后才mount。重新激活也保持同样的时序
85
+ sandbox.rebuildStyleSheets();
86
+ // 有渲染函数
87
+ sandbox.lifecycles?.beforeMount?.(activeWindow);
88
+ getXpeMount(activeWindow)?.();
89
+ sandbox.recoverMountedEventListeners();
90
+ sandbox.lifecycles?.afterMount?.(activeWindow);
91
+ sandbox.mountFlag = true;
92
+ return () => sandbox.destroy();
93
+ }
94
+ else {
95
+ // 没有渲染函数
96
+ await sandbox.destroy();
97
+ }
98
+ }
99
+ // 设置loading
100
+ addLoading(el, loading);
101
+ const newSandbox = new RuntimeSandbox({
102
+ name,
103
+ url,
104
+ attrs,
105
+ degradeAttrs,
106
+ fiber,
107
+ degrade,
108
+ plugins,
109
+ lifecycles,
110
+ iframeAddEventListeners,
111
+ iframeOnEvents,
112
+ });
113
+ const newSandboxWindow = newSandbox.getLifecycleWindow();
114
+ newSandboxWindow && newSandbox.lifecycles?.beforeLoad?.(newSandboxWindow);
115
+ try {
116
+ const { template, getExternalScripts, getExternalStyleSheets } = await importHTML({
117
+ url,
118
+ html,
119
+ opts: {
120
+ fetch: fetch || window.fetch,
121
+ plugins: newSandbox.plugins,
122
+ loadError: newSandbox.lifecycles.loadError,
123
+ fiber,
124
+ },
125
+ });
126
+ const processedHtml = await processCssLoader(newSandbox, template, getExternalStyleSheets);
127
+ await newSandbox.active({ url, sync, prefix, template: processedHtml, el, props, alive, fetch, replace });
128
+ await newSandbox.start(getExternalScripts);
129
+ return () => newSandbox.destroy();
130
+ }
131
+ catch (error) {
132
+ // 任一环节失败都要主动清理 loading,避免遮罩永久残留在容器上。
133
+ // 加载链路(importHTML / processCssLoader / active / start)任一步失败时,
134
+ // 此前 addLoading 注入的 loading 会永久残留在容器上,遮挡后续渲染。
135
+ // 这里统一兜底:移除 loading、上报 loadError、销毁半初始化的 sandbox,再 rethrow。
136
+ try {
137
+ removeLoading(getContainer(el));
138
+ }
139
+ catch (_) {
140
+ /* noop: 清理 loading 不应掩盖原始错误 */
141
+ }
142
+ newSandbox.lifecycles?.loadError?.(url, error);
143
+ await newSandbox.destroy().catch(() => undefined);
144
+ throw error;
145
+ }
146
+ }
147
+ /**
148
+ * 预加载 XPE 子应用
149
+ */
150
+ export function preloadApp(preOptions) {
151
+ requestIdleCallback(() => {
152
+ /**
153
+ * 已经存在
154
+ * url查询参数中有子应用的id,大概率是刷新浏览器或者分享url,此时需要直接打开子应用,无需预加载
155
+ */
156
+ if (getSandboxById(preOptions.name) || isMatchSyncQueryById(preOptions.name))
157
+ return;
158
+ const cacheOptions = getOptionsById(preOptions.name);
159
+ // 合并缓存配置
160
+ const options = mergeOptions({ ...preOptions }, cacheOptions);
161
+ const { name, url, html, props, alive, replace, fetch, exec, attrs, degradeAttrs, fiber, degrade, prefix, plugins, lifecycles, iframeAddEventListeners, iframeOnEvents, } = options;
162
+ const sandbox = new RuntimeSandbox({
163
+ name,
164
+ url,
165
+ attrs,
166
+ degradeAttrs,
167
+ fiber,
168
+ degrade,
169
+ plugins,
170
+ lifecycles,
171
+ iframeAddEventListeners,
172
+ iframeOnEvents,
173
+ });
174
+ if (sandbox.preload)
175
+ return sandbox.preload;
176
+ const runPreload = async () => {
177
+ const sandboxWindow = sandbox.getLifecycleWindow();
178
+ sandboxWindow && sandbox.lifecycles?.beforeLoad?.(sandboxWindow);
179
+ const { template, getExternalScripts, getExternalStyleSheets } = await importHTML({
180
+ url,
181
+ html,
182
+ opts: {
183
+ fetch: fetch || window.fetch,
184
+ plugins: sandbox.plugins,
185
+ loadError: sandbox.lifecycles.loadError,
186
+ fiber,
187
+ },
188
+ });
189
+ const processedHtml = await processCssLoader(sandbox, template, getExternalStyleSheets);
190
+ await sandbox.active({ url, props, prefix, alive, template: processedHtml, fetch, replace });
191
+ if (exec) {
192
+ await sandbox.start(getExternalScripts);
193
+ }
194
+ else {
195
+ await getExternalScripts();
196
+ }
197
+ };
198
+ sandbox.preload = runPreload();
199
+ });
200
+ }
201
+ /**
202
+ * 销毁子应用
203
+ */
204
+ export async function destroyApp(id) {
205
+ const sandbox = getSandboxById(id);
206
+ if (sandbox) {
207
+ await sandbox.destroy();
208
+ }
209
+ }
@@ -0,0 +1,235 @@
1
+ import { type ElementEventRecord } from "./iframe.js";
2
+ import { ScriptResultList } from "./entry.js";
3
+ import { SandboxCache } from "./common.js";
4
+ import { EventBus, EventObj } from "./event.js";
5
+ import { EventCleanupTracker } from "./tracker.js";
6
+ import { plugin, loadErrorHandler } from "./runtime-engine.js";
7
+ export type lifecycle = (appWindow: Window) => any;
8
+ type lifecycles = {
9
+ beforeLoad: lifecycle;
10
+ beforeMount: lifecycle;
11
+ afterMount: lifecycle;
12
+ beforeUnmount: lifecycle;
13
+ afterUnmount: lifecycle;
14
+ activated: lifecycle;
15
+ deactivated: lifecycle;
16
+ loadError: loadErrorHandler;
17
+ };
18
+ /**
19
+ * 基于 Proxy和iframe 实现的沙箱
20
+ */
21
+ export default class RuntimeSandbox {
22
+ id: string;
23
+ /** 激活时路由地址 */
24
+ url: string;
25
+ /** 子应用保活 */
26
+ alive: boolean;
27
+ /** window代理 */
28
+ proxy: WindowProxy;
29
+ /** document代理 */
30
+ proxyDocument: Object;
31
+ /** location代理 */
32
+ proxyLocation: Object;
33
+ /**
34
+ * 释放 window / document / location 代理。
35
+ * 代理的 handler 闭包捕获了 iframe / urlElement 等 DOM 引用,destroy 时调用此函数
36
+ * 解除代理与 handler 的关联,斩断「主应用 → 代理闭包 → iframe」的引用链。
37
+ */
38
+ proxyRevoke: () => void;
39
+ /** 事件中心 */
40
+ bus: EventBus;
41
+ /** 容器 */
42
+ el: HTMLElement;
43
+ /** js沙箱 */
44
+ iframe: HTMLIFrameElement;
45
+ /** css沙箱 */
46
+ shadowRoot: ShadowRoot;
47
+ /** 子应用的template */
48
+ template: string;
49
+ /** 子应用代码替换钩子 */
50
+ replace: (code: string) => string;
51
+ /** 子应用自定义fetch */
52
+ fetch: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
53
+ /** 子应用的生命周期 */
54
+ lifecycles: lifecycles;
55
+ /** 子应用的插件 */
56
+ plugins: Array<plugin>;
57
+ /** js沙箱ready态 */
58
+ iframeReady: Promise<void>;
59
+ /** 子应用预加载态 */
60
+ preload: Promise<void>;
61
+ /** 降级时渲染iframe的属性 */
62
+ degradeAttrs: {
63
+ [key: string]: any;
64
+ };
65
+ /** 子应用js执行队列 */
66
+ execQueue: Array<Function>;
67
+ /** 子应用执行过标志 */
68
+ execFlag: boolean;
69
+ /** 子应用激活标志 */
70
+ activeFlag: boolean;
71
+ /** 子应用mount标志 */
72
+ mountFlag: boolean;
73
+ /** 路由同步标志 */
74
+ sync: boolean;
75
+ /** 子应用短路径替换,路由同步时生效 */
76
+ prefix: {
77
+ [key: string]: string;
78
+ };
79
+ /** 子应用跳转标志 */
80
+ hrefFlag: boolean;
81
+ /** 子应用采用fiber模式执行 */
82
+ fiber: boolean;
83
+ /** 子应用降级标志 */
84
+ degrade: boolean;
85
+ /** 子应用降级document */
86
+ document: Document;
87
+ /** 子应用styleSheet元素 */
88
+ styleSheetElements: Array<HTMLLinkElement | HTMLStyleElement>;
89
+ /**
90
+ * 子应用通过 document.head.appendChild(<script>) 触发的动态脚本节点。
91
+ * 由 insertScriptToIframe 在收到 rawElement(即 effect.ts 转发的动态 script)
92
+ * 时登记,sandbox.destroy() 时统一从 iframe head detach 并清空。
93
+ */
94
+ dynamicScriptElements: Array<HTMLScriptElement>;
95
+ /**
96
+ * 动态 <link rel=stylesheet> 以空 href 插入(先 appendChild 后 setAttribute('href'),
97
+ * 如 tinymce 的 StyleSheetLoader)时,effect.ts 会注册一个 MutationObserver 监听
98
+ * href 的后续赋值。这些 observer 必须在 destroy 时统一 disconnect,否则游离 link
99
+ * 会通过 node → registered observer → callback 闭包链路把已销毁的 sandbox 钉在内存中。
100
+ */
101
+ deferredStyleObservers: Array<MutationObserver>;
102
+ /**
103
+ * 动态 <script src> 的串行执行链。每个 sandbox 独立一条,保证「同一子应用内」动态脚本
104
+ * 按插入顺序串行 fetch+exec;改为 per-sandbox 后,不同子应用之间不再相互阻塞,也避免
105
+ * 一个已销毁子应用的 pending 链把后续子应用的脚本拖在同一条全局 Promise 上。
106
+ */
107
+ dynamicScriptExecStack: Promise<void>;
108
+ /** 子应用head元素 */
109
+ head: HTMLHeadElement;
110
+ /** 子应用body元素 */
111
+ body: HTMLBodyElement;
112
+ /** 子应用dom监听事件留存,当降级时用于保存元素事件 */
113
+ elementEventCacheMap: WeakMap<Node, Array<ElementEventRecord>>;
114
+ /** 子应用window监听事件 */
115
+ iframeAddEventListeners?: Array<string>;
116
+ /** 子应用iframe on事件 */
117
+ iframeOnEvents?: Array<string>;
118
+ /** 销毁链路清理跟踪器:记录被转发到主应用 window/document 上的副作用,destroy 时统一回收 */
119
+ eventCleanupTracker: EventCleanupTracker;
120
+ /** 销毁状态:destroy 可能由宿主、WebComponent disconnectedCallback、降级 iframe unload 多路触发 */
121
+ private destroyed;
122
+ /** href 跳转 popstate 全局监听释放函数;由 sync.ts 引用计数保证只注册一次 */
123
+ private releaseHrefJumpListener;
124
+ /** XPE 子应用桥接对象 */
125
+ childBridge: {
126
+ bus: EventBus;
127
+ shadowRoot?: ShadowRoot;
128
+ props?: {
129
+ [key: string]: any;
130
+ };
131
+ location?: Object;
132
+ };
133
+ /** 子应用嵌套场景,父应用传递给子应用的数据 */
134
+ inject: {
135
+ idToSandboxMap: Map<String, SandboxCache>;
136
+ appEventObjMap: Map<String, EventObj>;
137
+ mainHostPath: string;
138
+ };
139
+ isDestroyed(): boolean;
140
+ getLifecycleWindow(): Window | undefined;
141
+ private getActiveIframeWindow;
142
+ private requireActiveIframeWindow;
143
+ private isCurrentIframeWindow;
144
+ private insertQueuedScriptWhenActive;
145
+ private insertAsyncScriptWhenActive;
146
+ /** 激活子应用
147
+ * 1、同步路由
148
+ * 2、动态修改iframe的fetch
149
+ * 3、准备shadow
150
+ * 4、准备子应用注入
151
+ */
152
+ active(options: {
153
+ url: string;
154
+ sync?: boolean;
155
+ prefix?: {
156
+ [key: string]: string;
157
+ };
158
+ template?: string;
159
+ el?: string | HTMLElement;
160
+ props?: {
161
+ [key: string]: any;
162
+ };
163
+ alive?: boolean;
164
+ fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>;
165
+ replace?: (code: string) => string;
166
+ }): Promise<void>;
167
+ requestIdleCallback(callback: any): number;
168
+ /** 启动子应用
169
+ * 1、运行js
170
+ * 2、处理兼容样式
171
+ */
172
+ start(getExternalScripts: () => ScriptResultList): Promise<void>;
173
+ /**
174
+ * 框架主动发起mount,如果子应用是异步渲染实例,比如将生命周期函数放到async函数内
175
+ * 此时如果采用fiber模式渲染(主应用调用mount的时机也是异步不确定的),框架调用mount时可能
176
+ * 子应用的mount函数还没有挂载到window,所以这里封装一个mount函数,当子应用是异步渲染
177
+ * 实例时,子应用异步函数里面最后加上window.__XPE__.mount()来主动调用
178
+ */
179
+ mount(): void;
180
+ recoverMountedEventListeners(): void;
181
+ /** 保活模式和使用proxyLocation.href跳转链接都不应该销毁shadow */
182
+ unmount(options?: {
183
+ allowDestroyed?: boolean;
184
+ preserveLifecycle?: boolean;
185
+ }): Promise<void>;
186
+ /** 销毁子应用 */
187
+ destroy(): Promise<void>;
188
+ /**
189
+ * destroy 阶段清空 styleSheetElements,同时把节点从父节点 detach。
190
+ *
191
+ * 仅供 destroy 调用:unmount 阶段需要保留数组以便 rebuildStyleSheets 复用样式节点
192
+ * (子应用 JS 模块只 init 一次,模块代码不会再次生成动态样式)。
193
+ */
194
+ clearStyleSheets(): void;
195
+ /**
196
+ * destroy 阶段清空 dynamicScriptElements,同时把残留的 <script> 节点从父节点 detach。
197
+ * 仅供 destroy 调用,理由同 clearStyleSheets。
198
+ */
199
+ clearDynamicScripts(): void;
200
+ /**
201
+ * unmount / destroy 阶段统一 disconnect 等待 href 赋值的 MutationObserver。
202
+ * observer 在 href 命中或超时兜底时会自行 disconnect 并出队;
203
+ * 这里兜底处理「子应用先于 href 赋值被卸载/销毁」的场景。
204
+ */
205
+ clearDeferredStyleObservers(): void;
206
+ /** 当子应用再次激活后,只运行mount函数,样式需要重新恢复 */
207
+ rebuildStyleSheets(): void;
208
+ /**
209
+ * 子应用样式打补丁
210
+ * 1、兼容:root选择器样式到:host选择器上
211
+ * 2、将@font-face定义到shadowRoot外部
212
+ */
213
+ patchCssRules(): void;
214
+ /**
215
+ * @param id 子应用的id,唯一标识
216
+ * @param url 子应用的url,可以包含protocol、host、path、query、hash
217
+ */
218
+ constructor(options: {
219
+ name: string;
220
+ url: string;
221
+ attrs: {
222
+ [key: string]: any;
223
+ };
224
+ degradeAttrs: {
225
+ [key: string]: any;
226
+ };
227
+ fiber: boolean;
228
+ degrade: any;
229
+ plugins: Array<plugin>;
230
+ lifecycles: lifecycles;
231
+ iframeAddEventListeners?: Array<string>;
232
+ iframeOnEvents?: Array<string>;
233
+ });
234
+ }
235
+ export {};