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,25 @@
1
+ import { type AppBridge, type AppContext, type AppManifest, type RemoteRuntimeConfig } from "../core/index.js";
2
+ export type RuntimeContainer = HTMLElement | string;
3
+ export type RuntimeBridgeFactory = (options: {
4
+ manifest: AppManifest;
5
+ context: AppContext;
6
+ }) => AppBridge;
7
+ export type RuntimeStartOptions = {
8
+ manifest: AppManifest;
9
+ context: AppContext;
10
+ container: RuntimeContainer;
11
+ bridge: AppBridge;
12
+ };
13
+ export type RuntimePreloadOptions = {
14
+ manifest: AppManifest;
15
+ };
16
+ export type RuntimeDestroyOptions = {
17
+ appCode: string;
18
+ runtime: RemoteRuntimeConfig;
19
+ };
20
+ export type RuntimeKernel = {
21
+ preload(options: RuntimePreloadOptions): void;
22
+ start(options: RuntimeStartOptions): Promise<void>;
23
+ destroy(options: RuntimeDestroyOptions): Promise<void>;
24
+ };
25
+ export declare function createRuntimeKernel(): RuntimeKernel;
@@ -0,0 +1,86 @@
1
+ import { XpeRuntimeError, } from "../core/index.js";
2
+ let runtimeEngineModule;
3
+ let runtimeEngineModulePromise;
4
+ export function createRuntimeKernel() {
5
+ return {
6
+ preload({ manifest }) {
7
+ void loadRuntimeEngine().then(({ preloadApp }) => {
8
+ preloadApp(toEnginePreloadOptions(manifest));
9
+ });
10
+ },
11
+ async start(options) {
12
+ const { startApp } = await loadRuntimeEngine();
13
+ await startApp(toEngineStartOptions(options));
14
+ },
15
+ async destroy(options) {
16
+ const destroy = ({ destroyApp }) => destroyApp(options.runtime.name || options.appCode);
17
+ if (runtimeEngineModule) {
18
+ await destroy(runtimeEngineModule);
19
+ return;
20
+ }
21
+ await loadRuntimeEngine().then(destroy);
22
+ },
23
+ };
24
+ }
25
+ function loadRuntimeEngine() {
26
+ if (runtimeEngineModule)
27
+ return Promise.resolve(runtimeEngineModule);
28
+ if (!runtimeEngineModulePromise) {
29
+ const runtimeEnginePath = "./runtime-engine.js";
30
+ runtimeEngineModulePromise = import(runtimeEnginePath).then((module) => {
31
+ runtimeEngineModule = module;
32
+ return runtimeEngineModule;
33
+ });
34
+ }
35
+ return runtimeEngineModulePromise;
36
+ }
37
+ function toEnginePreloadOptions(manifest) {
38
+ const { runtime } = manifest;
39
+ const runtimeName = runtime.name ?? manifest.appCode;
40
+ return {
41
+ name: runtimeName,
42
+ url: runtime.url,
43
+ alive: runtime.alive,
44
+ sync: runtime.sync,
45
+ prefix: toRuntimePrefix(runtime),
46
+ fetch: toRuntimeFetch(runtime.credentials),
47
+ props: {
48
+ appCode: manifest.appCode,
49
+ manifest,
50
+ runtime,
51
+ },
52
+ };
53
+ }
54
+ function toEngineStartOptions(options) {
55
+ const { manifest, context, bridge } = options;
56
+ return {
57
+ ...toEnginePreloadOptions(manifest),
58
+ el: toRuntimeContainer(options.container, manifest.appCode),
59
+ props: {
60
+ appCode: manifest.appCode,
61
+ context,
62
+ manifest,
63
+ runtime: manifest.runtime,
64
+ bridge,
65
+ },
66
+ };
67
+ }
68
+ function toRuntimeContainer(container, appCode) {
69
+ if (typeof container === "string")
70
+ return container;
71
+ if (container instanceof HTMLElement)
72
+ return container;
73
+ throw new XpeRuntimeError("XPE_CONTAINER_MISSING", "XPE 应用挂载容器必须是 HTMLElement 或选择器", {
74
+ appCode,
75
+ });
76
+ }
77
+ function toRuntimePrefix(runtime) {
78
+ if (!runtime.basename || !runtime.name)
79
+ return undefined;
80
+ return { [runtime.name]: runtime.basename };
81
+ }
82
+ function toRuntimeFetch(credentials) {
83
+ if (!credentials)
84
+ return undefined;
85
+ return (input, init) => window.fetch(input, { ...init, credentials: init?.credentials ?? credentials });
86
+ }
@@ -0,0 +1,36 @@
1
+ import { plugin } from "./runtime-engine.js";
2
+ interface loaderOption {
3
+ plugins: Array<plugin>;
4
+ replace: (code: string) => string;
5
+ }
6
+ /**
7
+ * 获取柯里化 cssLoader
8
+ */
9
+ export declare function getCssLoader({ plugins, replace }: loaderOption): (code: string, src: string, base: string) => string;
10
+ /**
11
+ * 获取柯里化 jsLoader
12
+ */
13
+ export declare function getJsLoader({ plugins, replace }: loaderOption): (code: string, src: string, base: string) => string;
14
+ /**
15
+ * 获取预置插件
16
+ */
17
+ type presetLoadersType = "cssBeforeLoaders" | "cssAfterLoaders" | "jsBeforeLoaders" | "jsAfterLoaders";
18
+ export declare function getPresetLoaders(loaderType: presetLoadersType, plugins: Array<plugin>): plugin[presetLoadersType];
19
+ /**
20
+ * 获取影响插件
21
+ */
22
+ type effectLoadersType = "jsExcludes" | "cssExcludes" | "jsIgnores" | "cssIgnores";
23
+ export declare function getEffectLoaders(loaderType: effectLoadersType, plugins: Array<plugin>): plugin[effectLoadersType];
24
+ export declare function isMatchUrl(url: string, effectLoaders: plugin[effectLoadersType]): boolean;
25
+ /**
26
+ * 转换子应用css内的相对地址成绝对地址
27
+ */
28
+ declare function cssRelativePathResolve(code: string, src: string, base: string): string;
29
+ declare const defaultPlugin: {
30
+ cssLoader: typeof cssRelativePathResolve;
31
+ cssBeforeLoaders: {
32
+ content: string;
33
+ }[];
34
+ };
35
+ export declare function getPlugins(plugins: Array<plugin>): Array<plugin>;
36
+ export default defaultPlugin;
@@ -0,0 +1,68 @@
1
+ import { compose, getAbsolutePath } from "./utils.js";
2
+ /**
3
+ * 获取柯里化 cssLoader
4
+ */
5
+ export function getCssLoader({ plugins, replace }) {
6
+ return (code, src = "", base) => compose(plugins.map((plugin) => plugin.cssLoader))(replace ? replace(code) : code, src, base);
7
+ }
8
+ /**
9
+ * 获取柯里化 jsLoader
10
+ */
11
+ export function getJsLoader({ plugins, replace }) {
12
+ return (code, src = "", base) => compose(plugins.map((plugin) => plugin.jsLoader))(replace ? replace(code) : code, src, base);
13
+ }
14
+ export function getPresetLoaders(loaderType, plugins) {
15
+ const loaders = plugins
16
+ .map((plugin) => plugin[loaderType])
17
+ .filter((loaders) => loaders?.length);
18
+ const res = loaders.reduce((preLoaders, curLoaders) => preLoaders.concat(curLoaders), []);
19
+ return loaderType === "cssBeforeLoaders" ? res.reverse() : res;
20
+ }
21
+ export function getEffectLoaders(loaderType, plugins) {
22
+ return plugins
23
+ .map((plugin) => plugin[loaderType])
24
+ .filter((loaders) => loaders?.length)
25
+ .reduce((preLoaders, curLoaders) => preLoaders.concat(curLoaders), []);
26
+ }
27
+ // 判断 url 是否符合loader的规则
28
+ export function isMatchUrl(url, effectLoaders) {
29
+ return effectLoaders.some((loader) => (typeof loader === "string" ? url === loader : loader.test(url)));
30
+ }
31
+ /**
32
+ * 转换子应用css内的相对地址成绝对地址
33
+ */
34
+ function cssRelativePathResolve(code, src, base) {
35
+ const baseUrl = src ? getAbsolutePath(src, base) : base;
36
+ /**
37
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/url
38
+ *
39
+ * 旧: const urlReg = /(url\((?!['"]?(?:data):)['"]?)([^'")]*)(['"]?\))/g;
40
+ *
41
+ * 这里修改一下正则匹配,先匹配url(xxx)内的xxx,需要兼容一下嵌套括号,
42
+ * 再判断是否为base64,不再预先忽略data:前缀,防止base64的svg内仍有url被匹配
43
+ *
44
+ * eg:
45
+ * background: url(data:image/svg+xml;charset=utf-8,<svg><path fill=url(#a)></path></svg>)
46
+ * 以上样式会匹配出#a并进行修改,svg填充的路径就出问题了。
47
+ *
48
+ * */
49
+ const urlReg = /url\((['"]?)((?:[^()]+|\((?:[^()]+|\([^()]*\))*\))*)(\1)\)/g;
50
+ return code.replace(urlReg, (_m, pre, url, post) => {
51
+ const base64Regx = /^data:/;
52
+ const isBase64 = base64Regx.test(url);
53
+ /** 如果匹配到data:前缀,则认为是base64文件,直接不进行路径替换吧 */
54
+ if (isBase64) {
55
+ return _m;
56
+ }
57
+ return `url(${pre}${getAbsolutePath(url, baseUrl)}${post})`;
58
+ });
59
+ }
60
+ const defaultPlugin = {
61
+ cssLoader: cssRelativePathResolve,
62
+ // 禁用 view-transition 继承,避免子应用切换时污染宿主页面动效。
63
+ cssBeforeLoaders: [{ content: "html {view-transition-name: none;}" }],
64
+ };
65
+ export function getPlugins(plugins) {
66
+ return Array.isArray(plugins) ? [defaultPlugin, ...plugins] : [defaultPlugin];
67
+ }
68
+ export default defaultPlugin;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 非降级情况下window、document、location代理
3
+ */
4
+ export declare function proxyGenerator(iframe: HTMLIFrameElement, urlElement: HTMLAnchorElement, mainHostPath: string, appHostPath: string): {
5
+ proxyWindow: Window;
6
+ proxyDocument: Object;
7
+ proxyLocation: Object;
8
+ proxyRevoke: () => void;
9
+ };
10
+ /**
11
+ * 降级情况下document、location代理处理
12
+ */
13
+ export declare function localGenerator(iframe: HTMLIFrameElement, urlElement: HTMLAnchorElement, mainHostPath: string, appHostPath: string): {
14
+ proxyDocument: Object;
15
+ proxyLocation: Object;
16
+ proxyRevoke: () => void;
17
+ };
@@ -0,0 +1,440 @@
1
+ import { patchElementEffect, renderIframeReplaceApp } from "./iframe.js";
2
+ import { renderElementToContainer } from "./shadow.js";
3
+ import { pushUrlToWindow } from "./sync.js";
4
+ import { documentProxyProperties, rawDocumentQuerySelector } from "./common.js";
5
+ import { XPE_TIPS_RELOAD_DISABLED, XPE_TIPS_GET_ELEMENT_BY_ID } from "./constant.js";
6
+ import { getTargetValue, anchorElementGenerator, getDegradeIframe, isCallable, checkProxyFunction, warn, stopMainAppRun, } from "./utils.js";
7
+ import { getXpeInternalSandbox, getXpeRawDocumentCreateElement, getXpeRawDocumentCreateTextNode, getXpeRawDocumentHead, getXpeRawDocumentQuerySelector, getXpeRawDocumentQuerySelectorAll, } from "./xpe-bridge.js";
8
+ /**
9
+ * location href 的set劫持操作
10
+ */
11
+ function locationHrefSet(iframe, value, appHostPath) {
12
+ const iframeWindow = getIframeWindow(iframe);
13
+ const iframeDocument = getIframeDocument(iframe);
14
+ const sandbox = getActiveSandbox(getXpeInternalSandbox(iframeWindow));
15
+ const { shadowRoot, id, degrade, document, degradeAttrs } = sandbox;
16
+ let url = value;
17
+ if (!/^http/.test(url)) {
18
+ const hrefElement = anchorElementGenerator(url);
19
+ url = appHostPath + hrefElement.pathname + hrefElement.search + hrefElement.hash;
20
+ }
21
+ sandbox.hrefFlag = true;
22
+ if (degrade) {
23
+ const iframeBody = getHtmlElement(rawDocumentQuerySelector.call(iframeDocument, "body"));
24
+ const degradeContainer = getElementParent(getHtmlElement(getDegradeIframe(id)));
25
+ renderElementToContainer(document.documentElement, iframeBody);
26
+ renderIframeReplaceApp(window.decodeURIComponent(url), degradeContainer, degradeAttrs);
27
+ }
28
+ else
29
+ renderIframeReplaceApp(url, getElementParent(shadowRoot.host), degradeAttrs);
30
+ pushUrlToWindow(id, url);
31
+ return true;
32
+ }
33
+ /**
34
+ * 非降级情况下window、document、location代理
35
+ */
36
+ export function proxyGenerator(iframe, urlElement, mainHostPath, appHostPath) {
37
+ const iframeWindow = getIframeWindow(iframe);
38
+ const iframeDocument = getIframeDocument(iframe);
39
+ const { proxy: proxyWindow, revoke: revokeWindow } = Proxy.revocable(iframeWindow, {
40
+ get: (target, p) => {
41
+ // location进行劫持
42
+ if (p === "location") {
43
+ return getActiveSandbox(getXpeInternalSandbox(target)).proxyLocation;
44
+ }
45
+ // 判断自身
46
+ if (p === "self" || (p === "window" && Object.getOwnPropertyDescriptor(window, "window").get)) {
47
+ return getActiveSandbox(getXpeInternalSandbox(target)).proxy;
48
+ }
49
+ // https://262.ecma-international.org/8.0/#sec-proxy-object-internal-methods-and-internal-slots-get-p-receiver
50
+ const descriptor = Object.getOwnPropertyDescriptor(target, p);
51
+ if (descriptor?.configurable === false && descriptor?.writable === false) {
52
+ return target[p];
53
+ }
54
+ // 修正this指针指向
55
+ return getTargetValue(target, p);
56
+ },
57
+ set: (target, p, value) => {
58
+ checkProxyFunction(target, value);
59
+ target[p] = value;
60
+ return true;
61
+ },
62
+ has: (target, p) => p in target,
63
+ });
64
+ // proxy document
65
+ const { proxy: proxyDocument, revoke: revokeDocument } = Proxy.revocable({}, {
66
+ get: function (_fakeDocument, propKey) {
67
+ const document = window.document;
68
+ const { shadowRoot, proxyLocation } = getActiveSandbox(getXpeInternalSandbox(iframeWindow));
69
+ // iframe初始化完成后,webcomponent还未挂在上去,此时运行了主应用代码,必须中止
70
+ if (!shadowRoot)
71
+ stopMainAppRun();
72
+ const rawCreateElement = getXpeRawDocumentCreateElement(iframeWindow);
73
+ const rawCreateTextNode = getXpeRawDocumentCreateTextNode(iframeWindow);
74
+ // need fix
75
+ if (propKey === "createElement" || propKey === "createTextNode") {
76
+ return new Proxy(document[propKey], {
77
+ apply(_createElement, _ctx, args) {
78
+ const rawCreateMethod = propKey === "createElement" ? rawCreateElement : rawCreateTextNode;
79
+ const element = rawCreateMethod.apply(iframeDocument, args);
80
+ patchElementEffect(element, iframeWindow);
81
+ return element;
82
+ },
83
+ });
84
+ }
85
+ if (propKey === "documentURI" || propKey === "URL") {
86
+ return proxyLocation.href;
87
+ }
88
+ // from shadowRoot
89
+ if (propKey === "getElementsByTagName" ||
90
+ propKey === "getElementsByClassName" ||
91
+ propKey === "getElementsByName") {
92
+ return new Proxy(shadowRoot.querySelectorAll, {
93
+ apply(querySelectorAll, _ctx, args) {
94
+ let arg = args[0];
95
+ if (_ctx !== iframeDocument) {
96
+ return getDocumentCollectionByProxyKey(_ctx, propKey, args);
97
+ }
98
+ if (propKey === "getElementsByTagName" && arg === "script") {
99
+ return iframeDocument.scripts;
100
+ }
101
+ if (propKey === "getElementsByClassName")
102
+ arg = "." + arg;
103
+ if (propKey === "getElementsByName")
104
+ arg = `[name="${arg}"]`;
105
+ // FIXME: This string must be a valid CSS selector string; if it's not, a SyntaxError exception is thrown;
106
+ // so we should ensure that the program can execute normally in case of exceptions.
107
+ // reference: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
108
+ let res;
109
+ try {
110
+ res = querySelectorAll.call(shadowRoot, arg);
111
+ }
112
+ catch (error) {
113
+ res = [];
114
+ }
115
+ return res;
116
+ },
117
+ });
118
+ }
119
+ if (propKey === "getElementById") {
120
+ return new Proxy(shadowRoot.querySelector, {
121
+ // case document.querySelector.call
122
+ apply(target, ctx, args) {
123
+ if (ctx !== iframeDocument) {
124
+ return Document.prototype.getElementById.call(ctx, args[0]);
125
+ }
126
+ try {
127
+ return (target.call(shadowRoot, `[id="${args[0]}"]`) ||
128
+ getXpeRawDocumentQuerySelector(iframeWindow).call(iframeWindow.document, `#${args[0]}`));
129
+ }
130
+ catch (error) {
131
+ warn(XPE_TIPS_GET_ELEMENT_BY_ID);
132
+ return null;
133
+ }
134
+ },
135
+ });
136
+ }
137
+ if (propKey === "querySelector" || propKey === "querySelectorAll") {
138
+ const rawPropMap = {
139
+ querySelector: getXpeRawDocumentQuerySelector,
140
+ querySelectorAll: getXpeRawDocumentQuerySelectorAll,
141
+ };
142
+ return new Proxy(shadowRoot[propKey], {
143
+ apply(target, ctx, args) {
144
+ if (ctx !== iframeDocument) {
145
+ return getRawDocumentQuery(propKey).call(ctx, args[0]);
146
+ }
147
+ // 二选一,优先shadowDom,除非采用array合并,排除base,防止对router造成影响
148
+ return (target.apply(shadowRoot, args) ||
149
+ (args[0] === "base"
150
+ ? null
151
+ : rawPropMap[propKey](iframeWindow).call(iframeWindow.document, args[0])));
152
+ },
153
+ });
154
+ }
155
+ if (propKey === "documentElement" || propKey === "scrollingElement")
156
+ return shadowRoot.firstElementChild;
157
+ if (propKey === "forms")
158
+ return shadowRoot.querySelectorAll("form");
159
+ if (propKey === "images")
160
+ return shadowRoot.querySelectorAll("img");
161
+ if (propKey === "links")
162
+ return shadowRoot.querySelectorAll("a");
163
+ const { ownerProperties, shadowProperties, shadowMethods, documentProperties, documentMethods } = documentProxyProperties;
164
+ if (ownerProperties.concat(shadowProperties).includes(propKey.toString())) {
165
+ if (propKey === "activeElement" && shadowRoot.activeElement === null)
166
+ return shadowRoot.body;
167
+ return shadowRoot[propKey];
168
+ }
169
+ if (shadowMethods.includes(propKey.toString())) {
170
+ return getTargetValue(shadowRoot, propKey) ?? getTargetValue(document, propKey);
171
+ }
172
+ // from window.document
173
+ if (documentProperties.includes(propKey.toString())) {
174
+ return document[propKey];
175
+ }
176
+ if (documentMethods.includes(propKey.toString())) {
177
+ return getTargetValue(document, propKey);
178
+ }
179
+ // 兜底:未分类属性(title / cookie / domain / designMode 等)回退到子应用自身 document,
180
+ // 与下方 set trap 保持同一归属,保证读写往返一致;缺失此兜底时一律返回 undefined。
181
+ return getTargetValue(iframeDocument, propKey);
182
+ },
183
+ set: function (_fakeDocument, propKey, value) {
184
+ // 写操作转发到子应用自身的 iframe document,避免落到空对象后静默丢失
185
+ // (document.title / document.cookie / document.domain / designMode 等可写属性)。
186
+ iframeDocument[propKey] = value;
187
+ return true;
188
+ },
189
+ has: function (_fakeDocument, propKey) {
190
+ // 让 'cookie' in document、'title' in document 等特性探测反映真实 document。
191
+ return propKey in window.document;
192
+ },
193
+ ownKeys: function () {
194
+ // 让 Object.keys(document) / Reflect.ownKeys(document) 反映真实 document 的自有键。
195
+ return Reflect.ownKeys(window.document);
196
+ },
197
+ getOwnPropertyDescriptor: function (_fakeDocument, propKey) {
198
+ const descriptor = Object.getOwnPropertyDescriptor(window.document, propKey) ||
199
+ Object.getOwnPropertyDescriptor(Document.prototype, propKey);
200
+ if (!descriptor)
201
+ return undefined;
202
+ // fake target 上无对应键,必须 configurable 才能满足 Proxy 不变量。
203
+ return { ...descriptor, configurable: true };
204
+ },
205
+ });
206
+ // proxy location
207
+ const { proxy: proxyLocation, revoke: revokeLocation } = Proxy.revocable({}, {
208
+ get: function (_fakeLocation, propKey) {
209
+ const location = iframe.contentWindow.location;
210
+ if (propKey === "host" ||
211
+ propKey === "hostname" ||
212
+ propKey === "protocol" ||
213
+ propKey === "port" ||
214
+ propKey === "origin") {
215
+ return urlElement[propKey];
216
+ }
217
+ if (propKey === "href") {
218
+ return location[propKey].replace(mainHostPath, appHostPath);
219
+ }
220
+ if (propKey === "reload") {
221
+ warn(XPE_TIPS_RELOAD_DISABLED);
222
+ return () => null;
223
+ }
224
+ if (propKey === "replace") {
225
+ return new Proxy(location[propKey], {
226
+ apply(replace, _ctx, args) {
227
+ return replace.call(location, args[0]?.replace(appHostPath, mainHostPath));
228
+ },
229
+ });
230
+ }
231
+ return getTargetValue(location, propKey);
232
+ },
233
+ set: function (_fakeLocation, propKey, value) {
234
+ // 如果是跳转链接的话重开一个iframe
235
+ if (propKey === "href") {
236
+ return locationHrefSet(iframe, value, appHostPath);
237
+ }
238
+ iframeWindow.location[propKey] = value;
239
+ return true;
240
+ },
241
+ ownKeys: function () {
242
+ return Object.keys(iframeWindow.location).filter((key) => key !== "reload");
243
+ },
244
+ getOwnPropertyDescriptor: function (_target, key) {
245
+ // 取真实 iframe location 上的值,而非 handler 自身属性(this 指向 handler 会导致全部失真)。
246
+ return { enumerable: true, configurable: true, value: iframeWindow.location[key] };
247
+ },
248
+ });
249
+ // revoke 后引擎清空代理的 [[ProxyTarget]] / [[ProxyHandler]],使捕获了 iframe / urlElement
250
+ // 的 handler 闭包不可达,从而释放对 iframe 的强引用
251
+ const proxyRevoke = () => {
252
+ revokeWindow();
253
+ revokeDocument();
254
+ revokeLocation();
255
+ };
256
+ return { proxyWindow, proxyDocument, proxyLocation, proxyRevoke };
257
+ }
258
+ /**
259
+ * 降级情况下document、location代理处理
260
+ */
261
+ export function localGenerator(iframe, urlElement, mainHostPath, appHostPath) {
262
+ const iframeWindow = getIframeWindow(iframe);
263
+ // 降级模式无法使用 Proxy.revocable,改用可清空的引用:getter 闭包统一通过 iframeRef /
264
+ // sandboxRef / locationRef 这三个 let 绑定访问 DOM,proxyRevoke 时置 null,闭包即丢失
265
+ // 对 iframe 的强引用,斩断「主应用 → 代理闭包 → iframe」的引用链。
266
+ let iframeRef = iframe;
267
+ let sandboxRef = getActiveSandbox(getXpeInternalSandbox(iframeWindow));
268
+ let locationRef = iframeWindow.location;
269
+ // 代理 document
270
+ const proxyDocument = {};
271
+ // 特殊处理
272
+ Object.defineProperties(proxyDocument, {
273
+ createElement: {
274
+ get: () => {
275
+ return function (...args) {
276
+ const activeIframe = getActiveIframe(iframeRef);
277
+ const activeWindow = getIframeWindow(activeIframe);
278
+ const activeDocument = getIframeDocument(activeIframe);
279
+ const element = getXpeRawDocumentCreateElement(activeWindow).apply(activeDocument, args);
280
+ patchElementEffect(element, activeWindow);
281
+ return element;
282
+ };
283
+ },
284
+ },
285
+ createTextNode: {
286
+ get: () => {
287
+ return function (...args) {
288
+ const activeIframe = getActiveIframe(iframeRef);
289
+ const activeWindow = getIframeWindow(activeIframe);
290
+ const activeDocument = getIframeDocument(activeIframe);
291
+ const element = getXpeRawDocumentCreateTextNode(activeWindow).apply(activeDocument, args);
292
+ patchElementEffect(element, activeWindow);
293
+ return element;
294
+ };
295
+ },
296
+ },
297
+ documentURI: {
298
+ get: () => sandboxRef?.proxyLocation?.href,
299
+ },
300
+ URL: {
301
+ get: () => sandboxRef?.proxyLocation?.href,
302
+ },
303
+ getElementsByTagName: {
304
+ get() {
305
+ return function (...args) {
306
+ const activeIframe = getActiveIframe(iframeRef);
307
+ const activeDocument = getIframeDocument(activeIframe);
308
+ const activeSandbox = getActiveSandbox(sandboxRef);
309
+ const tagName = args[0];
310
+ if (tagName === "script") {
311
+ return activeDocument.scripts;
312
+ }
313
+ return activeSandbox.document.getElementsByTagName(tagName);
314
+ };
315
+ },
316
+ },
317
+ getElementById: {
318
+ get() {
319
+ return function (...args) {
320
+ const activeIframe = getActiveIframe(iframeRef);
321
+ const activeWindow = getIframeWindow(activeIframe);
322
+ const activeSandbox = getActiveSandbox(sandboxRef);
323
+ const id = args[0];
324
+ return (activeSandbox.document.getElementById(id) ||
325
+ getXpeRawDocumentHead(activeWindow).querySelector(`#${id}`));
326
+ };
327
+ },
328
+ },
329
+ });
330
+ // 普通处理
331
+ const { modifyLocalProperties, modifyProperties, ownerProperties, shadowProperties, shadowMethods, documentProperties, documentMethods, } = documentProxyProperties;
332
+ modifyProperties
333
+ .filter((key) => !modifyLocalProperties.includes(key))
334
+ .concat(ownerProperties, shadowProperties, shadowMethods, documentProperties, documentMethods)
335
+ .forEach((key) => {
336
+ Object.defineProperty(proxyDocument, key, {
337
+ get: () => {
338
+ const activeSandbox = getActiveSandbox(sandboxRef);
339
+ const value = activeSandbox.document?.[key];
340
+ return isCallable(value) ? value.bind(activeSandbox.document) : value;
341
+ },
342
+ });
343
+ });
344
+ // 代理 location
345
+ const proxyLocation = {};
346
+ const locationKeys = Object.keys(locationRef);
347
+ const constantKey = ["host", "hostname", "port", "protocol", "port"];
348
+ constantKey.forEach((key) => {
349
+ proxyLocation[key] = urlElement[key];
350
+ });
351
+ Object.defineProperties(proxyLocation, {
352
+ href: {
353
+ get: () => getActiveLocation(locationRef).href.replace(mainHostPath, appHostPath),
354
+ set: (value) => {
355
+ locationHrefSet(getActiveIframe(iframeRef), value, appHostPath);
356
+ },
357
+ },
358
+ reload: {
359
+ get() {
360
+ warn(XPE_TIPS_RELOAD_DISABLED);
361
+ return () => null;
362
+ },
363
+ },
364
+ });
365
+ locationKeys
366
+ .filter((key) => !constantKey.concat(["href", "reload"]).includes(key))
367
+ .forEach((key) => {
368
+ Object.defineProperty(proxyLocation, key, {
369
+ get: () => {
370
+ const activeLocation = getActiveLocation(locationRef);
371
+ const value = activeLocation[key];
372
+ return isCallable(value) ? value.bind(activeLocation) : value;
373
+ },
374
+ });
375
+ });
376
+ // 置空捕获的 DOM 引用,斩断 getter 闭包对 iframe / location / sandbox 的强引用
377
+ const proxyRevoke = () => {
378
+ iframeRef = null;
379
+ sandboxRef = null;
380
+ locationRef = null;
381
+ };
382
+ return { proxyDocument, proxyLocation, proxyRevoke };
383
+ }
384
+ function getIframeWindow(iframe) {
385
+ if (!iframe.contentWindow) {
386
+ throw new Error("XPE runtime iframe window is unavailable");
387
+ }
388
+ return iframe.contentWindow;
389
+ }
390
+ function getIframeDocument(iframe) {
391
+ if (!iframe.contentDocument) {
392
+ throw new Error("XPE runtime iframe document is unavailable");
393
+ }
394
+ return iframe.contentDocument;
395
+ }
396
+ function getActiveSandbox(sandbox) {
397
+ if (!sandbox) {
398
+ throw new Error("XPE runtime sandbox is unavailable");
399
+ }
400
+ return sandbox;
401
+ }
402
+ function getActiveIframe(iframe) {
403
+ if (!iframe) {
404
+ throw new Error("XPE runtime iframe has been released");
405
+ }
406
+ return iframe;
407
+ }
408
+ function getActiveLocation(location) {
409
+ if (!location) {
410
+ throw new Error("XPE runtime location has been released");
411
+ }
412
+ return location;
413
+ }
414
+ function getElementParent(element) {
415
+ if (!(element.parentElement instanceof HTMLElement)) {
416
+ throw new Error("XPE runtime render container is unavailable");
417
+ }
418
+ return element.parentElement;
419
+ }
420
+ function getHtmlElement(element) {
421
+ if (!(element instanceof HTMLElement)) {
422
+ throw new Error("XPE runtime target element is unavailable");
423
+ }
424
+ return element;
425
+ }
426
+ function getRawDocumentQuery(propKey) {
427
+ return propKey === "querySelector" ? Document.prototype.querySelector : Document.prototype.querySelectorAll;
428
+ }
429
+ function getDocumentCollectionByProxyKey(ctx, propKey, args) {
430
+ if (propKey === "getElementsByTagName") {
431
+ return Document.prototype.getElementsByTagName.call(ctx, args[0]);
432
+ }
433
+ if (propKey === "getElementsByClassName") {
434
+ return Document.prototype.getElementsByClassName.call(ctx, args[0]);
435
+ }
436
+ if (propKey === "getElementsByName") {
437
+ return Document.prototype.getElementsByName.call(ctx, args[0]);
438
+ }
439
+ return [];
440
+ }