@blueking/bk-weweb 0.0.35-beta.1 → 0.0.35-beta.2
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/dist/index.d.mts +326 -42
- package/dist/index.esm.js +599 -252
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -119,10 +119,11 @@ var WewebMode = /* @__PURE__ */ ((WewebMode2) => {
|
|
|
119
119
|
// src/typings/sandbox.ts
|
|
120
120
|
var WINDOW_WHITE_LIST = [
|
|
121
121
|
"System",
|
|
122
|
-
// SystemJS
|
|
122
|
+
// SystemJS 模块加载器
|
|
123
123
|
"__cjsWrapper",
|
|
124
|
-
// SystemJS CommonJS
|
|
125
|
-
|
|
124
|
+
// SystemJS CommonJS 包装器
|
|
125
|
+
// 开发环境下允许 React DevTools
|
|
126
|
+
...false ? ["__REACT_DEVTOOLS_GLOBAL_HOOK__"] : []
|
|
126
127
|
];
|
|
127
128
|
var BK_WEWEB_INJECT_KEY_LIST = [
|
|
128
129
|
"__POWERED_BY_BK_WEWEB__",
|
|
@@ -137,18 +138,25 @@ var COMMON_MICRO_APP_WINDOW_KEY_MAP = {
|
|
|
137
138
|
i18n: true
|
|
138
139
|
};
|
|
139
140
|
var DEV_MICRO_APP_WINDOW_KEY_MAP = false ? {
|
|
141
|
+
// 开发环境标识
|
|
140
142
|
__DEV__: true,
|
|
143
|
+
// Vue DevTools 相关
|
|
141
144
|
__VUE_DEVTOOLS_GLOBAL_HOOK__: true,
|
|
142
145
|
__VUE_DEVTOOLS_HOOK_REPLAY__: true,
|
|
143
146
|
__VUE_DEVTOOLS_PLUGINS__: true,
|
|
147
|
+
// Vue I18n 相关
|
|
144
148
|
__VUE_I18N_FULL_INSTALL__: true,
|
|
145
149
|
__VUE_I18N_LEGACY_API__: true,
|
|
150
|
+
// Vue 配置相关
|
|
146
151
|
__VUE_OPTIONS_API__: true,
|
|
152
|
+
// Core-js 相关
|
|
147
153
|
"__core-js_shared__": true,
|
|
154
|
+
// Webpack 相关
|
|
148
155
|
webpackChunkapm: true,
|
|
149
156
|
webpackChunkpc: true,
|
|
150
157
|
webpackChunktrace: true,
|
|
151
158
|
webpackJsonp: true,
|
|
159
|
+
// 包含通用配置
|
|
152
160
|
...COMMON_MICRO_APP_WINDOW_KEY_MAP
|
|
153
161
|
} : COMMON_MICRO_APP_WINDOW_KEY_MAP;
|
|
154
162
|
|
|
@@ -198,10 +206,10 @@ var isJsonpUrl = (url) => {
|
|
|
198
206
|
};
|
|
199
207
|
|
|
200
208
|
// src/context/document.ts
|
|
201
|
-
var
|
|
202
|
-
var
|
|
203
|
-
|
|
204
|
-
function shadowRootInsertAdjacentHTML(where, domString) {
|
|
209
|
+
var SPECIAL_ELEMENT_TAGS = ["body", "html", "head"];
|
|
210
|
+
var APP_KEY_PROPERTY = "__BK_WEWEB_APP_KEY__";
|
|
211
|
+
function createShadowRootInsertAdjacentHTML(app) {
|
|
212
|
+
return function shadowRootInsertAdjacentHTML(where, domString) {
|
|
205
213
|
const temporaryContainer = document.createElement("div");
|
|
206
214
|
temporaryContainer.innerHTML = domString;
|
|
207
215
|
const elements = Array.from(temporaryContainer.childNodes);
|
|
@@ -228,16 +236,18 @@ var createProxyDocument = (rawDocument, app) => {
|
|
|
228
236
|
}
|
|
229
237
|
break;
|
|
230
238
|
}
|
|
231
|
-
}
|
|
232
|
-
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function createProxyBody(rawDocument, app) {
|
|
242
|
+
return new Proxy(
|
|
233
243
|
{},
|
|
234
244
|
{
|
|
235
245
|
get(_, key) {
|
|
236
246
|
if (app.container instanceof ShadowRoot) {
|
|
237
247
|
if (key === "insertAdjacentHTML") {
|
|
238
|
-
return
|
|
248
|
+
return createShadowRootInsertAdjacentHTML(app);
|
|
239
249
|
}
|
|
240
|
-
const value2 = app.container
|
|
250
|
+
const value2 = Reflect.get(app.container, key);
|
|
241
251
|
if (typeof value2 === "function") {
|
|
242
252
|
return value2.bind(app.container);
|
|
243
253
|
}
|
|
@@ -250,7 +260,7 @@ var createProxyDocument = (rawDocument, app) => {
|
|
|
250
260
|
},
|
|
251
261
|
set(_, key, value) {
|
|
252
262
|
if (app.container instanceof ShadowRoot) {
|
|
253
|
-
app.container
|
|
263
|
+
Reflect.set(app.container, key, value);
|
|
254
264
|
return true;
|
|
255
265
|
}
|
|
256
266
|
Reflect.set(rawDocument.body, key, value);
|
|
@@ -258,60 +268,102 @@ var createProxyDocument = (rawDocument, app) => {
|
|
|
258
268
|
}
|
|
259
269
|
}
|
|
260
270
|
);
|
|
261
|
-
|
|
271
|
+
}
|
|
272
|
+
function createElementWithAppKey(rawDocument, app) {
|
|
273
|
+
return function createElement(tagName, options) {
|
|
262
274
|
const element = rawDocument.createElement(tagName, options);
|
|
263
|
-
element
|
|
275
|
+
element[APP_KEY_PROPERTY] = app.appCacheKey;
|
|
264
276
|
return element;
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function isSpecialElementTag(selector) {
|
|
280
|
+
return SPECIAL_ELEMENT_TAGS.includes(selector);
|
|
281
|
+
}
|
|
282
|
+
function safeQuerySelector(container, selector) {
|
|
283
|
+
try {
|
|
284
|
+
return container?.querySelector(selector) ?? null;
|
|
285
|
+
} catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function safeQuerySelectorAll(container, selector) {
|
|
290
|
+
try {
|
|
291
|
+
return container?.querySelectorAll(selector) ?? [];
|
|
292
|
+
} catch {
|
|
293
|
+
return [];
|
|
265
294
|
}
|
|
266
|
-
|
|
295
|
+
}
|
|
296
|
+
function createProxyQuerySelector(rawDocument, app, proxyBody) {
|
|
297
|
+
return function querySelectorNew(selectors) {
|
|
267
298
|
if (selectors === proxyBody) {
|
|
268
299
|
return app.container instanceof ShadowRoot ? app.container : rawDocument.body;
|
|
269
300
|
}
|
|
270
|
-
if (
|
|
301
|
+
if (isSpecialElementTag(selectors)) {
|
|
271
302
|
if (app?.container instanceof ShadowRoot) {
|
|
272
303
|
return app?.container;
|
|
273
304
|
}
|
|
274
305
|
return rawDocument.querySelector.call(this, selectors);
|
|
275
306
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
function querySelectorAllNew(selectors) {
|
|
283
|
-
if (SPECIAL_ELEMENT_TAG.includes(selectors)) {
|
|
307
|
+
return safeQuerySelector(app?.container, selectors);
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function createProxyQuerySelectorAll(rawDocument, app) {
|
|
311
|
+
return function querySelectorAllNew(selectors) {
|
|
312
|
+
if (isSpecialElementTag(selectors)) {
|
|
284
313
|
if (app?.container instanceof ShadowRoot) {
|
|
285
|
-
return app?.container;
|
|
314
|
+
return [app?.container];
|
|
286
315
|
}
|
|
287
|
-
|
|
316
|
+
const result = rawDocument.querySelector(selectors);
|
|
317
|
+
return result ? [result] : [];
|
|
288
318
|
}
|
|
289
|
-
return app?.container
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
319
|
+
return safeQuerySelectorAll(app?.container, selectors);
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function createProxyGetElementById(rawDocument, querySelector) {
|
|
323
|
+
return function getElementByIdNew(id) {
|
|
324
|
+
return querySelector.call(rawDocument, `#${id}`);
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function createProxyGetElementsByClassName(querySelectorAll) {
|
|
328
|
+
return function getElementsByClassName(className) {
|
|
329
|
+
return querySelectorAll(`.${className}`);
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function createProxyGetElementsByTagName(rawDocument, app, querySelectorAll) {
|
|
333
|
+
return function getElementsByTagName(tagName) {
|
|
334
|
+
if (isSpecialElementTag(tagName) || !app?.showSourceCode && tagName.toLowerCase() === "script") {
|
|
335
|
+
return rawDocument.getElementsByTagName(tagName);
|
|
300
336
|
}
|
|
301
|
-
return
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
337
|
+
return querySelectorAll(tagName);
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function createProxyGetElementsByName(querySelectorAll) {
|
|
341
|
+
return function getElementsByNameNew(name) {
|
|
342
|
+
return querySelectorAll(`[name="${name}"]`);
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
function createProxyMethodMap(rawDocument, app, proxyBody) {
|
|
346
|
+
const createElement = createElementWithAppKey(rawDocument, app);
|
|
347
|
+
const querySelector = createProxyQuerySelector(rawDocument, app, proxyBody);
|
|
348
|
+
const querySelectorAll = createProxyQuerySelectorAll(rawDocument, app);
|
|
349
|
+
const getElementById = createProxyGetElementById(rawDocument, querySelector);
|
|
350
|
+
const getElementsByClassName = createProxyGetElementsByClassName(querySelectorAll);
|
|
351
|
+
const getElementsByTagName = createProxyGetElementsByTagName(rawDocument, app, querySelectorAll);
|
|
352
|
+
const getElementsByName = createProxyGetElementsByName(querySelectorAll);
|
|
353
|
+
return {
|
|
307
354
|
createElement: createElement.bind(rawDocument),
|
|
308
|
-
querySelector:
|
|
309
|
-
querySelectorAll:
|
|
310
|
-
getElementById:
|
|
355
|
+
querySelector: querySelector.bind(rawDocument),
|
|
356
|
+
querySelectorAll: querySelectorAll.bind(rawDocument),
|
|
357
|
+
getElementById: getElementById.bind(rawDocument),
|
|
311
358
|
getElementsByClassName: getElementsByClassName.bind(rawDocument),
|
|
312
359
|
getElementsByTagName: getElementsByTagName.bind(rawDocument),
|
|
313
|
-
getElementsByName:
|
|
360
|
+
getElementsByName: getElementsByName.bind(rawDocument)
|
|
314
361
|
};
|
|
362
|
+
}
|
|
363
|
+
var createProxyDocument = (rawDocument, app) => {
|
|
364
|
+
const fakeDocument = {};
|
|
365
|
+
const proxyBody = createProxyBody(rawDocument, app);
|
|
366
|
+
const methodMap = createProxyMethodMap(rawDocument, app, proxyBody);
|
|
315
367
|
return new Proxy(fakeDocument, {
|
|
316
368
|
get(_, key) {
|
|
317
369
|
if (key === "body") {
|
|
@@ -473,6 +525,11 @@ function rewriteWindowFunction(fakeWindow) {
|
|
|
473
525
|
|
|
474
526
|
// src/context/sandbox.ts
|
|
475
527
|
var SandBox = class {
|
|
528
|
+
/**
|
|
529
|
+
* 构造函数
|
|
530
|
+
* @description 初始化沙箱环境,创建代理对象和隔离机制
|
|
531
|
+
* @param app - 关联的微应用实例
|
|
532
|
+
*/
|
|
476
533
|
constructor(app) {
|
|
477
534
|
this.app = app;
|
|
478
535
|
const windowDescriptorSet = /* @__PURE__ */ new Set();
|
|
@@ -488,63 +545,30 @@ var SandBox = class {
|
|
|
488
545
|
this.fakeWindow = fakeWindow;
|
|
489
546
|
const { resetWindowFunction } = rewriteWindowFunction(this.fakeWindow);
|
|
490
547
|
this.resetWindowFunction = resetWindowFunction;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
)}__`;
|
|
548
|
+
const appIdentifier = (app.name || app.appCacheKey).replace(/[-,:~'"]/g, "_");
|
|
549
|
+
this.windowSymbolKey = `__${appIdentifier}_${random(10)}__`;
|
|
494
550
|
this.proxyWindow = new Proxy(this.fakeWindow, {
|
|
495
|
-
// 定义属性
|
|
496
551
|
defineProperty: (target, key, value) => {
|
|
497
552
|
if (windowDescriptorSet.has(key)) {
|
|
498
553
|
return Reflect.defineProperty(rawWindow, key, value);
|
|
499
554
|
}
|
|
500
555
|
return Reflect.defineProperty(target, key, value);
|
|
501
556
|
},
|
|
502
|
-
// 删除属性
|
|
503
557
|
deleteProperty: (target, key) => {
|
|
504
558
|
if (Object.hasOwn(target, key)) {
|
|
505
|
-
this.sameRawWindowKeySet.has(key)
|
|
506
|
-
|
|
559
|
+
if (this.sameRawWindowKeySet.has(key)) {
|
|
560
|
+
this.sameRawWindowKeySet.delete(key);
|
|
561
|
+
}
|
|
562
|
+
if (this.inRawWindowKeySet.has(key)) {
|
|
563
|
+
Reflect.deleteProperty(rawWindow, key);
|
|
564
|
+
}
|
|
507
565
|
return Reflect.deleteProperty(target, key);
|
|
508
566
|
}
|
|
509
567
|
return true;
|
|
510
568
|
},
|
|
511
|
-
// 获取属性
|
|
512
569
|
get: (target, key) => {
|
|
513
|
-
|
|
514
|
-
if (DEV_MICRO_APP_WINDOW_KEY_MAP[key]) return this.fakeWindow[key];
|
|
515
|
-
if (WINDOW_ALIAS_LIST.includes(key)) return this.proxyWindow;
|
|
516
|
-
if (key === "document") {
|
|
517
|
-
app.registerRunningApp();
|
|
518
|
-
return this.rawDocument;
|
|
519
|
-
}
|
|
520
|
-
if (key === "eval") {
|
|
521
|
-
app.registerRunningApp();
|
|
522
|
-
return eval;
|
|
523
|
-
}
|
|
524
|
-
if (BK_WEWEB_LOCATION_KEY_LIST.includes(key) && this.app instanceof MicroAppModel && this.app.iframe && this.app.scopeLocation) {
|
|
525
|
-
return this.app.iframe.contentWindow?.[key];
|
|
526
|
-
}
|
|
527
|
-
if (key === "hasOwnProperty")
|
|
528
|
-
return (key2) => Object.hasOwn(this.fakeWindow, key2) || Object.hasOwn(rawWindow, key2);
|
|
529
|
-
if (key === "top" || key === "parent") {
|
|
530
|
-
if (rawWindow === rawWindow.parent) {
|
|
531
|
-
return this.proxyWindow;
|
|
532
|
-
}
|
|
533
|
-
return Reflect.get(rawWindow, key);
|
|
534
|
-
}
|
|
535
|
-
if (key === "getComputedStyle") {
|
|
536
|
-
return (element, pseudoElt) => {
|
|
537
|
-
if (element instanceof Element) {
|
|
538
|
-
return rawWindow.getComputedStyle(element, pseudoElt);
|
|
539
|
-
}
|
|
540
|
-
return rawWindow.getComputedStyle(document.body, pseudoElt);
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
if (Reflect.has(target, key) || BK_WEWEB_INJECT_KEY_LIST.includes(key)) return Reflect.get(target, key);
|
|
544
|
-
const rawValue = Reflect.get(rawWindow, key);
|
|
545
|
-
return bindFunctionToRawWindow(rawWindow, rawValue);
|
|
570
|
+
return this.handleProxyGet(target, key, rawWindow);
|
|
546
571
|
},
|
|
547
|
-
// 获取属性描述符
|
|
548
572
|
getOwnPropertyDescriptor: (target, key) => {
|
|
549
573
|
if (Object.hasOwn(target, key)) {
|
|
550
574
|
return Object.getOwnPropertyDescriptor(target, key);
|
|
@@ -559,69 +583,197 @@ var SandBox = class {
|
|
|
559
583
|
}
|
|
560
584
|
return void 0;
|
|
561
585
|
},
|
|
562
|
-
// 检查属性是否存在
|
|
563
586
|
has: (target, key) => windowNativeFuncMap.has(key) || key in target || key in rawWindow,
|
|
564
|
-
// 获取所有属性名
|
|
565
587
|
ownKeys: (target) => Array.from(new Set(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)))),
|
|
566
|
-
// 设置属性
|
|
567
588
|
set: (target, key, value) => {
|
|
568
|
-
|
|
569
|
-
if (BK_WEWEB_LOCATION_KEY_LIST.includes(key) && this.app instanceof MicroAppModel && this.app.iframe && this.app.scopeLocation) {
|
|
570
|
-
return Reflect.set(this.app.iframe.contentWindow, key, value);
|
|
571
|
-
}
|
|
572
|
-
if (key === "location") {
|
|
573
|
-
Reflect.set(rawWindow, key, value);
|
|
574
|
-
} else if (!Object.hasOwn(target, key) && Object.hasOwn(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
|
|
575
|
-
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
576
|
-
const { configurable, enumerable, writable } = descriptor;
|
|
577
|
-
if (writable) {
|
|
578
|
-
Object.defineProperty(target, key, {
|
|
579
|
-
configurable,
|
|
580
|
-
enumerable,
|
|
581
|
-
value,
|
|
582
|
-
writable
|
|
583
|
-
});
|
|
584
|
-
this.sameRawWindowKeySet.add(key);
|
|
585
|
-
}
|
|
586
|
-
} else {
|
|
587
|
-
Reflect.set(target, key, value);
|
|
588
|
-
this.sameRawWindowKeySet.add(key);
|
|
589
|
-
}
|
|
590
|
-
if (WINDOW_WHITE_LIST.includes(key) && !Reflect.has(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
|
|
591
|
-
Reflect.set(rawWindow, key, value);
|
|
592
|
-
this.inRawWindowKeySet.add(key);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
return true;
|
|
589
|
+
return this.handleProxySet(target, key, value, rawWindow);
|
|
596
590
|
}
|
|
597
591
|
});
|
|
598
592
|
rawWindow[this.windowSymbolKey] = this.proxyWindow;
|
|
599
593
|
}
|
|
600
|
-
|
|
594
|
+
/** 沙箱激活状态标识 */
|
|
601
595
|
active = false;
|
|
602
|
-
|
|
596
|
+
/** 记录在原始 window 上新增的属性键集合 */
|
|
603
597
|
inRawWindowKeySet = /* @__PURE__ */ new Set();
|
|
604
|
-
|
|
598
|
+
/** 重置文档和 body 事件的函数 */
|
|
605
599
|
resetDocumentAndBodyEvent;
|
|
606
|
-
|
|
600
|
+
/** 重置 window 函数的方法 */
|
|
607
601
|
resetWindowFunction;
|
|
608
|
-
|
|
602
|
+
/** 记录与原始 window 相同的属性键集合 */
|
|
609
603
|
sameRawWindowKeySet = /* @__PURE__ */ new Set();
|
|
610
|
-
|
|
604
|
+
/** 伪造的 window 对象 */
|
|
611
605
|
fakeWindow;
|
|
612
|
-
|
|
606
|
+
/** 代理的 document 对象 */
|
|
613
607
|
proxyDocument;
|
|
614
|
-
|
|
608
|
+
/** 代理的 window 对象 */
|
|
615
609
|
proxyWindow;
|
|
616
|
-
|
|
610
|
+
/** 原始 document 对象 */
|
|
617
611
|
rawDocument;
|
|
618
|
-
|
|
612
|
+
/** 原始 window 对象 */
|
|
619
613
|
rawWindow;
|
|
620
|
-
|
|
614
|
+
/** 在 window 上的唯一标识键 */
|
|
621
615
|
windowSymbolKey;
|
|
616
|
+
/**
|
|
617
|
+
* 处理代理对象的 get 操作
|
|
618
|
+
* @description 统一处理代理对象属性获取的复杂逻辑
|
|
619
|
+
* @param target - 目标对象
|
|
620
|
+
* @param key - 属性键
|
|
621
|
+
* @param rawWindow - 原始 window 对象
|
|
622
|
+
* @returns unknown - 属性值
|
|
623
|
+
* @private
|
|
624
|
+
*/
|
|
625
|
+
handleProxyGet(target, key, rawWindow) {
|
|
626
|
+
if (key === Symbol.unscopables || windowNativeFuncMap.has(key)) {
|
|
627
|
+
return rawWindow[key];
|
|
628
|
+
}
|
|
629
|
+
if (DEV_MICRO_APP_WINDOW_KEY_MAP[key]) {
|
|
630
|
+
return this.fakeWindow[key];
|
|
631
|
+
}
|
|
632
|
+
if (WINDOW_ALIAS_LIST.includes(key)) {
|
|
633
|
+
return this.proxyWindow;
|
|
634
|
+
}
|
|
635
|
+
if (key === "document") {
|
|
636
|
+
this.app.registerRunningApp();
|
|
637
|
+
return this.rawDocument;
|
|
638
|
+
}
|
|
639
|
+
if (key === "eval") {
|
|
640
|
+
this.app.registerRunningApp();
|
|
641
|
+
return eval;
|
|
642
|
+
}
|
|
643
|
+
if (this.shouldUseIframeLocation(key)) {
|
|
644
|
+
if (this.app instanceof MicroAppModel && this.app.iframe?.contentWindow) {
|
|
645
|
+
return this.app.iframe.contentWindow[key];
|
|
646
|
+
}
|
|
647
|
+
return void 0;
|
|
648
|
+
}
|
|
649
|
+
if (key === "hasOwnProperty") {
|
|
650
|
+
return (checkKey) => Object.hasOwn(this.fakeWindow, checkKey) || Object.hasOwn(rawWindow, checkKey);
|
|
651
|
+
}
|
|
652
|
+
if (key === "top" || key === "parent") {
|
|
653
|
+
if (rawWindow === rawWindow.parent) {
|
|
654
|
+
return this.proxyWindow;
|
|
655
|
+
}
|
|
656
|
+
return Reflect.get(rawWindow, key);
|
|
657
|
+
}
|
|
658
|
+
if (key === "getComputedStyle") {
|
|
659
|
+
return this.createGetComputedStyleProxy(rawWindow);
|
|
660
|
+
}
|
|
661
|
+
if (Reflect.has(target, key) || BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
|
|
662
|
+
return Reflect.get(target, key);
|
|
663
|
+
}
|
|
664
|
+
const rawValue = Reflect.get(rawWindow, key);
|
|
665
|
+
return bindFunctionToRawWindow(rawWindow, rawValue);
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* 处理代理对象的 set 操作
|
|
669
|
+
* @description 统一处理代理对象属性设置的复杂逻辑
|
|
670
|
+
* @param target - 目标对象
|
|
671
|
+
* @param key - 属性键
|
|
672
|
+
* @param value - 属性值
|
|
673
|
+
* @param rawWindow - 原始 window 对象
|
|
674
|
+
* @returns boolean - 设置是否成功
|
|
675
|
+
* @private
|
|
676
|
+
*/
|
|
677
|
+
handleProxySet(target, key, value, rawWindow) {
|
|
678
|
+
if (!this.active) {
|
|
679
|
+
return true;
|
|
680
|
+
}
|
|
681
|
+
if (this.shouldUseIframeLocation(key)) {
|
|
682
|
+
const iframe = this.app instanceof MicroAppModel ? this.app.iframe : null;
|
|
683
|
+
return iframe?.contentWindow ? Reflect.set(iframe.contentWindow, key, value) : true;
|
|
684
|
+
}
|
|
685
|
+
if (key === "location") {
|
|
686
|
+
Reflect.set(rawWindow, key, value);
|
|
687
|
+
} else if (this.shouldSetOnTarget(target, key, rawWindow)) {
|
|
688
|
+
this.setPropertyOnTarget(target, key, value, rawWindow);
|
|
689
|
+
} else {
|
|
690
|
+
Reflect.set(target, key, value);
|
|
691
|
+
this.sameRawWindowKeySet.add(key);
|
|
692
|
+
}
|
|
693
|
+
this.handleWhiteListProperty(key, value, rawWindow);
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* 判断是否应该使用 iframe 的 location
|
|
698
|
+
* @description 检查是否在 iframe 模式下访问 location 相关属性
|
|
699
|
+
* @param key - 属性键
|
|
700
|
+
* @returns boolean - 是否使用 iframe location
|
|
701
|
+
* @private
|
|
702
|
+
*/
|
|
703
|
+
shouldUseIframeLocation(key) {
|
|
704
|
+
return !!(BK_WEWEB_LOCATION_KEY_LIST.includes(key) && this.app instanceof MicroAppModel && this.app.iframe && this.app.scopeLocation);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* 创建 getComputedStyle 方法的代理
|
|
708
|
+
* @description 为 getComputedStyle 方法创建安全的代理实现
|
|
709
|
+
* @param rawWindow - 原始 window 对象
|
|
710
|
+
* @returns Function - 代理后的 getComputedStyle 方法
|
|
711
|
+
* @private
|
|
712
|
+
*/
|
|
713
|
+
createGetComputedStyleProxy(rawWindow) {
|
|
714
|
+
return (element, pseudoElt) => {
|
|
715
|
+
if (element instanceof Element) {
|
|
716
|
+
return rawWindow.getComputedStyle(element, pseudoElt);
|
|
717
|
+
}
|
|
718
|
+
return rawWindow.getComputedStyle(document.body, pseudoElt);
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* 判断是否应该在目标对象上设置属性
|
|
723
|
+
* @description 检查属性设置的逻辑条件
|
|
724
|
+
* @param target - 目标对象
|
|
725
|
+
* @param key - 属性键
|
|
726
|
+
* @param rawWindow - 原始 window 对象
|
|
727
|
+
* @returns boolean - 是否在目标对象上设置
|
|
728
|
+
* @private
|
|
729
|
+
*/
|
|
730
|
+
shouldSetOnTarget(target, key, rawWindow) {
|
|
731
|
+
return !Object.hasOwn(target, key) && Object.hasOwn(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key);
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* 在目标对象上设置属性
|
|
735
|
+
* @description 安全地在目标对象上设置属性,保持描述符特性
|
|
736
|
+
* @param target - 目标对象
|
|
737
|
+
* @param key - 属性键
|
|
738
|
+
* @param value - 属性值
|
|
739
|
+
* @param rawWindow - 原始 window 对象
|
|
740
|
+
* @private
|
|
741
|
+
*/
|
|
742
|
+
setPropertyOnTarget(target, key, value, rawWindow) {
|
|
743
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
744
|
+
if (!descriptor) {
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
const { configurable, enumerable, writable } = descriptor;
|
|
748
|
+
if (writable) {
|
|
749
|
+
Object.defineProperty(target, key, {
|
|
750
|
+
configurable,
|
|
751
|
+
enumerable,
|
|
752
|
+
value,
|
|
753
|
+
writable
|
|
754
|
+
});
|
|
755
|
+
this.sameRawWindowKeySet.add(key);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* 处理白名单属性
|
|
760
|
+
* @description 处理需要在原始 window 上设置的白名单属性
|
|
761
|
+
* @param key - 属性键
|
|
762
|
+
* @param value - 属性值
|
|
763
|
+
* @param rawWindow - 原始 window 对象
|
|
764
|
+
* @private
|
|
765
|
+
*/
|
|
766
|
+
handleWhiteListProperty(key, value, rawWindow) {
|
|
767
|
+
if (WINDOW_WHITE_LIST.includes(key) && !Reflect.has(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
|
|
768
|
+
Reflect.set(rawWindow, key, value);
|
|
769
|
+
this.inRawWindowKeySet.add(key);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
622
772
|
/**
|
|
623
773
|
* 激活沙箱
|
|
624
|
-
* @
|
|
774
|
+
* @description 启动沙箱环境,初始化代理对象和事件处理
|
|
775
|
+
* @param data - 传递给沙箱的数据(可选)
|
|
776
|
+
* @returns void
|
|
625
777
|
*/
|
|
626
778
|
activated(data) {
|
|
627
779
|
if (!this.active) {
|
|
@@ -633,7 +785,9 @@ var SandBox = class {
|
|
|
633
785
|
}
|
|
634
786
|
}
|
|
635
787
|
/**
|
|
636
|
-
*
|
|
788
|
+
* 停用沙箱
|
|
789
|
+
* @description 关闭沙箱环境,清理所有副作用和修改
|
|
790
|
+
* @returns void
|
|
637
791
|
*/
|
|
638
792
|
deactivated() {
|
|
639
793
|
if (!this.active) return;
|
|
@@ -2320,37 +2474,79 @@ var EntrySource = class {
|
|
|
2320
2474
|
|
|
2321
2475
|
// src/cache/app-cache.ts
|
|
2322
2476
|
var AppCache = class {
|
|
2323
|
-
|
|
2477
|
+
/** 基础资源源,用于主应用共享资源包 */
|
|
2324
2478
|
baseSource;
|
|
2479
|
+
/** 应用实例缓存映射表 */
|
|
2325
2480
|
cache;
|
|
2481
|
+
/**
|
|
2482
|
+
* 构造函数
|
|
2483
|
+
* @description 初始化应用缓存管理器
|
|
2484
|
+
*/
|
|
2326
2485
|
constructor() {
|
|
2327
2486
|
this.cache = /* @__PURE__ */ new Map();
|
|
2328
2487
|
this.baseSource = new EntrySource(location.href);
|
|
2329
2488
|
}
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2489
|
+
/**
|
|
2490
|
+
* 设置应用实例到缓存
|
|
2491
|
+
* @description 将应用实例添加到缓存中,使用应用的缓存键作为标识
|
|
2492
|
+
* @param app - 要缓存的应用实例
|
|
2493
|
+
* @returns void
|
|
2494
|
+
*/
|
|
2495
|
+
setApp(app) {
|
|
2496
|
+
this.cache.set(app.appCacheKey, app);
|
|
2333
2497
|
}
|
|
2334
|
-
|
|
2498
|
+
/**
|
|
2499
|
+
* 获取缓存的应用实例
|
|
2500
|
+
* @description 根据名称或ID获取已缓存的应用实例
|
|
2501
|
+
* @param name - 应用名称或ID,为空时返回 undefined
|
|
2502
|
+
* @returns BaseModel | undefined - 应用实例或 undefined
|
|
2503
|
+
*/
|
|
2335
2504
|
getApp(name) {
|
|
2336
2505
|
if (!name) return void 0;
|
|
2337
2506
|
const app = this.cache.get(name);
|
|
2338
2507
|
if (app) return app;
|
|
2339
2508
|
return Array.from(this.cache.values()).find((item) => item.name === name);
|
|
2340
2509
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2510
|
+
/**
|
|
2511
|
+
* 删除缓存的应用实例
|
|
2512
|
+
* @description 从缓存中移除指定URL的应用实例
|
|
2513
|
+
* @param url - 要删除的应用URL标识
|
|
2514
|
+
* @returns void
|
|
2515
|
+
*/
|
|
2516
|
+
deleteApp(url) {
|
|
2517
|
+
this.cache.delete(url);
|
|
2344
2518
|
}
|
|
2519
|
+
/**
|
|
2520
|
+
* 获取缓存的HTML内容
|
|
2521
|
+
* @description 根据URL获取已缓存的HTML内容
|
|
2522
|
+
* @param url - 应用的URL
|
|
2523
|
+
* @returns string - HTML内容,未找到时返回空字符串
|
|
2524
|
+
*/
|
|
2345
2525
|
getCacheHtml(url) {
|
|
2346
2526
|
const list = Array.from(this.cache.values());
|
|
2347
2527
|
const app = list.find((item) => item.url === url);
|
|
2348
2528
|
if (app) return app.source?.rawHtml || "";
|
|
2349
2529
|
return "";
|
|
2350
2530
|
}
|
|
2531
|
+
/**
|
|
2532
|
+
* 设置基础应用脚本
|
|
2533
|
+
* @description 将脚本添加到基础资源源中,供多个应用共享
|
|
2534
|
+
* @param url - 脚本的URL
|
|
2535
|
+
* @param script - 脚本实例
|
|
2536
|
+
* @returns void
|
|
2537
|
+
*/
|
|
2538
|
+
setBaseAppScript(url, script) {
|
|
2539
|
+
this.baseSource.setScript(url, script);
|
|
2540
|
+
}
|
|
2541
|
+
/**
|
|
2542
|
+
* 获取缓存的脚本资源
|
|
2543
|
+
* @description 从基础资源源或应用缓存中获取脚本资源
|
|
2544
|
+
* @param url - 脚本的URL
|
|
2545
|
+
* @returns Script | undefined - 脚本实例或 undefined
|
|
2546
|
+
*/
|
|
2351
2547
|
getCacheScript(url) {
|
|
2352
2548
|
let script = this.baseSource.getScript(url);
|
|
2353
|
-
if (script) return;
|
|
2549
|
+
if (script) return script;
|
|
2354
2550
|
const list = Array.from(this.cache.values());
|
|
2355
2551
|
list.some((app) => {
|
|
2356
2552
|
script = app.source?.getScript(url);
|
|
@@ -2358,9 +2554,34 @@ var AppCache = class {
|
|
|
2358
2554
|
});
|
|
2359
2555
|
return script;
|
|
2360
2556
|
}
|
|
2557
|
+
/**
|
|
2558
|
+
* 设置基础应用样式
|
|
2559
|
+
* @description 将样式添加到基础资源源中,供多个应用共享
|
|
2560
|
+
* @param url - 样式的URL
|
|
2561
|
+
* @param style - 样式实例
|
|
2562
|
+
* @returns void
|
|
2563
|
+
*/
|
|
2564
|
+
setBaseAppStyle(url, style) {
|
|
2565
|
+
this.baseSource.setStyle(url, style);
|
|
2566
|
+
}
|
|
2567
|
+
/**
|
|
2568
|
+
* 获取基础应用样式
|
|
2569
|
+
* @description 从基础资源源中获取样式资源
|
|
2570
|
+
* @param urlOrCode - 样式的URL或代码
|
|
2571
|
+
* @returns Style | undefined - 样式实例或 undefined
|
|
2572
|
+
*/
|
|
2573
|
+
getBaseAppStyle(urlOrCode) {
|
|
2574
|
+
return this.baseSource.getStyle(urlOrCode);
|
|
2575
|
+
}
|
|
2576
|
+
/**
|
|
2577
|
+
* 获取缓存的样式资源
|
|
2578
|
+
* @description 从基础资源源或应用缓存中获取样式资源
|
|
2579
|
+
* @param url - 样式的URL
|
|
2580
|
+
* @returns Style | undefined - 样式实例或 undefined
|
|
2581
|
+
*/
|
|
2361
2582
|
getCacheStyle(url) {
|
|
2362
2583
|
let style = this.baseSource.getStyle(url);
|
|
2363
|
-
if (style) return;
|
|
2584
|
+
if (style) return style;
|
|
2364
2585
|
const list = Array.from(this.cache.values());
|
|
2365
2586
|
list.some((app) => {
|
|
2366
2587
|
style = app.source?.getStyle(url);
|
|
@@ -2368,15 +2589,11 @@ var AppCache = class {
|
|
|
2368
2589
|
});
|
|
2369
2590
|
return style;
|
|
2370
2591
|
}
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
}
|
|
2377
|
-
setBaseAppStyle(url, style) {
|
|
2378
|
-
this.baseSource.setStyle(url, style);
|
|
2379
|
-
}
|
|
2592
|
+
/**
|
|
2593
|
+
* 检查是否存在活跃的应用
|
|
2594
|
+
* @description 判断当前是否有处于非卸载状态的应用实例
|
|
2595
|
+
* @returns boolean - 存在活跃应用时返回 true
|
|
2596
|
+
*/
|
|
2380
2597
|
get hasActiveApp() {
|
|
2381
2598
|
return Array.from(this.cache.values()).some((app) => app.status !== AppState.UNMOUNT);
|
|
2382
2599
|
}
|
|
@@ -2396,8 +2613,8 @@ function getStyleSource(url, style, originLink) {
|
|
|
2396
2613
|
appCache.setBaseAppStyle(url, style);
|
|
2397
2614
|
replaceStyle.textContent = data;
|
|
2398
2615
|
dispatchLinkOrScriptLoad(originLink);
|
|
2399
|
-
}).catch((
|
|
2400
|
-
console.error(
|
|
2616
|
+
}).catch((error) => {
|
|
2617
|
+
console.error("Failed to load style resource:", error);
|
|
2401
2618
|
dispatchLinkOrScriptError(originLink);
|
|
2402
2619
|
});
|
|
2403
2620
|
return replaceStyle;
|
|
@@ -2412,59 +2629,67 @@ function getScriptSource(url, script, originScript) {
|
|
|
2412
2629
|
if (!url.startsWith("inline-")) {
|
|
2413
2630
|
originScript.setAttribute("origin-src", url);
|
|
2414
2631
|
}
|
|
2415
|
-
} catch (
|
|
2416
|
-
console.error(
|
|
2632
|
+
} catch (error) {
|
|
2633
|
+
console.error("Failed to set script content:", error, url);
|
|
2417
2634
|
}
|
|
2418
2635
|
dispatchLinkOrScriptLoad(originScript);
|
|
2419
|
-
}).catch((
|
|
2420
|
-
console.error(
|
|
2636
|
+
}).catch((error) => {
|
|
2637
|
+
console.error("Failed to load script resource:", error);
|
|
2421
2638
|
dispatchLinkOrScriptError(originScript);
|
|
2422
2639
|
});
|
|
2423
2640
|
return replaceScript;
|
|
2424
2641
|
}
|
|
2642
|
+
function processLinkElement(linkElement) {
|
|
2643
|
+
const rel = linkElement.getAttribute("rel");
|
|
2644
|
+
let href = linkElement.getAttribute("href");
|
|
2645
|
+
if (rel === "stylesheet" && href) {
|
|
2646
|
+
href = fillUpPath(href, location.origin);
|
|
2647
|
+
const replaceStyle = document.createElement("style");
|
|
2648
|
+
const styleInstance = new Style({
|
|
2649
|
+
code: "",
|
|
2650
|
+
fromHtml: false,
|
|
2651
|
+
url: href
|
|
2652
|
+
});
|
|
2653
|
+
getStyleSource(href, styleInstance, linkElement);
|
|
2654
|
+
return replaceStyle;
|
|
2655
|
+
}
|
|
2656
|
+
return linkElement;
|
|
2657
|
+
}
|
|
2658
|
+
function processScriptElement(scriptElement) {
|
|
2659
|
+
let src = scriptElement.getAttribute("src");
|
|
2660
|
+
if (src && scriptElement.type !== "module") {
|
|
2661
|
+
src = fillUpPath(src, location.origin);
|
|
2662
|
+
const script = new Script({
|
|
2663
|
+
async: scriptElement.hasAttribute("async"),
|
|
2664
|
+
code: "",
|
|
2665
|
+
defer: scriptElement.defer || scriptElement.type === "module",
|
|
2666
|
+
fromHtml: false,
|
|
2667
|
+
isModule: false
|
|
2668
|
+
});
|
|
2669
|
+
appCache.setBaseAppScript(src, script);
|
|
2670
|
+
const replaceElement = getScriptSource(src, script, scriptElement);
|
|
2671
|
+
return replaceElement || scriptElement;
|
|
2672
|
+
}
|
|
2673
|
+
return scriptElement;
|
|
2674
|
+
}
|
|
2425
2675
|
function createNewNode(child) {
|
|
2426
2676
|
if (child instanceof HTMLLinkElement) {
|
|
2427
|
-
|
|
2428
|
-
let href = child.getAttribute("href");
|
|
2429
|
-
if (rel === "stylesheet" && href) {
|
|
2430
|
-
href = fillUpPath(href, location.origin);
|
|
2431
|
-
const replaceStyle = document.createElement("style");
|
|
2432
|
-
const styleInstance = new Style({
|
|
2433
|
-
code: "",
|
|
2434
|
-
fromHtml: false,
|
|
2435
|
-
url: href
|
|
2436
|
-
});
|
|
2437
|
-
getStyleSource(href, styleInstance, child);
|
|
2438
|
-
return replaceStyle;
|
|
2439
|
-
}
|
|
2677
|
+
return processLinkElement(child);
|
|
2440
2678
|
}
|
|
2441
2679
|
if (child instanceof HTMLScriptElement) {
|
|
2442
|
-
|
|
2443
|
-
if (src && child.type !== "module") {
|
|
2444
|
-
src = fillUpPath(src, location.origin);
|
|
2445
|
-
const script = new Script({
|
|
2446
|
-
async: child.hasAttribute("async"),
|
|
2447
|
-
code: "",
|
|
2448
|
-
defer: child.defer || child.type === "module",
|
|
2449
|
-
fromHtml: false,
|
|
2450
|
-
isModule: false
|
|
2451
|
-
});
|
|
2452
|
-
appCache.setBaseAppScript(src, script);
|
|
2453
|
-
const replaceElement = getScriptSource(src, script, child);
|
|
2454
|
-
return replaceElement || child;
|
|
2455
|
-
}
|
|
2680
|
+
return processScriptElement(child);
|
|
2456
2681
|
}
|
|
2457
2682
|
return child;
|
|
2458
2683
|
}
|
|
2459
2684
|
function isLinkOrScript(node) {
|
|
2460
2685
|
return node instanceof HTMLLinkElement || node instanceof HTMLScriptElement;
|
|
2461
2686
|
}
|
|
2462
|
-
function baseElementInertHandle(parent, newChild,
|
|
2687
|
+
function baseElementInertHandle(parent, newChild, referenceChild, rawMethod) {
|
|
2463
2688
|
if (isLinkOrScript(newChild)) {
|
|
2464
2689
|
const targetChild = createNewNode(newChild);
|
|
2465
|
-
return rawMethod.call(parent, targetChild,
|
|
2690
|
+
return rawMethod.call(parent, targetChild, referenceChild);
|
|
2466
2691
|
}
|
|
2467
|
-
return rawMethod.call(parent, newChild,
|
|
2692
|
+
return rawMethod.call(parent, newChild, referenceChild);
|
|
2468
2693
|
}
|
|
2469
2694
|
function baseElementAppendHandle(parent, newChild, rawMethod) {
|
|
2470
2695
|
if (isLinkOrScript(newChild)) {
|
|
@@ -2475,10 +2700,15 @@ function baseElementAppendHandle(parent, newChild, rawMethod) {
|
|
|
2475
2700
|
}
|
|
2476
2701
|
|
|
2477
2702
|
// src/base-app/collect-source.ts
|
|
2478
|
-
function
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2703
|
+
function cacheOriginalDOMMethods() {
|
|
2704
|
+
return {
|
|
2705
|
+
rawBodyAppendChild: HTMLBodyElement.prototype.appendChild,
|
|
2706
|
+
rawHeadAppendChild: HTMLHeadElement.prototype.appendChild,
|
|
2707
|
+
rawHeadInsertBefore: HTMLHeadElement.prototype.insertBefore
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
function overrideDOMMethods(originalMethods) {
|
|
2711
|
+
const { rawBodyAppendChild, rawHeadAppendChild, rawHeadInsertBefore } = originalMethods;
|
|
2482
2712
|
HTMLBodyElement.prototype.appendChild = function(newChild) {
|
|
2483
2713
|
return baseElementAppendHandle(this, newChild, rawBodyAppendChild);
|
|
2484
2714
|
};
|
|
@@ -2488,22 +2718,39 @@ function collectBaseSource() {
|
|
|
2488
2718
|
HTMLHeadElement.prototype.insertBefore = function(newChild, refChild) {
|
|
2489
2719
|
return baseElementInertHandle(this, newChild, refChild, rawHeadInsertBefore);
|
|
2490
2720
|
};
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2721
|
+
}
|
|
2722
|
+
function collectExistingStyles() {
|
|
2723
|
+
const styleNodes = document.head.querySelectorAll("style");
|
|
2724
|
+
for (const styleNode of Array.from(styleNodes)) {
|
|
2725
|
+
const textContent = styleNode.textContent;
|
|
2726
|
+
if (textContent) {
|
|
2727
|
+
try {
|
|
2728
|
+
const style = new Style({
|
|
2729
|
+
code: textContent,
|
|
2498
2730
|
fromHtml: false,
|
|
2499
2731
|
url: ""
|
|
2500
|
-
})
|
|
2501
|
-
|
|
2732
|
+
});
|
|
2733
|
+
appCache.setBaseAppStyle(randomUrl(), style);
|
|
2734
|
+
} catch (error) {
|
|
2735
|
+
console.warn("Failed to collect style element:", error);
|
|
2736
|
+
}
|
|
2502
2737
|
}
|
|
2503
|
-
}
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
function setupLoadEventListener() {
|
|
2741
|
+
window.addEventListener("load", collectExistingStyles);
|
|
2742
|
+
}
|
|
2743
|
+
function collectBaseSource() {
|
|
2744
|
+
const originalMethods = cacheOriginalDOMMethods();
|
|
2745
|
+
overrideDOMMethods(originalMethods);
|
|
2746
|
+
setupLoadEventListener();
|
|
2504
2747
|
}
|
|
2505
2748
|
|
|
2506
2749
|
// src/context/element.ts
|
|
2750
|
+
var RESOURCE_ATTRIBUTES = ["src", "srcset"];
|
|
2751
|
+
var LINK_ATTRIBUTES = ["href"];
|
|
2752
|
+
var RESOURCE_TAG_NAMES = ["IMG", "SCRIPT"];
|
|
2753
|
+
var LINK_TAG_NAMES = ["LINK"];
|
|
2507
2754
|
var { setAttribute } = Element.prototype;
|
|
2508
2755
|
var {
|
|
2509
2756
|
append,
|
|
@@ -2518,47 +2765,84 @@ var {
|
|
|
2518
2765
|
} = HTMLHeadElement.prototype;
|
|
2519
2766
|
var rawHead = document.head;
|
|
2520
2767
|
var hasRewrite = false;
|
|
2521
|
-
function
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2768
|
+
function shouldProcessResourcePath(key, tagName) {
|
|
2769
|
+
const upperTagName = tagName.toUpperCase();
|
|
2770
|
+
return RESOURCE_ATTRIBUTES.includes(key) && RESOURCE_TAG_NAMES.includes(upperTagName) || LINK_ATTRIBUTES.includes(key) && LINK_TAG_NAMES.includes(upperTagName);
|
|
2771
|
+
}
|
|
2772
|
+
function getElementApp(element) {
|
|
2773
|
+
if (!element.__BK_WEWEB_APP_KEY__) {
|
|
2774
|
+
return null;
|
|
2775
|
+
}
|
|
2776
|
+
return appCache.getApp(element.__BK_WEWEB_APP_KEY__);
|
|
2777
|
+
}
|
|
2778
|
+
function createOverriddenSetAttribute() {
|
|
2779
|
+
return function(key, value) {
|
|
2780
|
+
const tagName = this.tagName.toUpperCase();
|
|
2781
|
+
if (shouldProcessResourcePath(key, tagName) && this.__BK_WEWEB_APP_KEY__) {
|
|
2782
|
+
const app = getElementApp(this);
|
|
2783
|
+
if (app) {
|
|
2784
|
+
setAttribute.call(this, key, fillUpPath(value, app.url));
|
|
2785
|
+
return;
|
|
2786
|
+
}
|
|
2530
2787
|
}
|
|
2788
|
+
setAttribute.call(this, key, value);
|
|
2531
2789
|
};
|
|
2532
|
-
|
|
2533
|
-
|
|
2790
|
+
}
|
|
2791
|
+
function handleKeepAliveElement(newChild) {
|
|
2792
|
+
if (newChild.__KEEP_ALIVE__ && isSpecialElement(newChild)) {
|
|
2793
|
+
return headAppendChild.call(rawHead, newChild);
|
|
2794
|
+
}
|
|
2795
|
+
return null;
|
|
2796
|
+
}
|
|
2797
|
+
function createOverriddenAppendChild() {
|
|
2798
|
+
return function(newChild) {
|
|
2799
|
+
const keepAliveResult = handleKeepAliveElement(newChild);
|
|
2800
|
+
if (keepAliveResult) {
|
|
2801
|
+
return keepAliveResult;
|
|
2802
|
+
}
|
|
2534
2803
|
return elementAppendHandler(this, newChild, bodyAppendChild2);
|
|
2535
2804
|
};
|
|
2536
|
-
|
|
2805
|
+
}
|
|
2806
|
+
function createOverriddenAppend() {
|
|
2807
|
+
return function(...nodes) {
|
|
2537
2808
|
nodes.forEach((node) => {
|
|
2538
|
-
|
|
2539
|
-
|
|
2809
|
+
const keepAliveResult = handleKeepAliveElement(node);
|
|
2810
|
+
if (keepAliveResult) {
|
|
2811
|
+
return;
|
|
2540
2812
|
}
|
|
2541
2813
|
elementAppendHandler(this, node, bodyAppendChild2);
|
|
2542
2814
|
});
|
|
2543
2815
|
};
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
};
|
|
2548
|
-
HTMLBodyElement.prototype.insertBefore = function(newChild, refChild) {
|
|
2816
|
+
}
|
|
2817
|
+
function createOverriddenInsertBefore() {
|
|
2818
|
+
return function(newChild, refChild) {
|
|
2549
2819
|
return elementInsertHandler(this, newChild, refChild, headInsertBefore);
|
|
2550
2820
|
};
|
|
2551
|
-
|
|
2552
|
-
|
|
2821
|
+
}
|
|
2822
|
+
function createOverriddenRemoveChild() {
|
|
2823
|
+
return function(oldChild) {
|
|
2824
|
+
const app = oldChild.__BK_WEWEB_APP_KEY__ ? appCache.getApp(oldChild.__BK_WEWEB_APP_KEY__) : null;
|
|
2553
2825
|
if (app?.container?.contains(oldChild)) {
|
|
2554
|
-
|
|
2555
|
-
return node;
|
|
2826
|
+
return bodyRemoveChild.call(app.container, oldChild);
|
|
2556
2827
|
}
|
|
2557
2828
|
if (this.contains(oldChild)) {
|
|
2558
2829
|
return bodyRemoveChild.call(this, oldChild);
|
|
2559
2830
|
}
|
|
2560
2831
|
return oldChild;
|
|
2561
2832
|
};
|
|
2833
|
+
}
|
|
2834
|
+
function rewriteBodyAndHeaderMethods() {
|
|
2835
|
+
if (hasRewrite) {
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
hasRewrite = true;
|
|
2839
|
+
Element.prototype.setAttribute = createOverriddenSetAttribute();
|
|
2840
|
+
HTMLBodyElement.prototype.appendChild = createOverriddenAppendChild();
|
|
2841
|
+
HTMLBodyElement.prototype.append = createOverriddenAppend();
|
|
2842
|
+
HTMLBodyElement.prototype.insertBefore = createOverriddenInsertBefore();
|
|
2843
|
+
HTMLBodyElement.prototype.removeChild = createOverriddenRemoveChild();
|
|
2844
|
+
HTMLHeadElement.prototype.appendChild = HTMLBodyElement.prototype.appendChild;
|
|
2845
|
+
HTMLHeadElement.prototype.insertBefore = createOverriddenInsertBefore();
|
|
2562
2846
|
HTMLHeadElement.prototype.removeChild = HTMLBodyElement.prototype.removeChild;
|
|
2563
2847
|
}
|
|
2564
2848
|
function resetBodyAndHeaderMethods() {
|
|
@@ -2587,8 +2871,8 @@ function activated(appKey, container, callback) {
|
|
|
2587
2871
|
beforeLoad();
|
|
2588
2872
|
app.activated(container, callback);
|
|
2589
2873
|
});
|
|
2590
|
-
} else {
|
|
2591
|
-
|
|
2874
|
+
} else if (app) {
|
|
2875
|
+
nextTask(() => {
|
|
2592
2876
|
beforeLoad();
|
|
2593
2877
|
app.mount(container, callback);
|
|
2594
2878
|
});
|
|
@@ -2596,9 +2880,10 @@ function activated(appKey, container, callback) {
|
|
|
2596
2880
|
}
|
|
2597
2881
|
|
|
2598
2882
|
// src/lifecycle/deactivated.ts
|
|
2883
|
+
var DEACTIVATABLE_STATES = [AppState.ACTIVATED, AppState.MOUNTED];
|
|
2599
2884
|
function deactivated(appKey) {
|
|
2600
2885
|
const app = appCache.getApp(appKey);
|
|
2601
|
-
if (app &&
|
|
2886
|
+
if (app && DEACTIVATABLE_STATES.some((status) => status === app.status)) {
|
|
2602
2887
|
app.keepAlive ? app.deactivated() : app.unmount();
|
|
2603
2888
|
}
|
|
2604
2889
|
if (!appCache.hasActiveApp) {
|
|
@@ -2607,9 +2892,12 @@ function deactivated(appKey) {
|
|
|
2607
2892
|
}
|
|
2608
2893
|
|
|
2609
2894
|
// src/lifecycle/load.ts
|
|
2895
|
+
var STATUS_CHECK_INTERVAL = 300;
|
|
2610
2896
|
async function load(props) {
|
|
2611
2897
|
beforeLoad();
|
|
2612
|
-
if (props.mode === "js" /* INSTANCE */)
|
|
2898
|
+
if (props.mode === "js" /* INSTANCE */) {
|
|
2899
|
+
return await loadInstance(props);
|
|
2900
|
+
}
|
|
2613
2901
|
return await loadApp(props);
|
|
2614
2902
|
}
|
|
2615
2903
|
async function loadApp(props) {
|
|
@@ -2638,7 +2926,7 @@ function loadInstance(props) {
|
|
|
2638
2926
|
resolve(instance);
|
|
2639
2927
|
clearInterval(timer);
|
|
2640
2928
|
}
|
|
2641
|
-
},
|
|
2929
|
+
}, STATUS_CHECK_INTERVAL);
|
|
2642
2930
|
return;
|
|
2643
2931
|
}
|
|
2644
2932
|
resolve(instance);
|
|
@@ -2658,14 +2946,35 @@ function unmount(appKey) {
|
|
|
2658
2946
|
|
|
2659
2947
|
// src/component/web-component.ts
|
|
2660
2948
|
var BkWewebElement = class extends HTMLElement {
|
|
2949
|
+
/** 应用 URL 缓存 */
|
|
2661
2950
|
appUrl = "";
|
|
2951
|
+
/** 组件连接状态标识 */
|
|
2662
2952
|
connected = false;
|
|
2953
|
+
/**
|
|
2954
|
+
* 观察的属性列表
|
|
2955
|
+
* @description 定义需要监听变化的属性名称列表
|
|
2956
|
+
* @returns string[] - 属性名称数组
|
|
2957
|
+
*/
|
|
2663
2958
|
static get observedAttributes() {
|
|
2664
2959
|
return ["url" /* url */];
|
|
2665
2960
|
}
|
|
2961
|
+
/**
|
|
2962
|
+
* 获取布尔类型属性值
|
|
2963
|
+
* @description 解析布尔类型的自定义属性,支持驼峰和短横线命名
|
|
2964
|
+
* @param name - 属性名称
|
|
2965
|
+
* @returns boolean | undefined - 属性值或 undefined
|
|
2966
|
+
* @private
|
|
2967
|
+
*/
|
|
2666
2968
|
getBooleanAttr(name) {
|
|
2667
|
-
|
|
2969
|
+
const hasAttr = this.hasAttribute(name) || this.hasAttribute(name.replace(/([A-Z])/g, "-$1").toLocaleLowerCase());
|
|
2970
|
+
return hasAttr ? this.getAttribute(name) !== "false" : void 0;
|
|
2668
2971
|
}
|
|
2972
|
+
/**
|
|
2973
|
+
* 处理属性变化的内部逻辑
|
|
2974
|
+
* @description 当属性发生变化时执行的处理逻辑
|
|
2975
|
+
* @returns Promise<void>
|
|
2976
|
+
* @private
|
|
2977
|
+
*/
|
|
2669
2978
|
async handleAttributeChanged() {
|
|
2670
2979
|
if (!this.appKey) return;
|
|
2671
2980
|
if (this.getBooleanAttr("setShodowDom" /* setShodowDom */)) {
|
|
@@ -2678,12 +2987,27 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2678
2987
|
}
|
|
2679
2988
|
await load(this.appProps);
|
|
2680
2989
|
}
|
|
2990
|
+
/**
|
|
2991
|
+
* 属性变化回调
|
|
2992
|
+
* @description 当观察的属性发生变化时触发
|
|
2993
|
+
* @param attr - 变化的属性名
|
|
2994
|
+
* @param _oldVal - 旧值(未使用)
|
|
2995
|
+
* @param newVal - 新值
|
|
2996
|
+
* @returns void
|
|
2997
|
+
*/
|
|
2681
2998
|
attributeChangedCallback(attr, _oldVal, newVal) {
|
|
2682
2999
|
if (attr !== "url" /* url */ || this[attr] === newVal || !this.connected) return;
|
|
2683
3000
|
this.appUrl = newVal;
|
|
2684
3001
|
const cacheApp = appCache.getApp(this.appKey);
|
|
2685
|
-
(this.connected || cacheApp)
|
|
3002
|
+
if (this.connected || cacheApp) {
|
|
3003
|
+
this.handleAttributeChanged();
|
|
3004
|
+
}
|
|
2686
3005
|
}
|
|
3006
|
+
/**
|
|
3007
|
+
* 组件连接到 DOM 时的回调
|
|
3008
|
+
* @description 当自定义元素被插入到 DOM 时触发
|
|
3009
|
+
* @returns Promise<void>
|
|
3010
|
+
*/
|
|
2687
3011
|
async connectedCallback() {
|
|
2688
3012
|
if (this.getBooleanAttr("setShodowDom" /* setShodowDom */) && !this.shadowRoot) {
|
|
2689
3013
|
this.attachShadow({ delegatesFocus: false, mode: "open" });
|
|
@@ -2692,12 +3016,24 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2692
3016
|
activated(this.appKey, this.shadowRoot ?? this);
|
|
2693
3017
|
this.connected = true;
|
|
2694
3018
|
}
|
|
3019
|
+
/**
|
|
3020
|
+
* 组件从 DOM 断开时的回调
|
|
3021
|
+
* @description 当自定义元素从 DOM 中移除时触发
|
|
3022
|
+
* @returns void
|
|
3023
|
+
*/
|
|
2695
3024
|
disconnectedCallback() {
|
|
2696
3025
|
this.connected = false;
|
|
2697
3026
|
if (this.appProps.keepAlive) {
|
|
2698
3027
|
deactivated(this.appKey);
|
|
2699
|
-
} else
|
|
3028
|
+
} else {
|
|
3029
|
+
unmount(this.appKey);
|
|
3030
|
+
}
|
|
2700
3031
|
}
|
|
3032
|
+
/**
|
|
3033
|
+
* 获取应用数据
|
|
3034
|
+
* @description 解析 data 属性中的 JSON 数据
|
|
3035
|
+
* @returns Record<string, unknown> - 应用数据对象
|
|
3036
|
+
*/
|
|
2701
3037
|
get appData() {
|
|
2702
3038
|
if (this.hasAttribute("data" /* data */)) {
|
|
2703
3039
|
try {
|
|
@@ -2707,35 +3043,44 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2707
3043
|
}
|
|
2708
3044
|
return {};
|
|
2709
3045
|
}
|
|
2710
|
-
|
|
3046
|
+
/**
|
|
3047
|
+
* 获取应用标识符
|
|
3048
|
+
* @description 优先使用 id 属性,其次使用 url 属性作为应用标识
|
|
3049
|
+
* 考虑到 JS 模式下需要 JS bundle 的复用性,需用户设置 id 属性
|
|
3050
|
+
* 如果是单实例应用则可以不用配置 id
|
|
3051
|
+
* @returns string | null - 应用标识符或 null
|
|
3052
|
+
*/
|
|
2711
3053
|
get appKey() {
|
|
2712
3054
|
return this.getAttribute("id" /* id */) || this.getAttribute("url" /* url */);
|
|
2713
3055
|
}
|
|
3056
|
+
/**
|
|
3057
|
+
* 获取应用配置属性
|
|
3058
|
+
* @description 根据模式返回相应的应用配置对象
|
|
3059
|
+
* @returns IAppModelProps | IJsModelProps - 应用配置对象
|
|
3060
|
+
*/
|
|
2714
3061
|
get appProps() {
|
|
3062
|
+
const commonProps = {
|
|
3063
|
+
container: this.shadowRoot ?? this,
|
|
3064
|
+
data: this.appData,
|
|
3065
|
+
id: this.appKey,
|
|
3066
|
+
keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
|
|
3067
|
+
showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
|
|
3068
|
+
url: this.getAttribute("url" /* url */)
|
|
3069
|
+
};
|
|
2715
3070
|
if (this.getAttribute("mode") === "js" /* INSTANCE */) {
|
|
2716
3071
|
return {
|
|
2717
|
-
|
|
2718
|
-
data: this.appData,
|
|
2719
|
-
id: this.appKey,
|
|
2720
|
-
keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
|
|
3072
|
+
...commonProps,
|
|
2721
3073
|
mode: "js" /* INSTANCE */,
|
|
2722
3074
|
scopeCss: this.getBooleanAttr("scopeCss" /* scopeCss */) && !this.getBooleanAttr("setShodowDom" /* setShodowDom */),
|
|
2723
|
-
scopeJs: this.getBooleanAttr("scopeJs" /* scopeJs */)
|
|
2724
|
-
showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
|
|
2725
|
-
url: this.getAttribute("url" /* url */)
|
|
3075
|
+
scopeJs: this.getBooleanAttr("scopeJs" /* scopeJs */)
|
|
2726
3076
|
};
|
|
2727
3077
|
}
|
|
2728
3078
|
return {
|
|
2729
|
-
|
|
2730
|
-
data: this.appData,
|
|
2731
|
-
id: this.appKey,
|
|
2732
|
-
keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
|
|
3079
|
+
...commonProps,
|
|
2733
3080
|
mode: "app" /* APP */,
|
|
2734
3081
|
scopeCss: !this.getBooleanAttr("setShodowDom" /* setShodowDom */),
|
|
2735
3082
|
scopeJs: !this.getBooleanAttr("scopeJs" /* scopeJs */),
|
|
2736
|
-
scopeLocation: this.getBooleanAttr("scopeLocation" /* scopeLocation */)
|
|
2737
|
-
showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
|
|
2738
|
-
url: this.getAttribute("url" /* url */)
|
|
3083
|
+
scopeLocation: this.getBooleanAttr("scopeLocation" /* scopeLocation */)
|
|
2739
3084
|
};
|
|
2740
3085
|
}
|
|
2741
3086
|
};
|
|
@@ -2743,10 +3088,12 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2743
3088
|
// src/lifecycle/mount.ts
|
|
2744
3089
|
function mount(appKey, container, callback) {
|
|
2745
3090
|
const app = appCache.getApp(appKey);
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
3091
|
+
if (app) {
|
|
3092
|
+
nextTask(() => {
|
|
3093
|
+
beforeLoad();
|
|
3094
|
+
app.mount(container, callback);
|
|
3095
|
+
});
|
|
3096
|
+
}
|
|
2750
3097
|
}
|
|
2751
3098
|
|
|
2752
3099
|
// src/lifecycle/unload.ts
|