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,224 @@
1
+ import processTpl, { genLinkReplaceSymbol, getInlineStyleReplaceSymbol, } from "./template.js";
2
+ import { defaultGetPublicPath, getInlineCode, requestIdleCallback, error, compose, getCurUrl } from "./utils.js";
3
+ import { XPE_TIPS_NO_FETCH, XPE_TIPS_SCRIPT_ERROR_REQUESTED, XPE_TIPS_CSS_ERROR_REQUESTED, XPE_TIPS_HTML_ERROR_REQUESTED, } from "./constant.js";
4
+ import { getEffectLoaders, isMatchUrl } from "./plugin.js";
5
+ // 模块级资源缓存:导出仅供 clearAssetsCache 内部使用,外部代码勿直接 mutate
6
+ export const styleCache = {};
7
+ export const scriptCache = {};
8
+ export const embedHTMLCache = {};
9
+ /**
10
+ * 清空资源缓存:不传 host 时全清;传单个/数组 host 时按 url 前缀清。
11
+ * 用于热更新或多 host 子应用切换时主动失效,避免缓存命中已变更资源。
12
+ */
13
+ export function clearAssetsCache(host) {
14
+ const matchers = host == null ? null : Array.isArray(host) ? host : [host];
15
+ const matchAndDelete = (cache) => {
16
+ if (!matchers) {
17
+ Object.keys(cache).forEach((key) => delete cache[key]);
18
+ return;
19
+ }
20
+ Object.keys(cache).forEach((key) => {
21
+ if (matchers.some((prefix) => key.startsWith(prefix))) {
22
+ delete cache[key];
23
+ }
24
+ });
25
+ };
26
+ matchAndDelete(styleCache);
27
+ matchAndDelete(scriptCache);
28
+ matchAndDelete(embedHTMLCache);
29
+ }
30
+ function getEmbedHTMLCacheKey(url, plugins) {
31
+ const signature = plugins?.length
32
+ ? plugins
33
+ .map((plugin) => [
34
+ plugin.htmlLoader ? "htmlLoader" : "",
35
+ plugin.jsExcludes?.length ? `jsExcludes:${plugin.jsExcludes.length}` : "",
36
+ plugin.cssExcludes?.length ? `cssExcludes:${plugin.cssExcludes.length}` : "",
37
+ plugin.jsIgnores?.length ? `jsIgnores:${plugin.jsIgnores.length}` : "",
38
+ plugin.cssIgnores?.length ? `cssIgnores:${plugin.cssIgnores.length}` : "",
39
+ ]
40
+ .filter(Boolean)
41
+ .join("|"))
42
+ .join("::")
43
+ : "default";
44
+ return `${url}::${signature}`;
45
+ }
46
+ if (!window.fetch) {
47
+ error(XPE_TIPS_NO_FETCH);
48
+ throw new Error();
49
+ }
50
+ const defaultFetch = window.fetch.bind(window);
51
+ function defaultGetTemplate(tpl) {
52
+ return tpl;
53
+ }
54
+ /**
55
+ * 处理css-loader
56
+ */
57
+ export async function processCssLoader(sandbox, template, getExternalStyleSheets) {
58
+ const curUrl = getCurUrl(sandbox.proxyLocation);
59
+ /** css-loader */
60
+ const composeCssLoader = compose(sandbox.plugins.map((plugin) => plugin.cssLoader));
61
+ const processedCssList = getExternalStyleSheets().map(({ src, ignore, contentPromise }) => ({
62
+ src,
63
+ ignore,
64
+ contentPromise: contentPromise.then((content) => composeCssLoader(content, src, curUrl)),
65
+ }));
66
+ const embedHTML = await getEmbedHTML(template, processedCssList);
67
+ return sandbox.replace ? sandbox.replace(embedHTML) : embedHTML;
68
+ }
69
+ /**
70
+ * convert external css link to inline style for performance optimization
71
+ * @return embedHTML
72
+ */
73
+ async function getEmbedHTML(template, styleResultList) {
74
+ let embedHTML = template;
75
+ return Promise.all(styleResultList.map((styleResult, index) => styleResult.contentPromise.then((content) => {
76
+ // 用函数式替换:String.replace 的字符串参数会把 content 里的 $&、$1、$$ 等
77
+ // 当作替换模式解释,css 文本(尤其 @font-face base64、content: "$1" 等)一旦
78
+ // 命中就会被破坏。函数形式返回的字符串原样写入,杜绝 $ 序列污染。
79
+ if (styleResult.src) {
80
+ const replacement = styleResult.ignore
81
+ ? `<link href="${styleResult.src}" rel="stylesheet" type="text/css">`
82
+ : `<style>/* ${styleResult.src} */${content}</style>`;
83
+ embedHTML = embedHTML.replace(genLinkReplaceSymbol(styleResult.src), () => replacement);
84
+ }
85
+ else if (content) {
86
+ const replacement = `<style>/* inline-style-${index} */${content}</style>`;
87
+ embedHTML = embedHTML.replace(getInlineStyleReplaceSymbol(index), () => replacement);
88
+ }
89
+ }))).then(() => embedHTML);
90
+ }
91
+ const isInlineCode = (code) => code.startsWith("<");
92
+ const fetchAssets = (src, cache, fetch, cssFlag, loadError) => cache[src] ||
93
+ (cache[src] = fetch(src)
94
+ .then((response) => {
95
+ // usually browser treats 4xx and 5xx response of script loading as an error and will fire a script error event
96
+ // https://stackoverflow.com/questions/5625420/what-http-headers-responses-trigger-the-onerror-handler-on-a-script-tag/5625603
97
+ if (response.status >= 400) {
98
+ cache[src] = null;
99
+ if (cssFlag) {
100
+ error(XPE_TIPS_CSS_ERROR_REQUESTED, { src, response });
101
+ loadError?.(src, new Error(XPE_TIPS_CSS_ERROR_REQUESTED));
102
+ return "";
103
+ }
104
+ else {
105
+ error(XPE_TIPS_SCRIPT_ERROR_REQUESTED, { src, response });
106
+ loadError?.(src, new Error(XPE_TIPS_SCRIPT_ERROR_REQUESTED));
107
+ throw new Error(XPE_TIPS_SCRIPT_ERROR_REQUESTED);
108
+ }
109
+ }
110
+ return response.text();
111
+ })
112
+ .catch((e) => {
113
+ cache[src] = null;
114
+ if (cssFlag) {
115
+ error(XPE_TIPS_CSS_ERROR_REQUESTED, src);
116
+ loadError?.(src, e);
117
+ return "";
118
+ }
119
+ else {
120
+ error(XPE_TIPS_SCRIPT_ERROR_REQUESTED, src);
121
+ loadError?.(src, e);
122
+ return "";
123
+ }
124
+ }));
125
+ // for prefetch
126
+ export function getExternalStyleSheets(styles, fetch = defaultFetch, loadError) {
127
+ return styles.map(({ src, content, ignore }) => {
128
+ // 内联
129
+ if (content) {
130
+ return { src: "", contentPromise: Promise.resolve(content) };
131
+ }
132
+ else if (isInlineCode(src)) {
133
+ // if it is inline style
134
+ return { src: "", contentPromise: Promise.resolve(getInlineCode(src)) };
135
+ }
136
+ else {
137
+ // external styles
138
+ return {
139
+ src,
140
+ ignore,
141
+ contentPromise: ignore ? Promise.resolve("") : fetchAssets(src, styleCache, fetch, true, loadError),
142
+ };
143
+ }
144
+ });
145
+ }
146
+ // for prefetch
147
+ export function getExternalScripts(scripts, fetch = defaultFetch, loadError, fiber) {
148
+ // module should be requested in iframe
149
+ return scripts.map((script) => {
150
+ const { src, async, defer, module, ignore } = script;
151
+ let contentPromise = null;
152
+ // async
153
+ if ((async || defer) && src && !module) {
154
+ contentPromise = new Promise((resolve, reject) => fiber
155
+ ? requestIdleCallback(() => fetchAssets(src, scriptCache, fetch, false, loadError).then(resolve, reject))
156
+ : fetchAssets(src, scriptCache, fetch, false, loadError).then(resolve, reject));
157
+ // module || ignore
158
+ }
159
+ else if ((module && src) || ignore) {
160
+ contentPromise = Promise.resolve("");
161
+ // inline
162
+ }
163
+ else if (!src) {
164
+ contentPromise = Promise.resolve(script.content);
165
+ // outline
166
+ }
167
+ else {
168
+ contentPromise = fetchAssets(src, scriptCache, fetch, false, loadError);
169
+ }
170
+ // refer https://html.spec.whatwg.org/multipage/scripting.html#attr-script-defer
171
+ if (module && !async)
172
+ script.defer = true;
173
+ return { ...script, contentPromise };
174
+ });
175
+ }
176
+ export default function importHTML(params) {
177
+ const { url, opts, html } = params;
178
+ const fetch = opts.fetch ?? defaultFetch;
179
+ const fiber = opts.fiber ?? true;
180
+ const { plugins, loadError } = opts;
181
+ const htmlLoader = plugins ? compose(plugins.map((plugin) => plugin.htmlLoader)) : defaultGetTemplate;
182
+ const jsExcludes = getEffectLoaders("jsExcludes", plugins);
183
+ const cssExcludes = getEffectLoaders("cssExcludes", plugins);
184
+ const jsIgnores = getEffectLoaders("jsIgnores", plugins);
185
+ const cssIgnores = getEffectLoaders("cssIgnores", plugins);
186
+ const getPublicPath = defaultGetPublicPath;
187
+ const cacheKey = getEmbedHTMLCacheKey(url, plugins);
188
+ const getHtmlParseResult = (url, html, htmlLoader) => (html
189
+ ? Promise.resolve(html)
190
+ : fetch(url)
191
+ .then((response) => {
192
+ if (response.status >= 400) {
193
+ error(XPE_TIPS_HTML_ERROR_REQUESTED, { url, response });
194
+ loadError?.(url, new Error(XPE_TIPS_HTML_ERROR_REQUESTED));
195
+ return "";
196
+ }
197
+ return response.text();
198
+ })
199
+ .catch((e) => {
200
+ embedHTMLCache[cacheKey] = null;
201
+ loadError?.(url, e);
202
+ return Promise.reject(e);
203
+ })).then((html) => {
204
+ const assetPublicPath = getPublicPath(url);
205
+ const { template, scripts, styles } = processTpl(htmlLoader(html), assetPublicPath);
206
+ return {
207
+ template: template,
208
+ assetPublicPath,
209
+ getExternalScripts: () => getExternalScripts(scripts
210
+ .filter((script) => !script.src || !isMatchUrl(script.src, jsExcludes))
211
+ .map((script) => ({ ...script, ignore: script.src && isMatchUrl(script.src, jsIgnores) })), fetch, loadError, fiber),
212
+ getExternalStyleSheets: () => getExternalStyleSheets(styles
213
+ .filter((style) => !style.src || !isMatchUrl(style.src, cssExcludes))
214
+ .map((style) => ({ ...style, ignore: style.src && isMatchUrl(style.src, cssIgnores) })), fetch, loadError),
215
+ };
216
+ });
217
+ if (opts?.plugins?.some((plugin) => plugin.htmlLoader)) {
218
+ return getHtmlParseResult(url, html, htmlLoader);
219
+ // 没有html-loader可以做缓存
220
+ }
221
+ else {
222
+ return embedHTMLCache[cacheKey] || (embedHTMLCache[cacheKey] = getHtmlParseResult(url, html, htmlLoader));
223
+ }
224
+ }
@@ -0,0 +1,22 @@
1
+ export type EventObj = {
2
+ [event: string]: Array<Function>;
3
+ };
4
+ export declare const appEventObjMap: Map<String, EventObj>;
5
+ export declare class EventBus {
6
+ private id;
7
+ private eventObj;
8
+ constructor(id: string);
9
+ $on(event: string, fn: Function): EventBus;
10
+ /** 任何$emit都会导致监听函数触发,第一个参数为事件名,后续的参数为$emit的参数 */
11
+ $onAll(fn: (event: string, ...args: Array<any>) => any): EventBus;
12
+ $once(event: string, fn: Function): void;
13
+ $off(event: string, fn: Function): EventBus;
14
+ $offAll(fn: Function): EventBus;
15
+ $emit(event: string, ...args: Array<any>): EventBus;
16
+ $clear(): EventBus;
17
+ /**
18
+ * 销毁 EventBus:先 $clear 再从全局 appEventObjMap 中移除当前 id 的 entry。
19
+ * 防止 sandbox.destroy() 之后该子应用仍长期占用一项 map 条目。
20
+ */
21
+ $destroy(): void;
22
+ }
@@ -0,0 +1,120 @@
1
+ import { warn, error } from "./utils.js";
2
+ import { XPE_ALL_EVENT, XPE_TIPS_NO_SUBJECT } from "./constant.js";
3
+ import { getXpeInject, getXpeInternalSandbox, isPoweredByXpe, setXpeInject } from "./xpe-bridge.js";
4
+ // 全部事件存储 map
5
+ // 除了挂载到 sandbox 实例上,还挂载到 XPE inject 全局上,防止重复创建
6
+ export const appEventObjMap = (() => {
7
+ const inject = getXpeInject(window);
8
+ if (inject?.appEventObjMap)
9
+ return inject.appEventObjMap;
10
+ else {
11
+ const cacheMap = (isPoweredByXpe(window) ? getXpeInternalSandbox(window)?.inject?.appEventObjMap : undefined) ??
12
+ new Map();
13
+ setXpeInject(window, { appEventObjMap: cacheMap });
14
+ return cacheMap;
15
+ }
16
+ })();
17
+ // eventBus 事件中心
18
+ export class EventBus {
19
+ constructor(id) {
20
+ Object.defineProperty(this, "id", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: void 0
25
+ });
26
+ Object.defineProperty(this, "eventObj", {
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true,
30
+ value: void 0
31
+ });
32
+ this.id = id;
33
+ this.$clear();
34
+ if (!appEventObjMap.get(this.id)) {
35
+ appEventObjMap.set(this.id, {});
36
+ }
37
+ this.eventObj = appEventObjMap.get(this.id);
38
+ }
39
+ // 监听事件
40
+ $on(event, fn) {
41
+ const cbs = this.eventObj[event];
42
+ if (!cbs) {
43
+ this.eventObj[event] = [fn];
44
+ return this;
45
+ }
46
+ if (!cbs.includes(fn))
47
+ cbs.push(fn);
48
+ return this;
49
+ }
50
+ /** 任何$emit都会导致监听函数触发,第一个参数为事件名,后续的参数为$emit的参数 */
51
+ $onAll(fn) {
52
+ return this.$on(XPE_ALL_EVENT, fn);
53
+ }
54
+ // 一次性监听事件
55
+ $once(event, fn) {
56
+ const on = function (...args) {
57
+ this.$off(event, on);
58
+ fn(...args);
59
+ }.bind(this);
60
+ this.$on(event, on);
61
+ }
62
+ // 取消监听
63
+ $off(event, fn) {
64
+ const cbs = this.eventObj[event];
65
+ if (!event || !cbs || !cbs.length) {
66
+ warn(`${event} ${XPE_TIPS_NO_SUBJECT}`);
67
+ return this;
68
+ }
69
+ let cb;
70
+ let i = cbs.length;
71
+ while (i--) {
72
+ cb = cbs[i];
73
+ if (cb === fn) {
74
+ cbs.splice(i, 1);
75
+ break;
76
+ }
77
+ }
78
+ return this;
79
+ }
80
+ // 取消监听$onAll
81
+ $offAll(fn) {
82
+ return this.$off(XPE_ALL_EVENT, fn);
83
+ }
84
+ // 发送事件
85
+ $emit(event, ...args) {
86
+ const cbs = [...(this.eventObj[event] ?? [])];
87
+ const allCbs = [...(this.eventObj[XPE_ALL_EVENT] ?? [])];
88
+ if (!event || (cbs.length === 0 && allCbs.length === 0)) {
89
+ warn(`${event} ${XPE_TIPS_NO_SUBJECT}`);
90
+ }
91
+ else {
92
+ try {
93
+ for (let i = 0, l = cbs.length; i < l; i++)
94
+ cbs[i](...args);
95
+ for (let i = 0, l = allCbs.length; i < l; i++)
96
+ allCbs[i](event, ...args);
97
+ }
98
+ catch (e) {
99
+ error(e);
100
+ }
101
+ }
102
+ return this;
103
+ }
104
+ // 清空当前所有的监听事件
105
+ $clear() {
106
+ const eventObj = appEventObjMap.get(this.id) ?? {};
107
+ const events = Object.keys(eventObj);
108
+ events.forEach((event) => delete eventObj[event]);
109
+ return this;
110
+ }
111
+ /**
112
+ * 销毁 EventBus:先 $clear 再从全局 appEventObjMap 中移除当前 id 的 entry。
113
+ * 防止 sandbox.destroy() 之后该子应用仍长期占用一项 map 条目。
114
+ */
115
+ $destroy() {
116
+ this.$clear();
117
+ appEventObjMap.delete(this.id);
118
+ this.eventObj = {};
119
+ }
120
+ }
@@ -0,0 +1,141 @@
1
+ import RuntimeSandbox from "./sandbox.js";
2
+ import { ScriptObject } from "./template.js";
3
+ import { ScriptObjectLoader } from "./runtime-engine.js";
4
+ import { type XpeEventListenerRecord } from "./xpe-bridge.js";
5
+ export type ElementEventRecord = {
6
+ type: string;
7
+ handler: EventListenerOrEventListenerObject;
8
+ callback: EventListenerOrEventListenerObject;
9
+ options: any;
10
+ };
11
+ declare global {
12
+ interface Window {
13
+ __POWERED_BY_XPE__?: boolean;
14
+ __XPE_PUBLIC_PATH__: string;
15
+ __XPE_RAW_DOCUMENT_QUERY_SELECTOR__: typeof Document.prototype.querySelector;
16
+ __XPE_RAW_DOCUMENT_CREATE_ELEMENT__: typeof Document.prototype.createElement;
17
+ __XPE_RAW_DOCUMENT_CREATE_TEXT_NODE__: typeof Document.prototype.createTextNode;
18
+ __XPE_RAW_DOCUMENT_HEAD__: typeof Document.prototype.head;
19
+ __XPE_RAW_DOCUMENT_QUERY_SELECTOR_ALL__: typeof Document.prototype.querySelectorAll;
20
+ __XPE_RAW_WINDOW__: Window;
21
+ __XPE_INTERNAL_SANDBOX__?: RuntimeSandbox;
22
+ __XPE_INJECT__?: Partial<RuntimeSandbox["inject"]>;
23
+ __XPE_EVENTLISTENER__: Set<XpeEventListenerRecord>;
24
+ __XPE_MOUNT__: () => void;
25
+ __XPE_UNMOUNT__: () => void | Promise<void>;
26
+ Document: typeof Document;
27
+ HTMLImageElement: typeof HTMLImageElement;
28
+ Node: typeof Node;
29
+ Element: typeof Element;
30
+ HTMLElement: typeof HTMLElement;
31
+ HTMLAnchorElement: typeof HTMLAnchorElement;
32
+ HTMLSourceElement: typeof HTMLSourceElement;
33
+ HTMLLinkElement: typeof HTMLLinkElement;
34
+ HTMLScriptElement: typeof HTMLScriptElement;
35
+ HTMLMediaElement: typeof HTMLMediaElement;
36
+ EventTarget: typeof EventTarget;
37
+ Event: typeof Event;
38
+ ShadowRoot: typeof ShadowRoot;
39
+ }
40
+ interface HTMLHeadElement {
41
+ _cacheListeners: Map<string, EventListenerOrEventListenerObject[]>;
42
+ }
43
+ interface HTMLBodyElement {
44
+ _cacheListeners: Map<string, EventListenerOrEventListenerObject[]>;
45
+ }
46
+ interface Document {
47
+ createTreeWalker(root: Node, whatToShow?: number, filter?: NodeFilter | null, entityReferenceExpansion?: boolean): TreeWalker;
48
+ }
49
+ }
50
+ /**
51
+ * patch iframe window effect
52
+ * @param iframeWindow
53
+ */
54
+ export declare function patchWindowEffect(iframeWindow: Window): void;
55
+ /**
56
+ * 让 targetWindow 上的 DOM 构造函数 instanceof 同时认可 peerWindow realm 的对象。
57
+ * 非降级:targetWindow=子应用 JS iframe,peerWindow=主应用 window(DOM 在 shadowRoot)。
58
+ * 降级:在 patchDegradeInstanceofAcrossRealms 中对渲染 iframe 与执行 iframe 双向调用。
59
+ */
60
+ export declare function patchInstanceofAcrossRealms(targetWindow: Window, peerWindow?: Window): void;
61
+ /**
62
+ * 降级模式:DOM 在渲染 iframe、JS 在执行 iframe,对两侧 window 双向 patch instanceof。
63
+ * 需在 sandbox.document(渲染 document)就绪后调用,勿在 patchWindowEffect 阶段调用。
64
+ */
65
+ export declare function patchDegradeInstanceofAcrossRealms(appWindow: Window, renderWindow: Window): void;
66
+ /**
67
+ * 恢复节点的监听事件
68
+ */
69
+ export declare function recoverEventListeners(rootElement: Node, iframeWindow: Window): void;
70
+ /**
71
+ * 恢复根节点的监听事件
72
+ */
73
+ export declare function recoverDocumentListeners(oldRootElement: Node, newRootElement: Node, iframeWindow: Window): void;
74
+ export declare function recoverShadowRootEventListeners(iframeWindow: Window): void;
75
+ /**
76
+ * 修复vue绑定事件e.timeStamp < attachedTimestamp 的情况
77
+ */
78
+ export declare function patchEventTimeStamp(targetWindow: Window, iframeWindow: Window): void;
79
+ /**
80
+ * patch document effect
81
+ * @param iframeWindow
82
+ */
83
+ export declare function patchDocumentEffect(iframeWindow: Window): void;
84
+ /**
85
+ * 初始化 base 标签,供 document 内相对路径资源解析使用。
86
+ * @param pathname 可选;降级渲染 iframe 的 location 为 about:blank,需传入 proxyLocation.pathname
87
+ */
88
+ export declare function initBase(iframeWindow: Window, url: string, pathname?: string): void;
89
+ /**
90
+ * 给子应用元素打上 baseURI / ownerDocument 补丁,让它在主应用 DOM 中也保留子应用
91
+ * 的 location / document 语义。
92
+ *
93
+ * 闭包持有策略:用 WeakRef<Window> 间接持有 iframeWindow,proxyLocation / plugins
94
+ * 都通过 iframeWindow 上的内部沙盒全局动态访问。这样一来,当子应用 element 被业务移到
95
+ * 主应用 DOM 下(portal / 弹窗 / 拖拽等),sandbox.destroy() 清理内部沙盒全局后,
96
+ * getter 会自动降级到主 document,element 不会把整个子应用上下文钉在内存中。
97
+ *
98
+ * WeakRef 是 ES2021 标准(Chrome 84+ / Node 14.6+);旧环境降级为强引用以保兼容。
99
+ */
100
+ export declare function patchElementEffect(element: (HTMLElement | Node | ShadowRoot) & {
101
+ _hasPatch?: boolean;
102
+ }, iframeWindow: Window): void;
103
+ /**
104
+ * 子应用前进后退,同步路由到主应用
105
+ * @param iframeWindow
106
+ */
107
+ export declare function syncIframeUrlToWindow(iframeWindow: Window): void;
108
+ /**
109
+ * iframe插入脚本
110
+ * @param scriptResult script请求结果
111
+ * @param iframeWindow
112
+ * @param rawElement 原始的脚本
113
+ */
114
+ export declare function insertScriptToIframe(scriptResult: ScriptObject | ScriptObjectLoader, iframeWindow: Window, rawElement?: HTMLScriptElement): void;
115
+ /**
116
+ * 加载iframe替换子应用
117
+ * @param src 地址
118
+ * @param element
119
+ * @param degradeAttrs
120
+ */
121
+ export declare function renderIframeReplaceApp(src: string, element: HTMLElement, degradeAttrs?: {
122
+ [key: string]: any;
123
+ }): void;
124
+ /**
125
+ * js沙箱
126
+ * 创建和主应用同源的iframe,路径携带了子路由的路由信息
127
+ * iframe必须禁止加载html,防止进入主应用的路由逻辑
128
+ *
129
+ * 统一使用 srcdoc 加载空白文档:
130
+ * - 不发任何请求加载主应用 host 资源(解决 issue #54)
131
+ * - origin 继承自 embedder,主应用可以正常 patch contentDocument
132
+ * - 之后通过 document.open() 把 iframe 的 location 改写到主应用 URL,
133
+ * 使 location.origin、history、router 等行为与主应用同源一致
134
+ *
135
+ * attrs.src 不再作为 iframe 的初始 src(HTML spec 规定 srcdoc 优先级高于 src,
136
+ * 即便保留 src 浏览器也会忽略它)。它被重新解释为「srcdoc trick 失败时的兜底空白页 URL」,
137
+ * 用户可指向自己提供的 `/empty` 静态文件或 Service Worker 端点;不传则兜底 mainHostPath。
138
+ */
139
+ export declare function iframeGenerator(sandbox: RuntimeSandbox, attrs: {
140
+ [key: string]: any;
141
+ }, mainHostPath: string, appHostPath: string, appRoutePath: string): HTMLIFrameElement;