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.
- package/README.md +627 -71
- package/dist/child/app-client.d.ts +44 -0
- package/dist/child/app-client.js +151 -0
- package/dist/child/index.d.ts +3 -0
- package/dist/child/index.js +3 -0
- package/dist/child/lifecycle.d.ts +12 -0
- package/dist/child/lifecycle.js +47 -0
- package/dist/child/mock-host.d.ts +8 -0
- package/dist/child/mock-host.js +41 -0
- package/dist/core/bridge.d.ts +28 -0
- package/dist/core/bridge.js +19 -0
- package/dist/core/events.d.ts +13 -0
- package/dist/core/events.js +56 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.js +3 -0
- package/dist/core/types.d.ts +102 -0
- package/dist/core/types.js +20 -0
- package/dist/dev-shell/index.d.ts +26 -0
- package/dist/dev-shell/index.js +56 -0
- package/dist/host/app-path-router.d.ts +33 -0
- package/dist/host/app-path-router.js +183 -0
- package/dist/host/host-runtime.d.ts +29 -0
- package/dist/host/host-runtime.js +176 -0
- package/dist/host/index.d.ts +1 -0
- package/dist/host/index.js +1 -0
- package/dist/host/xpe-host.d.ts +41 -0
- package/dist/host/xpe-host.js +61 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/kernel/common.d.ts +62 -0
- package/dist/kernel/common.js +207 -0
- package/dist/kernel/constant.d.ts +26 -0
- package/dist/kernel/constant.js +42 -0
- package/dist/kernel/effect.d.ts +32 -0
- package/dist/kernel/effect.js +529 -0
- package/dist/kernel/entry.d.ts +43 -0
- package/dist/kernel/entry.js +224 -0
- package/dist/kernel/event.d.ts +22 -0
- package/dist/kernel/event.js +120 -0
- package/dist/kernel/iframe.d.ts +141 -0
- package/dist/kernel/iframe.js +1104 -0
- package/dist/kernel/index.d.ts +25 -0
- package/dist/kernel/index.js +86 -0
- package/dist/kernel/plugin.d.ts +36 -0
- package/dist/kernel/plugin.js +68 -0
- package/dist/kernel/proxy.d.ts +17 -0
- package/dist/kernel/proxy.js +440 -0
- package/dist/kernel/runtime-engine.d.ts +154 -0
- package/dist/kernel/runtime-engine.js +209 -0
- package/dist/kernel/sandbox.d.ts +235 -0
- package/dist/kernel/sandbox.js +879 -0
- package/dist/kernel/shadow.d.ts +64 -0
- package/dist/kernel/shadow.js +385 -0
- package/dist/kernel/sync.d.ts +21 -0
- package/dist/kernel/sync.js +185 -0
- package/dist/kernel/template.d.ts +67 -0
- package/dist/kernel/template.js +226 -0
- package/dist/kernel/tracker.d.ts +44 -0
- package/dist/kernel/tracker.js +92 -0
- package/dist/kernel/utils.d.ts +100 -0
- package/dist/kernel/utils.js +325 -0
- package/dist/kernel/xpe-bridge.d.ts +27 -0
- package/dist/kernel/xpe-bridge.js +205 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +3 -0
- package/package.json +79 -57
- package/LICENSE +0 -21
- package/framework/es/core/Application.d.ts +0 -126
- package/framework/es/core/Command/Command.d.ts +0 -7
- package/framework/es/core/Container/Container.d.ts +0 -80
- package/framework/es/core/Contracts/AxiosAdapter.d.ts +0 -12
- package/framework/es/core/Helper/Helper.d.ts +0 -43
- package/framework/es/core/Helper/Storage/WebStorage.d.ts +0 -71
- package/framework/es/core/Libs/Exception.d.ts +0 -24
- package/framework/es/core/Libs/Lib.d.ts +0 -72
- package/framework/es/core/Provider/CommandProvider.d.ts +0 -4
- package/framework/es/core/Provider/HelperProvider.d.ts +0 -4
- package/framework/es/core/Provider/HttpProvider.d.ts +0 -13
- package/framework/es/core/Provider/ServiceProvider.d.ts +0 -15
- package/framework/es/core/Service/HttpService.d.ts +0 -133
- package/framework/es/core/Service/Service.d.ts +0 -6
- package/framework/es/core/Spanner/RESTful.d.ts +0 -30
- package/framework/es/core/Transformer/Transformer.d.ts +0 -46
- package/framework/es/core/Type/adapters.d.ts +0 -25
- package/framework/es/core/Type/types.d.ts +0 -161
- package/framework/es/core/TypeFunc/index.d.ts +0 -6
- package/framework/es/core/Wrenches/EventBus.d.ts +0 -56
- package/framework/es/core/Wrenches/is.d.ts +0 -19
- package/framework/es/ege.js +0 -4
- package/framework/es/ege.js.map +0 -1
- package/framework/es/index.d.ts +0 -13
- package/framework/es/pdd.js +0 -4
- package/framework/es/pdd.js.map +0 -1
- package/framework/es/src/core/Application.d.ts +0 -127
- package/framework/es/src/core/Application.d.ts.map +0 -1
- package/framework/es/src/core/Command/Command.d.ts +0 -8
- package/framework/es/src/core/Command/Command.d.ts.map +0 -1
- package/framework/es/src/core/Container/Container.d.ts +0 -81
- package/framework/es/src/core/Container/Container.d.ts.map +0 -1
- package/framework/es/src/core/Contracts/AxiosAdapter.d.ts +0 -13
- package/framework/es/src/core/Contracts/AxiosAdapter.d.ts.map +0 -1
- package/framework/es/src/core/Helper/Helper.d.ts +0 -45
- package/framework/es/src/core/Helper/Helper.d.ts.map +0 -1
- package/framework/es/src/core/Helper/Storage/WebStorage.d.ts +0 -72
- package/framework/es/src/core/Helper/Storage/WebStorage.d.ts.map +0 -1
- package/framework/es/src/core/Libs/Exception.d.ts +0 -25
- package/framework/es/src/core/Libs/Exception.d.ts.map +0 -1
- package/framework/es/src/core/Libs/Lib.d.ts +0 -73
- package/framework/es/src/core/Libs/Lib.d.ts.map +0 -1
- package/framework/es/src/core/Provider/CommandProvider.d.ts +0 -5
- package/framework/es/src/core/Provider/CommandProvider.d.ts.map +0 -1
- package/framework/es/src/core/Provider/HelperProvider.d.ts +0 -5
- package/framework/es/src/core/Provider/HelperProvider.d.ts.map +0 -1
- package/framework/es/src/core/Provider/HttpProvider.d.ts +0 -14
- package/framework/es/src/core/Provider/HttpProvider.d.ts.map +0 -1
- package/framework/es/src/core/Provider/ServiceProvider.d.ts +0 -16
- package/framework/es/src/core/Provider/ServiceProvider.d.ts.map +0 -1
- package/framework/es/src/core/Service/HttpService.d.ts +0 -128
- package/framework/es/src/core/Service/HttpService.d.ts.map +0 -1
- package/framework/es/src/core/Service/Service.d.ts +0 -7
- package/framework/es/src/core/Service/Service.d.ts.map +0 -1
- package/framework/es/src/core/Spanner/RESTful.d.ts +0 -32
- package/framework/es/src/core/Spanner/RESTful.d.ts.map +0 -1
- package/framework/es/src/core/Transformer/Transformer.d.ts +0 -47
- package/framework/es/src/core/Transformer/Transformer.d.ts.map +0 -1
- package/framework/es/src/core/Type/adapters.d.ts +0 -26
- package/framework/es/src/core/Type/adapters.d.ts.map +0 -1
- package/framework/es/src/core/Type/types.d.ts +0 -186
- package/framework/es/src/core/Type/types.d.ts.map +0 -1
- package/framework/es/src/core/TypeFunc/index.d.ts +0 -8
- package/framework/es/src/core/TypeFunc/index.d.ts.map +0 -1
- package/framework/es/src/core/Wrenches/EventBus.d.ts +0 -57
- package/framework/es/src/core/Wrenches/EventBus.d.ts.map +0 -1
- package/framework/es/src/core/Wrenches/is.d.ts +0 -20
- package/framework/es/src/core/Wrenches/is.d.ts.map +0 -1
- package/framework/es/src/index.d.ts +0 -14
- package/framework/es/src/index.d.ts.map +0 -1
- package/framework/es/src/utils.d.ts +0 -17
- package/framework/es/src/utils.d.ts.map +0 -1
- package/framework/es/utils.d.ts +0 -16
- package/framework/umd/core/Application.d.ts +0 -126
- package/framework/umd/core/Command/Command.d.ts +0 -7
- package/framework/umd/core/Container/Container.d.ts +0 -80
- package/framework/umd/core/Contracts/AxiosAdapter.d.ts +0 -12
- package/framework/umd/core/Helper/Helper.d.ts +0 -43
- package/framework/umd/core/Helper/Storage/WebStorage.d.ts +0 -71
- package/framework/umd/core/Libs/Exception.d.ts +0 -24
- package/framework/umd/core/Libs/Lib.d.ts +0 -72
- package/framework/umd/core/Provider/CommandProvider.d.ts +0 -4
- package/framework/umd/core/Provider/HelperProvider.d.ts +0 -4
- package/framework/umd/core/Provider/HttpProvider.d.ts +0 -13
- package/framework/umd/core/Provider/ServiceProvider.d.ts +0 -15
- package/framework/umd/core/Service/HttpService.d.ts +0 -133
- package/framework/umd/core/Service/Service.d.ts +0 -6
- package/framework/umd/core/Spanner/RESTful.d.ts +0 -30
- package/framework/umd/core/Transformer/Transformer.d.ts +0 -46
- package/framework/umd/core/Type/adapters.d.ts +0 -25
- package/framework/umd/core/Type/types.d.ts +0 -161
- package/framework/umd/core/TypeFunc/index.d.ts +0 -6
- package/framework/umd/core/Wrenches/EventBus.d.ts +0 -56
- package/framework/umd/core/Wrenches/is.d.ts +0 -19
- package/framework/umd/ege.js +0 -4
- package/framework/umd/ege.js.map +0 -1
- package/framework/umd/index.d.ts +0 -13
- package/framework/umd/pdd.js +0 -4
- package/framework/umd/pdd.js.map +0 -1
- package/framework/umd/src/core/Application.d.ts +0 -127
- package/framework/umd/src/core/Application.d.ts.map +0 -1
- package/framework/umd/src/core/Command/Command.d.ts +0 -8
- package/framework/umd/src/core/Command/Command.d.ts.map +0 -1
- package/framework/umd/src/core/Container/Container.d.ts +0 -81
- package/framework/umd/src/core/Container/Container.d.ts.map +0 -1
- package/framework/umd/src/core/Contracts/AxiosAdapter.d.ts +0 -13
- package/framework/umd/src/core/Contracts/AxiosAdapter.d.ts.map +0 -1
- package/framework/umd/src/core/Helper/Helper.d.ts +0 -45
- package/framework/umd/src/core/Helper/Helper.d.ts.map +0 -1
- package/framework/umd/src/core/Helper/Storage/WebStorage.d.ts +0 -72
- package/framework/umd/src/core/Helper/Storage/WebStorage.d.ts.map +0 -1
- package/framework/umd/src/core/Libs/Exception.d.ts +0 -25
- package/framework/umd/src/core/Libs/Exception.d.ts.map +0 -1
- package/framework/umd/src/core/Libs/Lib.d.ts +0 -73
- package/framework/umd/src/core/Libs/Lib.d.ts.map +0 -1
- package/framework/umd/src/core/Provider/CommandProvider.d.ts +0 -5
- package/framework/umd/src/core/Provider/CommandProvider.d.ts.map +0 -1
- package/framework/umd/src/core/Provider/HelperProvider.d.ts +0 -5
- package/framework/umd/src/core/Provider/HelperProvider.d.ts.map +0 -1
- package/framework/umd/src/core/Provider/HttpProvider.d.ts +0 -14
- package/framework/umd/src/core/Provider/HttpProvider.d.ts.map +0 -1
- package/framework/umd/src/core/Provider/ServiceProvider.d.ts +0 -16
- package/framework/umd/src/core/Provider/ServiceProvider.d.ts.map +0 -1
- package/framework/umd/src/core/Service/HttpService.d.ts +0 -128
- package/framework/umd/src/core/Service/HttpService.d.ts.map +0 -1
- package/framework/umd/src/core/Service/Service.d.ts +0 -7
- package/framework/umd/src/core/Service/Service.d.ts.map +0 -1
- package/framework/umd/src/core/Spanner/RESTful.d.ts +0 -32
- package/framework/umd/src/core/Spanner/RESTful.d.ts.map +0 -1
- package/framework/umd/src/core/Transformer/Transformer.d.ts +0 -47
- package/framework/umd/src/core/Transformer/Transformer.d.ts.map +0 -1
- package/framework/umd/src/core/Type/adapters.d.ts +0 -26
- package/framework/umd/src/core/Type/adapters.d.ts.map +0 -1
- package/framework/umd/src/core/Type/types.d.ts +0 -186
- package/framework/umd/src/core/Type/types.d.ts.map +0 -1
- package/framework/umd/src/core/TypeFunc/index.d.ts +0 -8
- package/framework/umd/src/core/TypeFunc/index.d.ts.map +0 -1
- package/framework/umd/src/core/Wrenches/EventBus.d.ts +0 -57
- package/framework/umd/src/core/Wrenches/EventBus.d.ts.map +0 -1
- package/framework/umd/src/core/Wrenches/is.d.ts +0 -20
- package/framework/umd/src/core/Wrenches/is.d.ts.map +0 -1
- package/framework/umd/src/index.d.ts +0 -14
- package/framework/umd/src/index.d.ts.map +0 -1
- package/framework/umd/src/utils.d.ts +0 -17
- package/framework/umd/src/utils.d.ts.map +0 -1
- package/framework/umd/utils.d.ts +0 -16
- 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
|
+
}
|