@blueking/bk-weweb 0.0.35-beta.1 → 0.0.35-beta.3
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 +395 -293
- package/dist/index.esm.js +670 -462
- 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,7 @@ function rewriteWindowFunction(fakeWindow) {
|
|
|
473
525
|
|
|
474
526
|
// src/context/sandbox.ts
|
|
475
527
|
var SandBox = class {
|
|
528
|
+
/** 初始化沙箱环境 */
|
|
476
529
|
constructor(app) {
|
|
477
530
|
this.app = app;
|
|
478
531
|
const windowDescriptorSet = /* @__PURE__ */ new Set();
|
|
@@ -488,63 +541,30 @@ var SandBox = class {
|
|
|
488
541
|
this.fakeWindow = fakeWindow;
|
|
489
542
|
const { resetWindowFunction } = rewriteWindowFunction(this.fakeWindow);
|
|
490
543
|
this.resetWindowFunction = resetWindowFunction;
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
)}__`;
|
|
544
|
+
const appIdentifier = (app.name || app.appCacheKey).replace(/[-,:~'"]/g, "_");
|
|
545
|
+
this.windowSymbolKey = `__${appIdentifier}_${random(10)}__`;
|
|
494
546
|
this.proxyWindow = new Proxy(this.fakeWindow, {
|
|
495
|
-
// 定义属性
|
|
496
547
|
defineProperty: (target, key, value) => {
|
|
497
548
|
if (windowDescriptorSet.has(key)) {
|
|
498
549
|
return Reflect.defineProperty(rawWindow, key, value);
|
|
499
550
|
}
|
|
500
551
|
return Reflect.defineProperty(target, key, value);
|
|
501
552
|
},
|
|
502
|
-
// 删除属性
|
|
503
553
|
deleteProperty: (target, key) => {
|
|
504
554
|
if (Object.hasOwn(target, key)) {
|
|
505
|
-
this.sameRawWindowKeySet.has(key)
|
|
506
|
-
|
|
555
|
+
if (this.sameRawWindowKeySet.has(key)) {
|
|
556
|
+
this.sameRawWindowKeySet.delete(key);
|
|
557
|
+
}
|
|
558
|
+
if (this.inRawWindowKeySet.has(key)) {
|
|
559
|
+
Reflect.deleteProperty(rawWindow, key);
|
|
560
|
+
}
|
|
507
561
|
return Reflect.deleteProperty(target, key);
|
|
508
562
|
}
|
|
509
563
|
return true;
|
|
510
564
|
},
|
|
511
|
-
// 获取属性
|
|
512
565
|
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);
|
|
566
|
+
return this.handleProxyGet(target, key, rawWindow);
|
|
546
567
|
},
|
|
547
|
-
// 获取属性描述符
|
|
548
568
|
getOwnPropertyDescriptor: (target, key) => {
|
|
549
569
|
if (Object.hasOwn(target, key)) {
|
|
550
570
|
return Object.getOwnPropertyDescriptor(target, key);
|
|
@@ -559,69 +579,188 @@ var SandBox = class {
|
|
|
559
579
|
}
|
|
560
580
|
return void 0;
|
|
561
581
|
},
|
|
562
|
-
// 检查属性是否存在
|
|
563
582
|
has: (target, key) => windowNativeFuncMap.has(key) || key in target || key in rawWindow,
|
|
564
|
-
// 获取所有属性名
|
|
565
583
|
ownKeys: (target) => Array.from(new Set(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)))),
|
|
566
|
-
// 设置属性
|
|
567
584
|
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;
|
|
585
|
+
return this.handleProxySet(target, key, value, rawWindow);
|
|
596
586
|
}
|
|
597
587
|
});
|
|
598
588
|
rawWindow[this.windowSymbolKey] = this.proxyWindow;
|
|
599
589
|
}
|
|
600
|
-
|
|
590
|
+
/** 沙箱激活状态标识 */
|
|
601
591
|
active = false;
|
|
602
|
-
|
|
592
|
+
/** 记录在原始 window 上新增的属性键集合 */
|
|
603
593
|
inRawWindowKeySet = /* @__PURE__ */ new Set();
|
|
604
|
-
|
|
594
|
+
/** 重置文档和 body 事件的函数 */
|
|
605
595
|
resetDocumentAndBodyEvent;
|
|
606
|
-
|
|
596
|
+
/** 重置 window 函数的方法 */
|
|
607
597
|
resetWindowFunction;
|
|
608
|
-
|
|
598
|
+
/** 记录与原始 window 相同的属性键集合 */
|
|
609
599
|
sameRawWindowKeySet = /* @__PURE__ */ new Set();
|
|
610
|
-
|
|
600
|
+
/** 伪造的 window 对象 */
|
|
611
601
|
fakeWindow;
|
|
612
|
-
|
|
602
|
+
/** 代理的 document 对象 */
|
|
613
603
|
proxyDocument;
|
|
614
|
-
|
|
604
|
+
/** 代理的 window 对象 */
|
|
615
605
|
proxyWindow;
|
|
616
|
-
|
|
606
|
+
/** 原始 document 对象 */
|
|
617
607
|
rawDocument;
|
|
618
|
-
|
|
608
|
+
/** 原始 window 对象 */
|
|
619
609
|
rawWindow;
|
|
620
|
-
|
|
610
|
+
/** 在 window 上的唯一标识键 */
|
|
621
611
|
windowSymbolKey;
|
|
612
|
+
/** 处理代理对象的 get 操作 */
|
|
613
|
+
handleProxyGet(target, key, rawWindow) {
|
|
614
|
+
if (key === Symbol.unscopables || windowNativeFuncMap.has(key)) {
|
|
615
|
+
return rawWindow[key];
|
|
616
|
+
}
|
|
617
|
+
if (DEV_MICRO_APP_WINDOW_KEY_MAP[key]) {
|
|
618
|
+
return this.fakeWindow[key];
|
|
619
|
+
}
|
|
620
|
+
if (WINDOW_ALIAS_LIST.includes(key)) {
|
|
621
|
+
return this.proxyWindow;
|
|
622
|
+
}
|
|
623
|
+
if (key === "document") {
|
|
624
|
+
this.app.registerRunningApp();
|
|
625
|
+
return this.rawDocument;
|
|
626
|
+
}
|
|
627
|
+
if (key === "eval") {
|
|
628
|
+
this.app.registerRunningApp();
|
|
629
|
+
return eval;
|
|
630
|
+
}
|
|
631
|
+
if (this.shouldUseIframeLocation(key)) {
|
|
632
|
+
if (this.app instanceof MicroAppModel && this.app.iframe?.contentWindow) {
|
|
633
|
+
return this.app.iframe.contentWindow[key];
|
|
634
|
+
}
|
|
635
|
+
return void 0;
|
|
636
|
+
}
|
|
637
|
+
if (key === "hasOwnProperty") {
|
|
638
|
+
return (checkKey) => Object.hasOwn(this.fakeWindow, checkKey) || Object.hasOwn(rawWindow, checkKey);
|
|
639
|
+
}
|
|
640
|
+
if (key === "top" || key === "parent") {
|
|
641
|
+
if (rawWindow === rawWindow.parent) {
|
|
642
|
+
return this.proxyWindow;
|
|
643
|
+
}
|
|
644
|
+
return Reflect.get(rawWindow, key);
|
|
645
|
+
}
|
|
646
|
+
if (key === "getComputedStyle") {
|
|
647
|
+
return this.createGetComputedStyleProxy(rawWindow);
|
|
648
|
+
}
|
|
649
|
+
if (Reflect.has(target, key) || BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
|
|
650
|
+
return Reflect.get(target, key);
|
|
651
|
+
}
|
|
652
|
+
const rawValue = Reflect.get(rawWindow, key);
|
|
653
|
+
return bindFunctionToRawWindow(rawWindow, rawValue);
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* 处理代理对象的 set 操作
|
|
657
|
+
* @description 统一处理代理对象属性设置的复杂逻辑
|
|
658
|
+
* @param target - 目标对象
|
|
659
|
+
* @param key - 属性键
|
|
660
|
+
* @param value - 属性值
|
|
661
|
+
* @param rawWindow - 原始 window 对象
|
|
662
|
+
* @returns boolean - 设置是否成功
|
|
663
|
+
* @private
|
|
664
|
+
*/
|
|
665
|
+
handleProxySet(target, key, value, rawWindow) {
|
|
666
|
+
if (!this.active) {
|
|
667
|
+
return true;
|
|
668
|
+
}
|
|
669
|
+
if (this.shouldUseIframeLocation(key)) {
|
|
670
|
+
const iframe = this.app instanceof MicroAppModel ? this.app.iframe : null;
|
|
671
|
+
return iframe?.contentWindow ? Reflect.set(iframe.contentWindow, key, value) : true;
|
|
672
|
+
}
|
|
673
|
+
if (key === "location") {
|
|
674
|
+
Reflect.set(rawWindow, key, value);
|
|
675
|
+
} else if (this.shouldSetOnTarget(target, key, rawWindow)) {
|
|
676
|
+
this.setPropertyOnTarget(target, key, value, rawWindow);
|
|
677
|
+
} else {
|
|
678
|
+
Reflect.set(target, key, value);
|
|
679
|
+
this.sameRawWindowKeySet.add(key);
|
|
680
|
+
}
|
|
681
|
+
this.handleWhiteListProperty(key, value, rawWindow);
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* 判断是否应该使用 iframe 的 location
|
|
686
|
+
* @description 检查是否在 iframe 模式下访问 location 相关属性
|
|
687
|
+
* @param key - 属性键
|
|
688
|
+
* @returns boolean - 是否使用 iframe location
|
|
689
|
+
* @private
|
|
690
|
+
*/
|
|
691
|
+
shouldUseIframeLocation(key) {
|
|
692
|
+
return !!(BK_WEWEB_LOCATION_KEY_LIST.includes(key) && this.app instanceof MicroAppModel && this.app.iframe && this.app.scopeLocation);
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* 创建 getComputedStyle 方法的代理
|
|
696
|
+
* @description 为 getComputedStyle 方法创建安全的代理实现
|
|
697
|
+
* @param rawWindow - 原始 window 对象
|
|
698
|
+
* @returns Function - 代理后的 getComputedStyle 方法
|
|
699
|
+
* @private
|
|
700
|
+
*/
|
|
701
|
+
createGetComputedStyleProxy(rawWindow) {
|
|
702
|
+
return (element, pseudoElt) => {
|
|
703
|
+
if (element instanceof Element) {
|
|
704
|
+
return rawWindow.getComputedStyle(element, pseudoElt);
|
|
705
|
+
}
|
|
706
|
+
return rawWindow.getComputedStyle(document.body, pseudoElt);
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* 判断是否应该在目标对象上设置属性
|
|
711
|
+
* @description 检查属性设置的逻辑条件
|
|
712
|
+
* @param target - 目标对象
|
|
713
|
+
* @param key - 属性键
|
|
714
|
+
* @param rawWindow - 原始 window 对象
|
|
715
|
+
* @returns boolean - 是否在目标对象上设置
|
|
716
|
+
* @private
|
|
717
|
+
*/
|
|
718
|
+
shouldSetOnTarget(target, key, rawWindow) {
|
|
719
|
+
return !Object.hasOwn(target, key) && Object.hasOwn(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* 在目标对象上设置属性
|
|
723
|
+
* @description 安全地在目标对象上设置属性,保持描述符特性
|
|
724
|
+
* @param target - 目标对象
|
|
725
|
+
* @param key - 属性键
|
|
726
|
+
* @param value - 属性值
|
|
727
|
+
* @param rawWindow - 原始 window 对象
|
|
728
|
+
* @private
|
|
729
|
+
*/
|
|
730
|
+
setPropertyOnTarget(target, key, value, rawWindow) {
|
|
731
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
732
|
+
if (!descriptor) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const { configurable, enumerable, writable } = descriptor;
|
|
736
|
+
if (writable) {
|
|
737
|
+
Object.defineProperty(target, key, {
|
|
738
|
+
configurable,
|
|
739
|
+
enumerable,
|
|
740
|
+
value,
|
|
741
|
+
writable
|
|
742
|
+
});
|
|
743
|
+
this.sameRawWindowKeySet.add(key);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* 处理白名单属性
|
|
748
|
+
* @description 处理需要在原始 window 上设置的白名单属性
|
|
749
|
+
* @param key - 属性键
|
|
750
|
+
* @param value - 属性值
|
|
751
|
+
* @param rawWindow - 原始 window 对象
|
|
752
|
+
* @private
|
|
753
|
+
*/
|
|
754
|
+
handleWhiteListProperty(key, value, rawWindow) {
|
|
755
|
+
if (WINDOW_WHITE_LIST.includes(key) && !Reflect.has(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
|
|
756
|
+
Reflect.set(rawWindow, key, value);
|
|
757
|
+
this.inRawWindowKeySet.add(key);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
622
760
|
/**
|
|
623
761
|
* 激活沙箱
|
|
624
|
-
* @
|
|
762
|
+
* @description 启动沙箱环境,初始化代理对象和事件处理
|
|
763
|
+
* @param data - 传递给沙箱的数据(可选)
|
|
625
764
|
*/
|
|
626
765
|
activated(data) {
|
|
627
766
|
if (!this.active) {
|
|
@@ -633,7 +772,8 @@ var SandBox = class {
|
|
|
633
772
|
}
|
|
634
773
|
}
|
|
635
774
|
/**
|
|
636
|
-
*
|
|
775
|
+
* 停用沙箱
|
|
776
|
+
* @description 关闭沙箱环境,清理所有副作用和修改
|
|
637
777
|
*/
|
|
638
778
|
deactivated() {
|
|
639
779
|
if (!this.active) return;
|
|
@@ -1241,9 +1381,7 @@ var MicroInstanceModel = class {
|
|
|
1241
1381
|
this.fetchSource = props.fetchSource;
|
|
1242
1382
|
this.initializeSandBox();
|
|
1243
1383
|
}
|
|
1244
|
-
/**
|
|
1245
|
-
* 激活微模块
|
|
1246
|
-
*/
|
|
1384
|
+
/** 激活微模块 */
|
|
1247
1385
|
activated(container, callback) {
|
|
1248
1386
|
this.isPreLoad = false;
|
|
1249
1387
|
this.state = AppState.ACTIVATED;
|
|
@@ -1256,22 +1394,19 @@ var MicroInstanceModel = class {
|
|
|
1256
1394
|
callback?.(this, scriptInfo?.exportInstance);
|
|
1257
1395
|
}
|
|
1258
1396
|
}
|
|
1259
|
-
/**
|
|
1260
|
-
* 停用微模块
|
|
1261
|
-
*/
|
|
1397
|
+
/** 停用微模块 */
|
|
1262
1398
|
deactivated() {
|
|
1263
1399
|
this.state = AppState.DEACTIVATED;
|
|
1264
1400
|
this.sandBox?.deactivated();
|
|
1265
1401
|
}
|
|
1266
|
-
/**
|
|
1267
|
-
* 挂载微模块
|
|
1268
|
-
*/
|
|
1402
|
+
/** 挂载微模块 */
|
|
1269
1403
|
mount(container, callback) {
|
|
1270
1404
|
this.isPreLoad = false;
|
|
1271
1405
|
this.container = container ?? this.container;
|
|
1272
1406
|
this.state = AppState.MOUNTING;
|
|
1273
1407
|
this.setContainerAttribute(this.container);
|
|
1274
1408
|
this.setupContainer();
|
|
1409
|
+
this.executeStyles();
|
|
1275
1410
|
this.sandBox?.activated();
|
|
1276
1411
|
execAppScripts(this).finally(() => {
|
|
1277
1412
|
this.state = AppState.MOUNTED;
|
|
@@ -1280,39 +1415,29 @@ var MicroInstanceModel = class {
|
|
|
1280
1415
|
callback?.(this, scriptInfo?.exportInstance);
|
|
1281
1416
|
});
|
|
1282
1417
|
}
|
|
1283
|
-
/**
|
|
1284
|
-
* 错误处理
|
|
1285
|
-
*/
|
|
1418
|
+
/** 错误处理 */
|
|
1286
1419
|
onError() {
|
|
1287
1420
|
this.state = AppState.ERROR;
|
|
1288
1421
|
}
|
|
1289
|
-
/**
|
|
1290
|
-
* 挂载处理
|
|
1291
|
-
*/
|
|
1422
|
+
/** 挂载处理 */
|
|
1292
1423
|
onMount() {
|
|
1293
1424
|
if (this.isPreLoad) return;
|
|
1294
1425
|
this.state = AppState.LOADED;
|
|
1295
1426
|
this.mount();
|
|
1296
1427
|
}
|
|
1297
|
-
/**
|
|
1298
|
-
* 注册运行中的应用
|
|
1299
|
-
*/
|
|
1428
|
+
/** 注册运行中的应用 */
|
|
1300
1429
|
registerRunningApp() {
|
|
1301
1430
|
setCurrentRunningApp(this);
|
|
1302
1431
|
Promise.resolve().then(() => setCurrentRunningApp(null));
|
|
1303
1432
|
}
|
|
1304
|
-
/**
|
|
1305
|
-
* 启动微模块
|
|
1306
|
-
*/
|
|
1433
|
+
/** 启动微模块 */
|
|
1307
1434
|
async start() {
|
|
1308
1435
|
if (!this.source || this.needsReload()) {
|
|
1309
1436
|
this.source = new EntrySource(this.url);
|
|
1310
1437
|
await this.source.importEntry(this);
|
|
1311
1438
|
}
|
|
1312
1439
|
}
|
|
1313
|
-
/**
|
|
1314
|
-
* 卸载微模块
|
|
1315
|
-
*/
|
|
1440
|
+
/** 卸载微模块 */
|
|
1316
1441
|
unmount(needDestroy) {
|
|
1317
1442
|
this.state = AppState.UNMOUNT;
|
|
1318
1443
|
this.sandBox?.deactivated();
|
|
@@ -1324,37 +1449,25 @@ var MicroInstanceModel = class {
|
|
|
1324
1449
|
this.container = void 0;
|
|
1325
1450
|
}
|
|
1326
1451
|
}
|
|
1327
|
-
/**
|
|
1328
|
-
* 设置微模块 状态
|
|
1329
|
-
*/
|
|
1330
1452
|
set status(value) {
|
|
1331
1453
|
this.state = value;
|
|
1332
1454
|
}
|
|
1333
|
-
/**
|
|
1334
|
-
* 获取微模块 状态
|
|
1335
|
-
*/
|
|
1336
1455
|
get status() {
|
|
1337
1456
|
return this.state;
|
|
1338
1457
|
}
|
|
1339
|
-
/**
|
|
1340
|
-
* 初始化沙盒
|
|
1341
|
-
*/
|
|
1458
|
+
/** 初始化沙盒 */
|
|
1342
1459
|
initializeSandBox() {
|
|
1343
1460
|
if (this.scopeJs) {
|
|
1344
1461
|
this.sandBox = new SandBox(this);
|
|
1345
1462
|
}
|
|
1346
1463
|
}
|
|
1347
|
-
/**
|
|
1348
|
-
* 设置容器属性
|
|
1349
|
-
*/
|
|
1464
|
+
/** 设置容器属性 */
|
|
1350
1465
|
setContainerAttribute(container) {
|
|
1351
1466
|
if (container instanceof HTMLElement) {
|
|
1352
1467
|
container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
|
|
1353
1468
|
}
|
|
1354
1469
|
}
|
|
1355
|
-
/**
|
|
1356
|
-
* 转移节点到新容器
|
|
1357
|
-
*/
|
|
1470
|
+
/** 转移节点到新容器 */
|
|
1358
1471
|
transferNodes(container) {
|
|
1359
1472
|
if (!this.container) return;
|
|
1360
1473
|
const fragment = document.createDocumentFragment();
|
|
@@ -1364,51 +1477,46 @@ var MicroInstanceModel = class {
|
|
|
1364
1477
|
}
|
|
1365
1478
|
container.appendChild(fragment);
|
|
1366
1479
|
}
|
|
1367
|
-
/**
|
|
1368
|
-
* 设置容器
|
|
1369
|
-
*/
|
|
1480
|
+
/** 设置容器 */
|
|
1370
1481
|
setupContainer() {
|
|
1371
|
-
if (
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1482
|
+
if (this.container) {
|
|
1483
|
+
this.container.innerHTML = "";
|
|
1484
|
+
if (this.showSourceCode) {
|
|
1485
|
+
const instanceWrapper = this.createInstanceWrapper();
|
|
1486
|
+
this.container.appendChild(instanceWrapper);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
/** 执行样式 */
|
|
1491
|
+
executeStyles() {
|
|
1492
|
+
if (this.source?.styles.size && this.container) {
|
|
1375
1493
|
executeAppStyles(this, this.container);
|
|
1376
1494
|
}
|
|
1377
|
-
this.container.appendChild(instanceWrap);
|
|
1378
1495
|
}
|
|
1379
|
-
/**
|
|
1380
|
-
* 创建微模块 包装器
|
|
1381
|
-
*/
|
|
1496
|
+
/** 创建实例包装器 */
|
|
1382
1497
|
createInstanceWrapper() {
|
|
1383
|
-
const
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
return instanceWrap;
|
|
1498
|
+
const wrapper = document.createElement("div");
|
|
1499
|
+
wrapper.id = `${this.name}${WRAPPER_SUFFIX}`;
|
|
1500
|
+
return wrapper;
|
|
1387
1501
|
}
|
|
1388
|
-
/**
|
|
1389
|
-
* 渲染微模块
|
|
1390
|
-
*/
|
|
1502
|
+
/** 渲染实例 */
|
|
1391
1503
|
renderInstance() {
|
|
1392
1504
|
const scriptInfo = this.getScriptInfo();
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
renderFunction(instanceWrap, this.data);
|
|
1505
|
+
if (scriptInfo?.exportInstance?.render && this.container) {
|
|
1506
|
+
const targetContainer = this.showSourceCode ? this.container.querySelector(`#${this.name}${WRAPPER_SUFFIX}`) : this.container;
|
|
1507
|
+
if (targetContainer) {
|
|
1508
|
+
scriptInfo.exportInstance.render(targetContainer, this.data);
|
|
1398
1509
|
}
|
|
1399
1510
|
}
|
|
1400
1511
|
}
|
|
1401
|
-
/**
|
|
1402
|
-
* 获取脚本信息
|
|
1403
|
-
*/
|
|
1512
|
+
/** 获取脚本信息 */
|
|
1404
1513
|
getScriptInfo() {
|
|
1405
|
-
|
|
1514
|
+
const script = this.source?.getScript(this.url);
|
|
1515
|
+
return script ? { exportInstance: script.exportInstance } : void 0;
|
|
1406
1516
|
}
|
|
1407
|
-
/**
|
|
1408
|
-
* 检查是否需要重新加载
|
|
1409
|
-
*/
|
|
1517
|
+
/** 检查是否需要重新加载 */
|
|
1410
1518
|
needsReload() {
|
|
1411
|
-
return
|
|
1519
|
+
return this.status === AppState.ERROR;
|
|
1412
1520
|
}
|
|
1413
1521
|
};
|
|
1414
1522
|
|
|
@@ -1437,12 +1545,7 @@ var Script = class {
|
|
|
1437
1545
|
this.fromHtml = fromHtml ?? false;
|
|
1438
1546
|
this.initial = initial ?? false;
|
|
1439
1547
|
}
|
|
1440
|
-
/**
|
|
1441
|
-
* 执行脚本代码
|
|
1442
|
-
* @param app 应用实例
|
|
1443
|
-
* @param needReplaceScriptElement 是否需要替换script标签
|
|
1444
|
-
* @returns 返回执行后的script标签或注释
|
|
1445
|
-
*/
|
|
1548
|
+
/** 执行脚本代码 */
|
|
1446
1549
|
async executeCode(app, needReplaceScriptElement = false) {
|
|
1447
1550
|
try {
|
|
1448
1551
|
if (!this.code) await this.getCode(app);
|
|
@@ -1482,9 +1585,7 @@ var Script = class {
|
|
|
1482
1585
|
}
|
|
1483
1586
|
return;
|
|
1484
1587
|
}
|
|
1485
|
-
/**
|
|
1486
|
-
* 内存脚本执行
|
|
1487
|
-
*/
|
|
1588
|
+
/** 内存脚本执行 */
|
|
1488
1589
|
executeMemoryScript(app, scopedCode) {
|
|
1489
1590
|
try {
|
|
1490
1591
|
const isScopedLocation = app instanceof MicroAppModel && app.scopeLocation;
|
|
@@ -1498,9 +1599,7 @@ var Script = class {
|
|
|
1498
1599
|
console.error(error);
|
|
1499
1600
|
}
|
|
1500
1601
|
}
|
|
1501
|
-
/**
|
|
1502
|
-
* 脚本标签执行
|
|
1503
|
-
*/
|
|
1602
|
+
/** 脚本标签执行 */
|
|
1504
1603
|
executeSourceScript(scriptElement, scopedCode) {
|
|
1505
1604
|
if (this.isModule) {
|
|
1506
1605
|
scriptElement.src = `${this.url}?key=${Date.now()}`;
|
|
@@ -1510,9 +1609,7 @@ var Script = class {
|
|
|
1510
1609
|
}
|
|
1511
1610
|
this.url && scriptElement.setAttribute("origin-src", this.url);
|
|
1512
1611
|
}
|
|
1513
|
-
/**
|
|
1514
|
-
* 获取脚本内容
|
|
1515
|
-
*/
|
|
1612
|
+
/** 获取脚本内容 */
|
|
1516
1613
|
async getCode(app) {
|
|
1517
1614
|
if (this.code.length || !this.url) {
|
|
1518
1615
|
return this.code;
|
|
@@ -1537,9 +1634,7 @@ var Script = class {
|
|
|
1537
1634
|
setCode(code) {
|
|
1538
1635
|
this.code = code;
|
|
1539
1636
|
}
|
|
1540
|
-
/**
|
|
1541
|
-
* 转换脚本内容
|
|
1542
|
-
*/
|
|
1637
|
+
/** 转换脚本内容 */
|
|
1543
1638
|
transformCode(app) {
|
|
1544
1639
|
const sourceMapUrl = "";
|
|
1545
1640
|
if (app.sandBox) {
|
|
@@ -1684,9 +1779,7 @@ var MicroAppModel = class {
|
|
|
1684
1779
|
this.initializeSandBox();
|
|
1685
1780
|
this.setContainerAttribute();
|
|
1686
1781
|
}
|
|
1687
|
-
/**
|
|
1688
|
-
* 激活微应用
|
|
1689
|
-
*/
|
|
1782
|
+
/** 激活微应用 */
|
|
1690
1783
|
activated(container, callback) {
|
|
1691
1784
|
this.isPreLoad = false;
|
|
1692
1785
|
this.state = AppState.ACTIVATED;
|
|
@@ -1699,9 +1792,7 @@ var MicroAppModel = class {
|
|
|
1699
1792
|
callback?.(this);
|
|
1700
1793
|
}
|
|
1701
1794
|
}
|
|
1702
|
-
/**
|
|
1703
|
-
* 创建隔离iframe
|
|
1704
|
-
*/
|
|
1795
|
+
/** 创建隔离iframe */
|
|
1705
1796
|
createIframe() {
|
|
1706
1797
|
return new Promise((resolve) => {
|
|
1707
1798
|
const iframe = this.createIframeElement();
|
|
@@ -1713,16 +1804,12 @@ var MicroAppModel = class {
|
|
|
1713
1804
|
}
|
|
1714
1805
|
});
|
|
1715
1806
|
}
|
|
1716
|
-
/**
|
|
1717
|
-
* 停用微应用
|
|
1718
|
-
*/
|
|
1807
|
+
/** 停用微应用 */
|
|
1719
1808
|
deactivated() {
|
|
1720
1809
|
this.state = AppState.DEACTIVATED;
|
|
1721
1810
|
this.sandBox?.deactivated();
|
|
1722
1811
|
}
|
|
1723
|
-
/**
|
|
1724
|
-
* 初始化ShadowRoot容器
|
|
1725
|
-
*/
|
|
1812
|
+
/** 初始化ShadowRoot容器 */
|
|
1726
1813
|
initShadowRootContainer() {
|
|
1727
1814
|
if (this.container instanceof ShadowRoot) {
|
|
1728
1815
|
Object.defineProperties(this.container, {
|
|
@@ -1734,9 +1821,7 @@ var MicroAppModel = class {
|
|
|
1734
1821
|
});
|
|
1735
1822
|
}
|
|
1736
1823
|
}
|
|
1737
|
-
/**
|
|
1738
|
-
* 挂载微应用
|
|
1739
|
-
*/
|
|
1824
|
+
/** 挂载微应用 */
|
|
1740
1825
|
mount(container, callback) {
|
|
1741
1826
|
this.isPreLoad = false;
|
|
1742
1827
|
this.container = container ?? this.container;
|
|
@@ -1752,30 +1837,22 @@ var MicroAppModel = class {
|
|
|
1752
1837
|
});
|
|
1753
1838
|
}
|
|
1754
1839
|
}
|
|
1755
|
-
/**
|
|
1756
|
-
* 错误处理
|
|
1757
|
-
*/
|
|
1840
|
+
/** 错误处理 */
|
|
1758
1841
|
onError() {
|
|
1759
1842
|
this.state = AppState.ERROR;
|
|
1760
1843
|
}
|
|
1761
|
-
/**
|
|
1762
|
-
* 挂载处理
|
|
1763
|
-
*/
|
|
1844
|
+
/** 挂载处理 */
|
|
1764
1845
|
onMount() {
|
|
1765
1846
|
if (this.isPreLoad) return;
|
|
1766
1847
|
this.state = AppState.LOADED;
|
|
1767
1848
|
this.mount();
|
|
1768
1849
|
}
|
|
1769
|
-
/**
|
|
1770
|
-
* 注册运行中的微应用
|
|
1771
|
-
*/
|
|
1850
|
+
/** 注册运行中的微应用 */
|
|
1772
1851
|
registerRunningApp() {
|
|
1773
1852
|
setCurrentRunningApp(this);
|
|
1774
1853
|
Promise.resolve().then(() => setCurrentRunningApp(null));
|
|
1775
1854
|
}
|
|
1776
|
-
/**
|
|
1777
|
-
* 启动微应用
|
|
1778
|
-
*/
|
|
1855
|
+
/** 启动微应用 */
|
|
1779
1856
|
async start() {
|
|
1780
1857
|
if (!this.source || this.needsReload()) {
|
|
1781
1858
|
this.state = AppState.LOADING;
|
|
@@ -1787,9 +1864,7 @@ var MicroAppModel = class {
|
|
|
1787
1864
|
await this.source.importEntry(this);
|
|
1788
1865
|
}
|
|
1789
1866
|
}
|
|
1790
|
-
/**
|
|
1791
|
-
* 卸载微应用
|
|
1792
|
-
*/
|
|
1867
|
+
/** 卸载微应用 */
|
|
1793
1868
|
unmount(needDestroy = false) {
|
|
1794
1869
|
this.state = AppState.UNMOUNT;
|
|
1795
1870
|
this.sandBox?.deactivated();
|
|
@@ -1801,123 +1876,84 @@ var MicroAppModel = class {
|
|
|
1801
1876
|
this.container = void 0;
|
|
1802
1877
|
}
|
|
1803
1878
|
}
|
|
1804
|
-
/**
|
|
1805
|
-
* 获取微应用缓存键
|
|
1806
|
-
*/
|
|
1807
1879
|
get appCacheKey() {
|
|
1808
1880
|
return this.url;
|
|
1809
1881
|
}
|
|
1810
|
-
/**
|
|
1811
|
-
* 获取微应用状态
|
|
1812
|
-
*/
|
|
1813
1882
|
get status() {
|
|
1814
1883
|
return this.state;
|
|
1815
1884
|
}
|
|
1816
|
-
/**
|
|
1817
|
-
* 设置微应用状态
|
|
1818
|
-
*/
|
|
1819
1885
|
set status(value) {
|
|
1820
1886
|
this.state = value;
|
|
1821
1887
|
}
|
|
1822
|
-
/**
|
|
1823
|
-
* 初始化沙盒
|
|
1824
|
-
*/
|
|
1888
|
+
/** 初始化沙盒 */
|
|
1825
1889
|
initializeSandBox() {
|
|
1826
1890
|
if (this.scopeJs) {
|
|
1827
1891
|
this.sandBox = new SandBox(this);
|
|
1828
1892
|
}
|
|
1829
1893
|
}
|
|
1830
|
-
/**
|
|
1831
|
-
* 设置容器属性
|
|
1832
|
-
*/
|
|
1894
|
+
/** 设置容器属性 */
|
|
1833
1895
|
setContainerAttribute(container) {
|
|
1834
1896
|
const targetContainer = container || this.container;
|
|
1835
1897
|
if (targetContainer instanceof HTMLElement) {
|
|
1836
1898
|
targetContainer.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
|
|
1837
1899
|
}
|
|
1838
1900
|
}
|
|
1839
|
-
/**
|
|
1840
|
-
* 转移节点到新容器
|
|
1841
|
-
*/
|
|
1901
|
+
/** 转移节点到新容器 */
|
|
1842
1902
|
transferNodes(container) {
|
|
1903
|
+
if (!this.container) return;
|
|
1843
1904
|
const fragment = document.createDocumentFragment();
|
|
1844
1905
|
const nodeList = Array.from(this.container.childNodes);
|
|
1845
1906
|
for (const node of nodeList) {
|
|
1846
1907
|
this.setupNodeProperties(node);
|
|
1847
1908
|
fragment.appendChild(node);
|
|
1848
1909
|
}
|
|
1849
|
-
container.innerHTML = "";
|
|
1850
1910
|
container.appendChild(fragment);
|
|
1851
1911
|
}
|
|
1852
|
-
/**
|
|
1853
|
-
* 设置节点属性
|
|
1854
|
-
*/
|
|
1912
|
+
/** 设置节点属性 */
|
|
1855
1913
|
setupNodeProperties(node) {
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1914
|
+
const nodeWithProps = node;
|
|
1915
|
+
if (this.keepAlive) {
|
|
1916
|
+
nodeWithProps.__KEEP_ALIVE__ = this.name;
|
|
1917
|
+
}
|
|
1918
|
+
nodeWithProps.__BK_WEWEB_APP_KEY__ = this.name;
|
|
1919
|
+
nodeWithProps.data = this.data;
|
|
1862
1920
|
}
|
|
1863
|
-
/**
|
|
1864
|
-
* 创建iframe元素
|
|
1865
|
-
*/
|
|
1921
|
+
/** 创建iframe元素 */
|
|
1866
1922
|
createIframeElement() {
|
|
1867
1923
|
const iframe = document.createElement("iframe");
|
|
1868
1924
|
const url = new URL(addUrlProtocol(this.url));
|
|
1869
|
-
|
|
1870
|
-
iframe.setAttribute("src", srcUrl);
|
|
1925
|
+
iframe.src = this.buildIframeSrc(url);
|
|
1871
1926
|
iframe.style.cssText = IFRAME_CONSTANTS.STYLE_HIDDEN;
|
|
1872
1927
|
return iframe;
|
|
1873
1928
|
}
|
|
1874
|
-
/**
|
|
1875
|
-
* 构建iframe的src地址
|
|
1876
|
-
*/
|
|
1929
|
+
/** 构建iframe源地址 */
|
|
1877
1930
|
buildIframeSrc(url) {
|
|
1878
|
-
|
|
1879
|
-
return `${origin}${url.pathname || "/"}${url.search}${url.hash}`;
|
|
1931
|
+
return `${url.protocol}//${url.host}`;
|
|
1880
1932
|
}
|
|
1881
|
-
/**
|
|
1882
|
-
* 检查是否为Chrome用户代理
|
|
1883
|
-
*/
|
|
1933
|
+
/** 检查是否为Chrome浏览器 */
|
|
1884
1934
|
isChromeUserAgent() {
|
|
1885
|
-
return navigator.userAgent.
|
|
1935
|
+
return navigator.userAgent.includes(IFRAME_CONSTANTS.CHROME_USER_AGENT);
|
|
1886
1936
|
}
|
|
1887
|
-
/**
|
|
1888
|
-
* 处理非Chrome浏览器的iframe
|
|
1889
|
-
*/
|
|
1937
|
+
/** 处理非Chrome浏览器iframe */
|
|
1890
1938
|
handleNonChromeIframe(iframe, resolve) {
|
|
1891
|
-
const
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
resolve(iframe);
|
|
1900
|
-
}
|
|
1901
|
-
}, IFRAME_CONSTANTS.POLLING_INTERVAL);
|
|
1939
|
+
const iframeOnload = () => {
|
|
1940
|
+
resolve(iframe);
|
|
1941
|
+
};
|
|
1942
|
+
if (iframe.contentDocument?.readyState === "complete") {
|
|
1943
|
+
iframeOnload();
|
|
1944
|
+
} else {
|
|
1945
|
+
iframe.addEventListener("load", iframeOnload);
|
|
1946
|
+
}
|
|
1902
1947
|
}
|
|
1903
|
-
/**
|
|
1904
|
-
* 渲染微应用内容
|
|
1905
|
-
*/
|
|
1948
|
+
/** 渲染应用内容 */
|
|
1906
1949
|
renderAppContent() {
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
for (const node of Array.from(clonedNode?.childNodes || [])) {
|
|
1910
|
-
this.setupNodeProperties(node);
|
|
1911
|
-
fragment.appendChild(node);
|
|
1950
|
+
if (this.showSourceCode && this.source) {
|
|
1951
|
+
this.container.innerHTML = this.source.rawHtml || IFRAME_CONSTANTS.DEFAULT_HTML;
|
|
1912
1952
|
}
|
|
1913
|
-
this.container.innerHTML = "";
|
|
1914
|
-
this.container.appendChild(fragment);
|
|
1915
1953
|
}
|
|
1916
|
-
/**
|
|
1917
|
-
* 检查是否需要重新加载
|
|
1918
|
-
*/
|
|
1954
|
+
/** 检查是否需要重新加载 */
|
|
1919
1955
|
needsReload() {
|
|
1920
|
-
return
|
|
1956
|
+
return this.status === AppState.ERROR;
|
|
1921
1957
|
}
|
|
1922
1958
|
};
|
|
1923
1959
|
|
|
@@ -2012,9 +2048,7 @@ var EntrySource = class {
|
|
|
2012
2048
|
rawHtml;
|
|
2013
2049
|
scripts;
|
|
2014
2050
|
styles;
|
|
2015
|
-
/**
|
|
2016
|
-
* 收集链接元素
|
|
2017
|
-
*/
|
|
2051
|
+
/** 收集链接元素 */
|
|
2018
2052
|
collectLink = (link, parent, needReplaceElement = false) => {
|
|
2019
2053
|
if (link.hasAttribute("exclude")) {
|
|
2020
2054
|
return {
|
|
@@ -2037,9 +2071,7 @@ var EntrySource = class {
|
|
|
2037
2071
|
}
|
|
2038
2072
|
return { replace: link };
|
|
2039
2073
|
};
|
|
2040
|
-
/**
|
|
2041
|
-
* 收集脚本元素
|
|
2042
|
-
*/
|
|
2074
|
+
/** 收集脚本元素 */
|
|
2043
2075
|
collectScript = (script, parent, needReplaceElement = false) => {
|
|
2044
2076
|
if (this.shouldIgnoreScript(script)) {
|
|
2045
2077
|
return;
|
|
@@ -2056,9 +2088,7 @@ var EntrySource = class {
|
|
|
2056
2088
|
}
|
|
2057
2089
|
return { replace: script };
|
|
2058
2090
|
};
|
|
2059
|
-
/**
|
|
2060
|
-
* 收集样式和脚本
|
|
2061
|
-
*/
|
|
2091
|
+
/** 收集样式和脚本 */
|
|
2062
2092
|
collectScriptAndStyle = (parent) => {
|
|
2063
2093
|
this.processLinks(parent);
|
|
2064
2094
|
this.processStyles(parent);
|
|
@@ -2070,9 +2100,7 @@ var EntrySource = class {
|
|
|
2070
2100
|
getStyle = (urlOrCode) => {
|
|
2071
2101
|
return this.styles.get(urlOrCode) || Array.from(this.styles.values()).find((style) => style.code === urlOrCode);
|
|
2072
2102
|
};
|
|
2073
|
-
/**
|
|
2074
|
-
* 导入入口资源
|
|
2075
|
-
*/
|
|
2103
|
+
/** html entry */
|
|
2076
2104
|
async importEntry(app) {
|
|
2077
2105
|
await this.loadInitialSources(app);
|
|
2078
2106
|
if (app instanceof MicroAppModel) {
|
|
@@ -2081,9 +2109,7 @@ var EntrySource = class {
|
|
|
2081
2109
|
await this.importInstanceEntry(app);
|
|
2082
2110
|
}
|
|
2083
2111
|
}
|
|
2084
|
-
/**
|
|
2085
|
-
* 导入HTML入口
|
|
2086
|
-
*/
|
|
2112
|
+
/** 微应用入口 */
|
|
2087
2113
|
async importHtmlEntry(app) {
|
|
2088
2114
|
const htmlStr = await this.fetchHtmlContent(app);
|
|
2089
2115
|
if (!htmlStr) {
|
|
@@ -2096,9 +2122,7 @@ var EntrySource = class {
|
|
|
2096
2122
|
await executeAppStyles(app, wrapElement);
|
|
2097
2123
|
this.html = wrapElement;
|
|
2098
2124
|
}
|
|
2099
|
-
/**
|
|
2100
|
-
* 导入实例入口
|
|
2101
|
-
*/
|
|
2125
|
+
/** 微模块入口 */
|
|
2102
2126
|
async importInstanceEntry(app) {
|
|
2103
2127
|
const jsStr = await this.fetchJsContent(app);
|
|
2104
2128
|
if (!jsStr) {
|
|
@@ -2123,9 +2147,7 @@ var EntrySource = class {
|
|
|
2123
2147
|
setStyle = (url, style) => {
|
|
2124
2148
|
this.styles.set(url, style);
|
|
2125
2149
|
};
|
|
2126
|
-
/**
|
|
2127
|
-
* 处理样式表链接
|
|
2128
|
-
*/
|
|
2150
|
+
/** 处理样式表链接 */
|
|
2129
2151
|
handleStylesheetLink = (link, parent, href, needReplaceElement) => {
|
|
2130
2152
|
const fullHref = fillUpPath(href, this.url);
|
|
2131
2153
|
const replaceElement = document.createComment(`\u3010bk-weweb\u3011style with href=${fullHref}`);
|
|
@@ -2320,37 +2342,76 @@ var EntrySource = class {
|
|
|
2320
2342
|
|
|
2321
2343
|
// src/cache/app-cache.ts
|
|
2322
2344
|
var AppCache = class {
|
|
2323
|
-
|
|
2345
|
+
/** 基础资源源,用于主应用共享资源包 */
|
|
2324
2346
|
baseSource;
|
|
2347
|
+
/** 应用实例缓存映射表 */
|
|
2325
2348
|
cache;
|
|
2349
|
+
/**
|
|
2350
|
+
* 构造函数
|
|
2351
|
+
* @description 初始化应用缓存管理器
|
|
2352
|
+
*/
|
|
2326
2353
|
constructor() {
|
|
2327
2354
|
this.cache = /* @__PURE__ */ new Map();
|
|
2328
2355
|
this.baseSource = new EntrySource(location.href);
|
|
2329
2356
|
}
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2357
|
+
/**
|
|
2358
|
+
* 设置应用实例到缓存
|
|
2359
|
+
* @description 将应用实例添加到缓存中,使用应用的缓存键作为标识
|
|
2360
|
+
* @param app - 要缓存的应用实例
|
|
2361
|
+
*/
|
|
2362
|
+
setApp(app) {
|
|
2363
|
+
this.cache.set(app.appCacheKey, app);
|
|
2333
2364
|
}
|
|
2334
|
-
|
|
2365
|
+
/**
|
|
2366
|
+
* 获取缓存的应用实例
|
|
2367
|
+
* @description 根据名称或ID获取已缓存的应用实例
|
|
2368
|
+
* @param name - 应用名称或ID,为空时返回 undefined
|
|
2369
|
+
* @returns BaseModel | undefined - 应用实例或 undefined
|
|
2370
|
+
*/
|
|
2335
2371
|
getApp(name) {
|
|
2336
2372
|
if (!name) return void 0;
|
|
2337
2373
|
const app = this.cache.get(name);
|
|
2338
2374
|
if (app) return app;
|
|
2339
2375
|
return Array.from(this.cache.values()).find((item) => item.name === name);
|
|
2340
2376
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2377
|
+
/**
|
|
2378
|
+
* 删除缓存的应用实例
|
|
2379
|
+
* @description 从缓存中移除指定URL的应用实例
|
|
2380
|
+
* @param url - 要删除的应用URL标识
|
|
2381
|
+
*/
|
|
2382
|
+
deleteApp(url) {
|
|
2383
|
+
this.cache.delete(url);
|
|
2344
2384
|
}
|
|
2385
|
+
/**
|
|
2386
|
+
* 获取缓存的HTML内容
|
|
2387
|
+
* @description 根据URL获取已缓存的HTML内容
|
|
2388
|
+
* @param url - 应用的URL
|
|
2389
|
+
* @returns string - HTML内容,未找到时返回空字符串
|
|
2390
|
+
*/
|
|
2345
2391
|
getCacheHtml(url) {
|
|
2346
2392
|
const list = Array.from(this.cache.values());
|
|
2347
2393
|
const app = list.find((item) => item.url === url);
|
|
2348
2394
|
if (app) return app.source?.rawHtml || "";
|
|
2349
2395
|
return "";
|
|
2350
2396
|
}
|
|
2397
|
+
/**
|
|
2398
|
+
* 设置基础应用脚本
|
|
2399
|
+
* @description 将脚本添加到基础资源源中,供多个应用共享
|
|
2400
|
+
* @param url - 脚本的URL
|
|
2401
|
+
* @param script - 脚本实例
|
|
2402
|
+
*/
|
|
2403
|
+
setBaseAppScript(url, script) {
|
|
2404
|
+
this.baseSource.setScript(url, script);
|
|
2405
|
+
}
|
|
2406
|
+
/**
|
|
2407
|
+
* 获取缓存的脚本资源
|
|
2408
|
+
* @description 从基础资源源或应用缓存中获取脚本资源
|
|
2409
|
+
* @param url - 脚本的URL
|
|
2410
|
+
* @returns Script | undefined - 脚本实例或 undefined
|
|
2411
|
+
*/
|
|
2351
2412
|
getCacheScript(url) {
|
|
2352
2413
|
let script = this.baseSource.getScript(url);
|
|
2353
|
-
if (script) return;
|
|
2414
|
+
if (script) return script;
|
|
2354
2415
|
const list = Array.from(this.cache.values());
|
|
2355
2416
|
list.some((app) => {
|
|
2356
2417
|
script = app.source?.getScript(url);
|
|
@@ -2358,9 +2419,33 @@ var AppCache = class {
|
|
|
2358
2419
|
});
|
|
2359
2420
|
return script;
|
|
2360
2421
|
}
|
|
2422
|
+
/**
|
|
2423
|
+
* 设置基础应用样式
|
|
2424
|
+
* @description 将样式添加到基础资源源中,供多个应用共享
|
|
2425
|
+
* @param url - 样式的URL
|
|
2426
|
+
* @param style - 样式实例
|
|
2427
|
+
*/
|
|
2428
|
+
setBaseAppStyle(url, style) {
|
|
2429
|
+
this.baseSource.setStyle(url, style);
|
|
2430
|
+
}
|
|
2431
|
+
/**
|
|
2432
|
+
* 获取基础应用样式
|
|
2433
|
+
* @description 从基础资源源中获取样式资源
|
|
2434
|
+
* @param urlOrCode - 样式的URL或代码
|
|
2435
|
+
* @returns Style | undefined - 样式实例或 undefined
|
|
2436
|
+
*/
|
|
2437
|
+
getBaseAppStyle(urlOrCode) {
|
|
2438
|
+
return this.baseSource.getStyle(urlOrCode);
|
|
2439
|
+
}
|
|
2440
|
+
/**
|
|
2441
|
+
* 获取缓存的样式资源
|
|
2442
|
+
* @description 从基础资源源或应用缓存中获取样式资源
|
|
2443
|
+
* @param url - 样式的URL
|
|
2444
|
+
* @returns Style | undefined - 样式实例或 undefined
|
|
2445
|
+
*/
|
|
2361
2446
|
getCacheStyle(url) {
|
|
2362
2447
|
let style = this.baseSource.getStyle(url);
|
|
2363
|
-
if (style) return;
|
|
2448
|
+
if (style) return style;
|
|
2364
2449
|
const list = Array.from(this.cache.values());
|
|
2365
2450
|
list.some((app) => {
|
|
2366
2451
|
style = app.source?.getStyle(url);
|
|
@@ -2368,15 +2453,11 @@ var AppCache = class {
|
|
|
2368
2453
|
});
|
|
2369
2454
|
return style;
|
|
2370
2455
|
}
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
}
|
|
2377
|
-
setBaseAppStyle(url, style) {
|
|
2378
|
-
this.baseSource.setStyle(url, style);
|
|
2379
|
-
}
|
|
2456
|
+
/**
|
|
2457
|
+
* 检查是否存在活跃的应用
|
|
2458
|
+
* @description 判断当前是否有处于非卸载状态的应用实例
|
|
2459
|
+
* @returns boolean - 存在活跃应用时返回 true
|
|
2460
|
+
*/
|
|
2380
2461
|
get hasActiveApp() {
|
|
2381
2462
|
return Array.from(this.cache.values()).some((app) => app.status !== AppState.UNMOUNT);
|
|
2382
2463
|
}
|
|
@@ -2396,8 +2477,8 @@ function getStyleSource(url, style, originLink) {
|
|
|
2396
2477
|
appCache.setBaseAppStyle(url, style);
|
|
2397
2478
|
replaceStyle.textContent = data;
|
|
2398
2479
|
dispatchLinkOrScriptLoad(originLink);
|
|
2399
|
-
}).catch((
|
|
2400
|
-
console.error(
|
|
2480
|
+
}).catch((error) => {
|
|
2481
|
+
console.error("Failed to load style resource:", error);
|
|
2401
2482
|
dispatchLinkOrScriptError(originLink);
|
|
2402
2483
|
});
|
|
2403
2484
|
return replaceStyle;
|
|
@@ -2412,59 +2493,67 @@ function getScriptSource(url, script, originScript) {
|
|
|
2412
2493
|
if (!url.startsWith("inline-")) {
|
|
2413
2494
|
originScript.setAttribute("origin-src", url);
|
|
2414
2495
|
}
|
|
2415
|
-
} catch (
|
|
2416
|
-
console.error(
|
|
2496
|
+
} catch (error) {
|
|
2497
|
+
console.error("Failed to set script content:", error, url);
|
|
2417
2498
|
}
|
|
2418
2499
|
dispatchLinkOrScriptLoad(originScript);
|
|
2419
|
-
}).catch((
|
|
2420
|
-
console.error(
|
|
2500
|
+
}).catch((error) => {
|
|
2501
|
+
console.error("Failed to load script resource:", error);
|
|
2421
2502
|
dispatchLinkOrScriptError(originScript);
|
|
2422
2503
|
});
|
|
2423
2504
|
return replaceScript;
|
|
2424
2505
|
}
|
|
2506
|
+
function processLinkElement(linkElement) {
|
|
2507
|
+
const rel = linkElement.getAttribute("rel");
|
|
2508
|
+
let href = linkElement.getAttribute("href");
|
|
2509
|
+
if (rel === "stylesheet" && href) {
|
|
2510
|
+
href = fillUpPath(href, location.origin);
|
|
2511
|
+
const replaceStyle = document.createElement("style");
|
|
2512
|
+
const styleInstance = new Style({
|
|
2513
|
+
code: "",
|
|
2514
|
+
fromHtml: false,
|
|
2515
|
+
url: href
|
|
2516
|
+
});
|
|
2517
|
+
getStyleSource(href, styleInstance, linkElement);
|
|
2518
|
+
return replaceStyle;
|
|
2519
|
+
}
|
|
2520
|
+
return linkElement;
|
|
2521
|
+
}
|
|
2522
|
+
function processScriptElement(scriptElement) {
|
|
2523
|
+
let src = scriptElement.getAttribute("src");
|
|
2524
|
+
if (src && scriptElement.type !== "module") {
|
|
2525
|
+
src = fillUpPath(src, location.origin);
|
|
2526
|
+
const script = new Script({
|
|
2527
|
+
async: scriptElement.hasAttribute("async"),
|
|
2528
|
+
code: "",
|
|
2529
|
+
defer: scriptElement.defer || scriptElement.type === "module",
|
|
2530
|
+
fromHtml: false,
|
|
2531
|
+
isModule: false
|
|
2532
|
+
});
|
|
2533
|
+
appCache.setBaseAppScript(src, script);
|
|
2534
|
+
const replaceElement = getScriptSource(src, script, scriptElement);
|
|
2535
|
+
return replaceElement || scriptElement;
|
|
2536
|
+
}
|
|
2537
|
+
return scriptElement;
|
|
2538
|
+
}
|
|
2425
2539
|
function createNewNode(child) {
|
|
2426
2540
|
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
|
-
}
|
|
2541
|
+
return processLinkElement(child);
|
|
2440
2542
|
}
|
|
2441
2543
|
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
|
-
}
|
|
2544
|
+
return processScriptElement(child);
|
|
2456
2545
|
}
|
|
2457
2546
|
return child;
|
|
2458
2547
|
}
|
|
2459
2548
|
function isLinkOrScript(node) {
|
|
2460
2549
|
return node instanceof HTMLLinkElement || node instanceof HTMLScriptElement;
|
|
2461
2550
|
}
|
|
2462
|
-
function baseElementInertHandle(parent, newChild,
|
|
2551
|
+
function baseElementInertHandle(parent, newChild, referenceChild, rawMethod) {
|
|
2463
2552
|
if (isLinkOrScript(newChild)) {
|
|
2464
2553
|
const targetChild = createNewNode(newChild);
|
|
2465
|
-
return rawMethod.call(parent, targetChild,
|
|
2554
|
+
return rawMethod.call(parent, targetChild, referenceChild);
|
|
2466
2555
|
}
|
|
2467
|
-
return rawMethod.call(parent, newChild,
|
|
2556
|
+
return rawMethod.call(parent, newChild, referenceChild);
|
|
2468
2557
|
}
|
|
2469
2558
|
function baseElementAppendHandle(parent, newChild, rawMethod) {
|
|
2470
2559
|
if (isLinkOrScript(newChild)) {
|
|
@@ -2475,10 +2564,15 @@ function baseElementAppendHandle(parent, newChild, rawMethod) {
|
|
|
2475
2564
|
}
|
|
2476
2565
|
|
|
2477
2566
|
// src/base-app/collect-source.ts
|
|
2478
|
-
function
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2567
|
+
function cacheOriginalDOMMethods() {
|
|
2568
|
+
return {
|
|
2569
|
+
rawBodyAppendChild: HTMLBodyElement.prototype.appendChild,
|
|
2570
|
+
rawHeadAppendChild: HTMLHeadElement.prototype.appendChild,
|
|
2571
|
+
rawHeadInsertBefore: HTMLHeadElement.prototype.insertBefore
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
function overrideDOMMethods(originalMethods) {
|
|
2575
|
+
const { rawBodyAppendChild, rawHeadAppendChild, rawHeadInsertBefore } = originalMethods;
|
|
2482
2576
|
HTMLBodyElement.prototype.appendChild = function(newChild) {
|
|
2483
2577
|
return baseElementAppendHandle(this, newChild, rawBodyAppendChild);
|
|
2484
2578
|
};
|
|
@@ -2488,22 +2582,39 @@ function collectBaseSource() {
|
|
|
2488
2582
|
HTMLHeadElement.prototype.insertBefore = function(newChild, refChild) {
|
|
2489
2583
|
return baseElementInertHandle(this, newChild, refChild, rawHeadInsertBefore);
|
|
2490
2584
|
};
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2585
|
+
}
|
|
2586
|
+
function collectExistingStyles() {
|
|
2587
|
+
const styleNodes = document.head.querySelectorAll("style");
|
|
2588
|
+
for (const styleNode of Array.from(styleNodes)) {
|
|
2589
|
+
const textContent = styleNode.textContent;
|
|
2590
|
+
if (textContent) {
|
|
2591
|
+
try {
|
|
2592
|
+
const style = new Style({
|
|
2593
|
+
code: textContent,
|
|
2498
2594
|
fromHtml: false,
|
|
2499
2595
|
url: ""
|
|
2500
|
-
})
|
|
2501
|
-
|
|
2596
|
+
});
|
|
2597
|
+
appCache.setBaseAppStyle(randomUrl(), style);
|
|
2598
|
+
} catch (error) {
|
|
2599
|
+
console.warn("Failed to collect style element:", error);
|
|
2600
|
+
}
|
|
2502
2601
|
}
|
|
2503
|
-
}
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
function setupLoadEventListener() {
|
|
2605
|
+
window.addEventListener("load", collectExistingStyles);
|
|
2606
|
+
}
|
|
2607
|
+
function collectBaseSource() {
|
|
2608
|
+
const originalMethods = cacheOriginalDOMMethods();
|
|
2609
|
+
overrideDOMMethods(originalMethods);
|
|
2610
|
+
setupLoadEventListener();
|
|
2504
2611
|
}
|
|
2505
2612
|
|
|
2506
2613
|
// src/context/element.ts
|
|
2614
|
+
var RESOURCE_ATTRIBUTES = ["src", "srcset"];
|
|
2615
|
+
var LINK_ATTRIBUTES = ["href"];
|
|
2616
|
+
var RESOURCE_TAG_NAMES = ["IMG", "SCRIPT"];
|
|
2617
|
+
var LINK_TAG_NAMES = ["LINK"];
|
|
2507
2618
|
var { setAttribute } = Element.prototype;
|
|
2508
2619
|
var {
|
|
2509
2620
|
append,
|
|
@@ -2518,47 +2629,84 @@ var {
|
|
|
2518
2629
|
} = HTMLHeadElement.prototype;
|
|
2519
2630
|
var rawHead = document.head;
|
|
2520
2631
|
var hasRewrite = false;
|
|
2521
|
-
function
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2632
|
+
function shouldProcessResourcePath(key, tagName) {
|
|
2633
|
+
const upperTagName = tagName.toUpperCase();
|
|
2634
|
+
return RESOURCE_ATTRIBUTES.includes(key) && RESOURCE_TAG_NAMES.includes(upperTagName) || LINK_ATTRIBUTES.includes(key) && LINK_TAG_NAMES.includes(upperTagName);
|
|
2635
|
+
}
|
|
2636
|
+
function getElementApp(element) {
|
|
2637
|
+
if (!element.__BK_WEWEB_APP_KEY__) {
|
|
2638
|
+
return null;
|
|
2639
|
+
}
|
|
2640
|
+
return appCache.getApp(element.__BK_WEWEB_APP_KEY__);
|
|
2641
|
+
}
|
|
2642
|
+
function createOverriddenSetAttribute() {
|
|
2643
|
+
return function(key, value) {
|
|
2644
|
+
const tagName = this.tagName.toUpperCase();
|
|
2645
|
+
if (shouldProcessResourcePath(key, tagName) && this.__BK_WEWEB_APP_KEY__) {
|
|
2646
|
+
const app = getElementApp(this);
|
|
2647
|
+
if (app) {
|
|
2648
|
+
setAttribute.call(this, key, fillUpPath(value, app.url));
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2530
2651
|
}
|
|
2652
|
+
setAttribute.call(this, key, value);
|
|
2531
2653
|
};
|
|
2532
|
-
|
|
2533
|
-
|
|
2654
|
+
}
|
|
2655
|
+
function handleKeepAliveElement(newChild) {
|
|
2656
|
+
if (newChild.__KEEP_ALIVE__ && isSpecialElement(newChild)) {
|
|
2657
|
+
return headAppendChild.call(rawHead, newChild);
|
|
2658
|
+
}
|
|
2659
|
+
return null;
|
|
2660
|
+
}
|
|
2661
|
+
function createOverriddenAppendChild() {
|
|
2662
|
+
return function(newChild) {
|
|
2663
|
+
const keepAliveResult = handleKeepAliveElement(newChild);
|
|
2664
|
+
if (keepAliveResult) {
|
|
2665
|
+
return keepAliveResult;
|
|
2666
|
+
}
|
|
2534
2667
|
return elementAppendHandler(this, newChild, bodyAppendChild2);
|
|
2535
2668
|
};
|
|
2536
|
-
|
|
2669
|
+
}
|
|
2670
|
+
function createOverriddenAppend() {
|
|
2671
|
+
return function(...nodes) {
|
|
2537
2672
|
nodes.forEach((node) => {
|
|
2538
|
-
|
|
2539
|
-
|
|
2673
|
+
const keepAliveResult = handleKeepAliveElement(node);
|
|
2674
|
+
if (keepAliveResult) {
|
|
2675
|
+
return;
|
|
2540
2676
|
}
|
|
2541
2677
|
elementAppendHandler(this, node, bodyAppendChild2);
|
|
2542
2678
|
});
|
|
2543
2679
|
};
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
};
|
|
2548
|
-
HTMLBodyElement.prototype.insertBefore = function(newChild, refChild) {
|
|
2680
|
+
}
|
|
2681
|
+
function createOverriddenInsertBefore() {
|
|
2682
|
+
return function(newChild, refChild) {
|
|
2549
2683
|
return elementInsertHandler(this, newChild, refChild, headInsertBefore);
|
|
2550
2684
|
};
|
|
2551
|
-
|
|
2552
|
-
|
|
2685
|
+
}
|
|
2686
|
+
function createOverriddenRemoveChild() {
|
|
2687
|
+
return function(oldChild) {
|
|
2688
|
+
const app = oldChild.__BK_WEWEB_APP_KEY__ ? appCache.getApp(oldChild.__BK_WEWEB_APP_KEY__) : null;
|
|
2553
2689
|
if (app?.container?.contains(oldChild)) {
|
|
2554
|
-
|
|
2555
|
-
return node;
|
|
2690
|
+
return bodyRemoveChild.call(app.container, oldChild);
|
|
2556
2691
|
}
|
|
2557
2692
|
if (this.contains(oldChild)) {
|
|
2558
2693
|
return bodyRemoveChild.call(this, oldChild);
|
|
2559
2694
|
}
|
|
2560
2695
|
return oldChild;
|
|
2561
2696
|
};
|
|
2697
|
+
}
|
|
2698
|
+
function rewriteBodyAndHeaderMethods() {
|
|
2699
|
+
if (hasRewrite) {
|
|
2700
|
+
return;
|
|
2701
|
+
}
|
|
2702
|
+
hasRewrite = true;
|
|
2703
|
+
Element.prototype.setAttribute = createOverriddenSetAttribute();
|
|
2704
|
+
HTMLBodyElement.prototype.appendChild = createOverriddenAppendChild();
|
|
2705
|
+
HTMLBodyElement.prototype.append = createOverriddenAppend();
|
|
2706
|
+
HTMLBodyElement.prototype.insertBefore = createOverriddenInsertBefore();
|
|
2707
|
+
HTMLBodyElement.prototype.removeChild = createOverriddenRemoveChild();
|
|
2708
|
+
HTMLHeadElement.prototype.appendChild = HTMLBodyElement.prototype.appendChild;
|
|
2709
|
+
HTMLHeadElement.prototype.insertBefore = createOverriddenInsertBefore();
|
|
2562
2710
|
HTMLHeadElement.prototype.removeChild = HTMLBodyElement.prototype.removeChild;
|
|
2563
2711
|
}
|
|
2564
2712
|
function resetBodyAndHeaderMethods() {
|
|
@@ -2587,8 +2735,8 @@ function activated(appKey, container, callback) {
|
|
|
2587
2735
|
beforeLoad();
|
|
2588
2736
|
app.activated(container, callback);
|
|
2589
2737
|
});
|
|
2590
|
-
} else {
|
|
2591
|
-
|
|
2738
|
+
} else if (app) {
|
|
2739
|
+
nextTask(() => {
|
|
2592
2740
|
beforeLoad();
|
|
2593
2741
|
app.mount(container, callback);
|
|
2594
2742
|
});
|
|
@@ -2607,9 +2755,12 @@ function deactivated(appKey) {
|
|
|
2607
2755
|
}
|
|
2608
2756
|
|
|
2609
2757
|
// src/lifecycle/load.ts
|
|
2758
|
+
var STATUS_CHECK_INTERVAL = 300;
|
|
2610
2759
|
async function load(props) {
|
|
2611
2760
|
beforeLoad();
|
|
2612
|
-
if (props.mode === "js" /* INSTANCE */)
|
|
2761
|
+
if (props.mode === "js" /* INSTANCE */) {
|
|
2762
|
+
return await loadInstance(props);
|
|
2763
|
+
}
|
|
2613
2764
|
return await loadApp(props);
|
|
2614
2765
|
}
|
|
2615
2766
|
async function loadApp(props) {
|
|
@@ -2638,7 +2789,7 @@ function loadInstance(props) {
|
|
|
2638
2789
|
resolve(instance);
|
|
2639
2790
|
clearInterval(timer);
|
|
2640
2791
|
}
|
|
2641
|
-
},
|
|
2792
|
+
}, STATUS_CHECK_INTERVAL);
|
|
2642
2793
|
return;
|
|
2643
2794
|
}
|
|
2644
2795
|
resolve(instance);
|
|
@@ -2658,14 +2809,35 @@ function unmount(appKey) {
|
|
|
2658
2809
|
|
|
2659
2810
|
// src/component/web-component.ts
|
|
2660
2811
|
var BkWewebElement = class extends HTMLElement {
|
|
2812
|
+
/** 应用 URL 缓存 */
|
|
2661
2813
|
appUrl = "";
|
|
2814
|
+
/** 组件连接状态标识 */
|
|
2662
2815
|
connected = false;
|
|
2816
|
+
/**
|
|
2817
|
+
* 观察的属性列表
|
|
2818
|
+
* @description 定义需要监听变化的属性名称列表
|
|
2819
|
+
* @returns string[] - 属性名称数组
|
|
2820
|
+
*/
|
|
2663
2821
|
static get observedAttributes() {
|
|
2664
2822
|
return ["url" /* url */];
|
|
2665
2823
|
}
|
|
2824
|
+
/**
|
|
2825
|
+
* 获取布尔类型属性值
|
|
2826
|
+
* @description 解析布尔类型的自定义属性,支持驼峰和短横线命名
|
|
2827
|
+
* @param name - 属性名称
|
|
2828
|
+
* @returns boolean | undefined - 属性值或 undefined
|
|
2829
|
+
* @private
|
|
2830
|
+
*/
|
|
2666
2831
|
getBooleanAttr(name) {
|
|
2667
|
-
|
|
2832
|
+
const hasAttr = this.hasAttribute(name) || this.hasAttribute(name.replace(/([A-Z])/g, "-$1").toLocaleLowerCase());
|
|
2833
|
+
return hasAttr ? this.getAttribute(name) !== "false" : void 0;
|
|
2668
2834
|
}
|
|
2835
|
+
/**
|
|
2836
|
+
* 处理属性变化的内部逻辑
|
|
2837
|
+
* @description 当属性发生变化时执行的处理逻辑
|
|
2838
|
+
* @returns Promise<void>
|
|
2839
|
+
* @private
|
|
2840
|
+
*/
|
|
2669
2841
|
async handleAttributeChanged() {
|
|
2670
2842
|
if (!this.appKey) return;
|
|
2671
2843
|
if (this.getBooleanAttr("setShodowDom" /* setShodowDom */)) {
|
|
@@ -2678,12 +2850,26 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2678
2850
|
}
|
|
2679
2851
|
await load(this.appProps);
|
|
2680
2852
|
}
|
|
2853
|
+
/**
|
|
2854
|
+
* 属性变化回调
|
|
2855
|
+
* @description 当观察的属性发生变化时触发
|
|
2856
|
+
* @param attr - 变化的属性名
|
|
2857
|
+
* @param _oldVal - 旧值(未使用)
|
|
2858
|
+
* @param newVal - 新值
|
|
2859
|
+
*/
|
|
2681
2860
|
attributeChangedCallback(attr, _oldVal, newVal) {
|
|
2682
2861
|
if (attr !== "url" /* url */ || this[attr] === newVal || !this.connected) return;
|
|
2683
2862
|
this.appUrl = newVal;
|
|
2684
2863
|
const cacheApp = appCache.getApp(this.appKey);
|
|
2685
|
-
(this.connected || cacheApp)
|
|
2864
|
+
if (this.connected || cacheApp) {
|
|
2865
|
+
this.handleAttributeChanged();
|
|
2866
|
+
}
|
|
2686
2867
|
}
|
|
2868
|
+
/**
|
|
2869
|
+
* 组件连接到 DOM 时的回调
|
|
2870
|
+
* @description 当自定义元素被插入到 DOM 时触发
|
|
2871
|
+
* @returns Promise<void>
|
|
2872
|
+
*/
|
|
2687
2873
|
async connectedCallback() {
|
|
2688
2874
|
if (this.getBooleanAttr("setShodowDom" /* setShodowDom */) && !this.shadowRoot) {
|
|
2689
2875
|
this.attachShadow({ delegatesFocus: false, mode: "open" });
|
|
@@ -2692,12 +2878,23 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2692
2878
|
activated(this.appKey, this.shadowRoot ?? this);
|
|
2693
2879
|
this.connected = true;
|
|
2694
2880
|
}
|
|
2881
|
+
/**
|
|
2882
|
+
* 组件从 DOM 断开时的回调
|
|
2883
|
+
* @description 当自定义元素从 DOM 中移除时触发
|
|
2884
|
+
*/
|
|
2695
2885
|
disconnectedCallback() {
|
|
2696
2886
|
this.connected = false;
|
|
2697
2887
|
if (this.appProps.keepAlive) {
|
|
2698
2888
|
deactivated(this.appKey);
|
|
2699
|
-
} else
|
|
2889
|
+
} else {
|
|
2890
|
+
unmount(this.appKey);
|
|
2891
|
+
}
|
|
2700
2892
|
}
|
|
2893
|
+
/**
|
|
2894
|
+
* 获取应用数据
|
|
2895
|
+
* @description 解析 data 属性中的 JSON 数据
|
|
2896
|
+
* @returns Record<string, unknown> - 应用数据对象
|
|
2897
|
+
*/
|
|
2701
2898
|
get appData() {
|
|
2702
2899
|
if (this.hasAttribute("data" /* data */)) {
|
|
2703
2900
|
try {
|
|
@@ -2707,35 +2904,44 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2707
2904
|
}
|
|
2708
2905
|
return {};
|
|
2709
2906
|
}
|
|
2710
|
-
|
|
2907
|
+
/**
|
|
2908
|
+
* 获取应用标识符
|
|
2909
|
+
* @description 优先使用 id 属性,其次使用 url 属性作为应用标识
|
|
2910
|
+
* 考虑到 JS 模式下需要 JS bundle 的复用性,需用户设置 id 属性
|
|
2911
|
+
* 如果是单实例应用则可以不用配置 id
|
|
2912
|
+
* @returns string | null - 应用标识符或 null
|
|
2913
|
+
*/
|
|
2711
2914
|
get appKey() {
|
|
2712
2915
|
return this.getAttribute("id" /* id */) || this.getAttribute("url" /* url */);
|
|
2713
2916
|
}
|
|
2917
|
+
/**
|
|
2918
|
+
* 获取应用配置属性
|
|
2919
|
+
* @description 根据模式返回相应的应用配置对象
|
|
2920
|
+
* @returns IAppModelProps | IJsModelProps - 应用配置对象
|
|
2921
|
+
*/
|
|
2714
2922
|
get appProps() {
|
|
2923
|
+
const commonProps = {
|
|
2924
|
+
container: this.shadowRoot ?? this,
|
|
2925
|
+
data: this.appData,
|
|
2926
|
+
id: this.appKey,
|
|
2927
|
+
keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
|
|
2928
|
+
showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
|
|
2929
|
+
url: this.getAttribute("url" /* url */)
|
|
2930
|
+
};
|
|
2715
2931
|
if (this.getAttribute("mode") === "js" /* INSTANCE */) {
|
|
2716
2932
|
return {
|
|
2717
|
-
|
|
2718
|
-
data: this.appData,
|
|
2719
|
-
id: this.appKey,
|
|
2720
|
-
keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
|
|
2933
|
+
...commonProps,
|
|
2721
2934
|
mode: "js" /* INSTANCE */,
|
|
2722
2935
|
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 */)
|
|
2936
|
+
scopeJs: this.getBooleanAttr("scopeJs" /* scopeJs */)
|
|
2726
2937
|
};
|
|
2727
2938
|
}
|
|
2728
2939
|
return {
|
|
2729
|
-
|
|
2730
|
-
data: this.appData,
|
|
2731
|
-
id: this.appKey,
|
|
2732
|
-
keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
|
|
2940
|
+
...commonProps,
|
|
2733
2941
|
mode: "app" /* APP */,
|
|
2734
2942
|
scopeCss: !this.getBooleanAttr("setShodowDom" /* setShodowDom */),
|
|
2735
2943
|
scopeJs: !this.getBooleanAttr("scopeJs" /* scopeJs */),
|
|
2736
|
-
scopeLocation: this.getBooleanAttr("scopeLocation" /* scopeLocation */)
|
|
2737
|
-
showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
|
|
2738
|
-
url: this.getAttribute("url" /* url */)
|
|
2944
|
+
scopeLocation: this.getBooleanAttr("scopeLocation" /* scopeLocation */)
|
|
2739
2945
|
};
|
|
2740
2946
|
}
|
|
2741
2947
|
};
|
|
@@ -2743,10 +2949,12 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2743
2949
|
// src/lifecycle/mount.ts
|
|
2744
2950
|
function mount(appKey, container, callback) {
|
|
2745
2951
|
const app = appCache.getApp(appKey);
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2952
|
+
if (app) {
|
|
2953
|
+
nextTask(() => {
|
|
2954
|
+
beforeLoad();
|
|
2955
|
+
app.mount(container, callback);
|
|
2956
|
+
});
|
|
2957
|
+
}
|
|
2750
2958
|
}
|
|
2751
2959
|
|
|
2752
2960
|
// src/lifecycle/unload.ts
|
|
@@ -2787,13 +2995,13 @@ var WeWeb = class {
|
|
|
2787
2995
|
window.customElements.define(CUSTOM_ELEMENT_TAG, BkWewebElement);
|
|
2788
2996
|
}
|
|
2789
2997
|
}
|
|
2790
|
-
|
|
2998
|
+
/** 设置自定义DOM标签名 */
|
|
2791
2999
|
setWebComponentTag() {
|
|
2792
3000
|
if (!window.customElements.get(this.webComponentTag)) {
|
|
2793
3001
|
window.customElements.define(this.webComponentTag, BkWewebElement);
|
|
2794
3002
|
}
|
|
2795
3003
|
}
|
|
2796
|
-
|
|
3004
|
+
/** 启动WeWeb */
|
|
2797
3005
|
start(option) {
|
|
2798
3006
|
if (option?.collectBaseSource) {
|
|
2799
3007
|
collectBaseSource();
|