@blueking/bk-weweb 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/collect-source.js +2139 -0
  2. package/dist/collect-source.js.map +1 -0
  3. package/dist/index.esm.js +2106 -0
  4. package/dist/index.esm.js.map +1 -0
  5. package/dist/index.min.js +2 -0
  6. package/dist/index.min.js.map +1 -0
  7. package/dist/index.umd.js +2 -0
  8. package/dist/index.umd.js.map +1 -0
  9. package/package.json +82 -0
  10. package/readme.md +33 -0
  11. package/typings/base-app/base-element.d.ts +6 -0
  12. package/typings/base-app/collect-source.d.ts +1 -0
  13. package/typings/cache/app-cache.d.ts +19 -0
  14. package/typings/common/index.d.ts +1 -0
  15. package/typings/common/state.d.ts +11 -0
  16. package/typings/component/web-compnent.d.ts +26 -0
  17. package/typings/context/document.d.ts +2 -0
  18. package/typings/context/element.d.ts +2 -0
  19. package/typings/context/function.d.ts +1 -0
  20. package/typings/context/memory.d.ts +10 -0
  21. package/typings/context/sandbox.d.ts +17 -0
  22. package/typings/context/window.d.ts +9 -0
  23. package/typings/entry/entry.d.ts +28 -0
  24. package/typings/entry/script.d.ts +22 -0
  25. package/typings/entry/style.d.ts +22 -0
  26. package/typings/index.d.ts +19 -0
  27. package/typings/lifecircle/activated.d.ts +2 -0
  28. package/typings/lifecircle/before-load.d.ts +1 -0
  29. package/typings/lifecircle/deactivated.d.ts +1 -0
  30. package/typings/lifecircle/load.d.ts +6 -0
  31. package/typings/lifecircle/mount.d.ts +2 -0
  32. package/typings/lifecircle/unload.d.ts +1 -0
  33. package/typings/lifecircle/unmount.d.ts +1 -0
  34. package/typings/mode/app.d.ts +37 -0
  35. package/typings/mode/instance.d.ts +32 -0
  36. package/typings/preload/preload.d.ts +5 -0
  37. package/typings/typings/global.d.ts +17 -0
  38. package/typings/typings/index.d.ts +10 -0
  39. package/typings/typings/model.d.ts +64 -0
  40. package/typings/typings/sandbox.d.ts +18 -0
  41. package/typings/typings/source.d.ts +23 -0
  42. package/typings/utils/common.d.ts +18 -0
  43. package/typings/utils/element-event.d.ts +2 -0
  44. package/typings/utils/element.d.ts +6 -0
  45. package/typings/utils/fetch.d.ts +1 -0
  46. package/typings/utils/index.d.ts +4 -0
  47. package/typings/utils/load-source.d.ts +12 -0
@@ -0,0 +1,2139 @@
1
+ // app status
2
+ var AppState;
3
+ (function (AppState) {
4
+ AppState["UNSET"] = "UNSET";
5
+ AppState["LOADING"] = "LOADING";
6
+ AppState["LOADED"] = "LOADED";
7
+ AppState["ERROR"] = "ERROR";
8
+ AppState["MOUNTING"] = "MOUNTING";
9
+ AppState["MOUNTED"] = "MOUNTED";
10
+ AppState["ACTIVATED"] = "ACTIVATED";
11
+ AppState["DEACTIVATED"] = "DEACTIVATED";
12
+ AppState["UNMOUNT"] = "UNMOUNT";
13
+ })(AppState || (AppState = {}));
14
+
15
+ // is function
16
+ function isFunction(target) {
17
+ return typeof target === 'function';
18
+ }
19
+ // Promise.then might be synchronized in Zone.js context, we need to use setTimeout instead to mock next tick.
20
+ const nextTask = typeof window.Zone === 'function' ? setTimeout : cb => Promise.resolve().then(cb);
21
+ function addUrlProtocol(url) {
22
+ return url.startsWith('//') ? `${location.protocol}${url}` : url;
23
+ }
24
+ // Get valid address, such as https://xxx/xx/xx.html to https://xxx/xx/
25
+ function getUrlDir(url) {
26
+ const { origin, pathname } = new URL(url);
27
+ if (/\.(\w+)$/.test(pathname)) {
28
+ const fullPath = `${origin}${pathname}`;
29
+ const pathArr = fullPath.split('/');
30
+ pathArr.pop();
31
+ return `${pathArr.join('/')}/`;
32
+ }
33
+ return `${origin}${pathname}/`.replace(/\/\/$/, '/');
34
+ }
35
+ // 补齐url地址
36
+ function fillUpPath(path, baseURI) {
37
+ if (!path || /^((((ht|f)tps?)|file):)?\/\//.test(path) || /^(data|blob):/.test(path))
38
+ return path;
39
+ return new URL(path, getUrlDir(addUrlProtocol(baseURI))).toString();
40
+ }
41
+ // 获取url目录
42
+ function getFileDir(linkpath) {
43
+ const pathArr = linkpath.split('/');
44
+ pathArr.pop();
45
+ return addUrlProtocol(`${pathArr.join('/')}/`);
46
+ }
47
+ // is ie11
48
+ const isIE11 = typeof navigator !== 'undefined' && navigator.userAgent.indexOf('Trident') !== -1;
49
+ // 随机url
50
+ function randomUrl() {
51
+ return `inline-${random(16)}`;
52
+ }
53
+ // Array deduplication
54
+ function arrayUnique(array) {
55
+ return Array.from(new Set(array));
56
+ }
57
+ // is safari browser
58
+ function isSafari() {
59
+ return /Safari/.test(navigator.userAgent);
60
+ }
61
+ // Create pure elements
62
+ function createElement$1(tagName, options) {
63
+ const element = document.createElement(tagName, options);
64
+ if (element.__BK_WEWEB_APP_KEY__)
65
+ delete element.__BK_WEWEB_APP_KEY__;
66
+ return element;
67
+ }
68
+ // bodyle element
69
+ function isBodyElement(key) {
70
+ return /^(body|head|html)$/i.test(key);
71
+ }
72
+ // create random string
73
+ const random = (n, str = 'abcdefghijklmnopqrstuvwxyz0123456789') => {
74
+ // 生成n位长度的字符串
75
+ let result = '';
76
+ for (let i = 0; i < n; i++) {
77
+ result += str[parseInt((Math.random() * str.length).toString(), 10)];
78
+ }
79
+ return result;
80
+ };
81
+
82
+ let currentRunningApp = null;
83
+ function getCurrentRunningApp() {
84
+ return currentRunningApp;
85
+ }
86
+ function setCurrentRunningApp(appInstance) {
87
+ currentRunningApp = appInstance;
88
+ }
89
+ const documentClickListMap = new Map();
90
+ const documentEventListenerMap = new Map();
91
+ const script = document.createElement('script');
92
+ const isSupportModuleScript = 'noModule' in script;
93
+ const SCOPED_CSS_STYLE_ID = 'SCOPED_CSS_STYLE_ID';
94
+ const templateStyle = document.createElement('style');
95
+ templateStyle.setAttribute('id', SCOPED_CSS_STYLE_ID);
96
+ document.body.appendChild(templateStyle);
97
+ templateStyle.sheet.disabled = true;
98
+ const disabledStyleDom = templateStyle;
99
+
100
+ const { document: document$1 } = window;
101
+ const { createElement, querySelector, querySelectorAll, getElementById, getElementsByClassName, getElementsByTagName, getElementsByName, } = Document.prototype;
102
+ function rewriteDocumentPrototypeMethods() {
103
+ Document.prototype.createElement = function (tagName, options) {
104
+ const element = createElement.call(this, tagName, options);
105
+ const app = getCurrentRunningApp();
106
+ // img.src = '' iframe.src = '' 均不能在setAttributes上监听 但是这里所有的src都是 全地址 无法判断是否需要添加子应用域名
107
+ // if (tagName.toLocaleLowerCase() === 'img') {
108
+ // const observer = new MutationObserver((list, observer) => {
109
+ // observer.disconnect();
110
+ // const url = new URL((element as HTMLImageElement).src)
111
+ // (element as HTMLImageElement).src = `${}`
112
+ // });
113
+ // observer.observe(element, { attributeFilter: ['src'], subtree: false, childList: false });
114
+ // }
115
+ if (app)
116
+ element.__BK_WEWEB_APP_KEY__ = app.appCacheKey;
117
+ return element;
118
+ };
119
+ function querySelectorNew(selectors) {
120
+ const app = getCurrentRunningApp();
121
+ if (!app || !selectors || isBodyElement(selectors) || document$1 !== this) {
122
+ return querySelector.call(this, selectors);
123
+ }
124
+ return app?.container?.querySelector(selectors) ?? null;
125
+ }
126
+ function querySelectorAllNew(selectors) {
127
+ const app = getCurrentRunningApp();
128
+ if (!app || !selectors || isBodyElement(selectors) || document$1 !== this) {
129
+ return querySelectorAll.call(this, selectors);
130
+ }
131
+ return app?.container?.querySelectorAll(selectors) ?? [];
132
+ }
133
+ Document.prototype.querySelector = querySelectorNew;
134
+ Document.prototype.querySelectorAll = querySelectorAllNew;
135
+ Document.prototype.getElementById = function getElementByIdNew(key) {
136
+ if (!getCurrentRunningApp()) {
137
+ return getElementById.call(this, key);
138
+ }
139
+ try {
140
+ return querySelectorNew.call(this, `#${key}`);
141
+ }
142
+ catch {
143
+ return getElementById.call(this, key);
144
+ }
145
+ };
146
+ Document.prototype.getElementsByClassName = function (key) {
147
+ if (!getCurrentRunningApp()) {
148
+ return getElementsByClassName.call(this, key);
149
+ }
150
+ try {
151
+ return querySelectorAllNew.call(this, `.${key}`);
152
+ }
153
+ catch {
154
+ return getElementsByClassName.call(this, key);
155
+ }
156
+ };
157
+ // eslint-disable-next-line max-len
158
+ Document.prototype.getElementsByTagName = function (key) {
159
+ const app = getCurrentRunningApp();
160
+ if (!app
161
+ || isBodyElement(key)
162
+ || (!app?.showSourceCode && key.toLocaleLowerCase() === 'script')) {
163
+ return getElementsByTagName.call(this, key);
164
+ }
165
+ try {
166
+ return querySelectorAllNew.call(this, key);
167
+ }
168
+ catch {
169
+ return getElementsByTagName.call(this, key);
170
+ }
171
+ };
172
+ Document.prototype.getElementsByName = function (key) {
173
+ if (!getCurrentRunningApp()) {
174
+ return getElementsByName.call(this, key);
175
+ }
176
+ try {
177
+ return querySelectorAllNew.call(this, `[name=${key}]`);
178
+ }
179
+ catch {
180
+ return getElementsByName.call(this, key);
181
+ }
182
+ };
183
+ }
184
+ function resetDocumentPrototypeMethods() {
185
+ Document.prototype.createElement = createElement;
186
+ Document.prototype.querySelector = querySelector;
187
+ Document.prototype.querySelectorAll = querySelectorAll;
188
+ Document.prototype.getElementById = getElementById;
189
+ Document.prototype.getElementsByClassName = getElementsByClassName;
190
+ Document.prototype.getElementsByTagName = getElementsByTagName;
191
+ Document.prototype.getElementsByName = getElementsByName;
192
+ }
193
+
194
+ const CSS_ATTRIBUTE_KEY = 'id';
195
+ var CSS_RULE_TYPE;
196
+ (function (CSS_RULE_TYPE) {
197
+ CSS_RULE_TYPE[CSS_RULE_TYPE["STYLE_RULE"] = 1] = "STYLE_RULE";
198
+ CSS_RULE_TYPE[CSS_RULE_TYPE["MEDIA_RULE"] = 4] = "MEDIA_RULE";
199
+ CSS_RULE_TYPE[CSS_RULE_TYPE["SUPPORTS_RULE"] = 12] = "SUPPORTS_RULE";
200
+ })(CSS_RULE_TYPE || (CSS_RULE_TYPE = {}));
201
+
202
+ const commonEScapeKeyList = ['System', '__cjsWrapper', '__REACT_ERROR_OVERLAY_GLOBAL_HOOK__'];
203
+ // 共享主应用上下文属性名
204
+ const escapeSetterKeyList = ['location'];
205
+ // 一定需要在子应用自身上下文获取的属性名
206
+ const scopeWindowKeyList = ['webpackJsonp', '__POWERED_BY_BK_WEWEB__', '__BK_WEWEB_APP_KEY__', '__BK_WEWEB_DATA__'];
207
+ // 设置了scopedLocation 后需要监听属性名
208
+ const scopedLocationKeyList = ['location', 'history'];
209
+ var DescriptorMapValue;
210
+ (function (DescriptorMapValue) {
211
+ DescriptorMapValue["TARGET"] = "TARGET";
212
+ DescriptorMapValue["WINDOW"] = "WINDOW";
213
+ })(DescriptorMapValue || (DescriptorMapValue = {}));
214
+ const commonRawWindowKeyMap = {
215
+ undefined: true,
216
+ Array: true,
217
+ Object: true,
218
+ String: true,
219
+ Boolean: true,
220
+ Math: true,
221
+ Reflect: true,
222
+ Function: true,
223
+ Number: true,
224
+ Symbol: true,
225
+ parseFloat: true,
226
+ parseInt: true,
227
+ Float32Array: true,
228
+ Set: true,
229
+ Infinity: true,
230
+ navigator: true,
231
+ devicePixelRatio: true,
232
+ Promise: true,
233
+ HTMLElement: true,
234
+ Map: true,
235
+ Element: true,
236
+ performance: true,
237
+ console: true,
238
+ isFinite: true,
239
+ RegExp: true,
240
+ JSON: true,
241
+ Date: true,
242
+ Proxy: true,
243
+ isNaN: true,
244
+ WeakMap: true,
245
+ WeakSet: true,
246
+ Uint8Array: true,
247
+ // btoa: true,
248
+ // unescape: true,
249
+ // WebSocket: true,
250
+ // encodeURIComponent: true,
251
+ // decodeURIComponent: true,
252
+ // ArrayBuffer: true,
253
+ // XMLHttpRequest: true,
254
+ // SVGElement: true,
255
+ // URLSearchParams: true,
256
+ // URL: true,
257
+ // RangeError: true,
258
+ // TypeError: true,
259
+ // Uint16Array: true,
260
+ // Uint32Array: true,
261
+ // Float64Array: true,
262
+ // Int32Array: true,
263
+ // requestAnimationFrame: true,
264
+ // SVGRect: true,
265
+ // Error: true,
266
+ // Buffer: true,
267
+ // SyntaxError: true,
268
+ // DataView: true,
269
+ // Worker: true,
270
+ // localStorage: true,
271
+ // Text: true,
272
+ // FormData: true,
273
+ // ShadowRoot: true,
274
+ // encodeURI: true,
275
+ // crypto: true,
276
+ // HTMLAnchorElement: true,
277
+ // Int8Array: true,
278
+ // FinalizationRegistry: true,
279
+ // BigInt: true,
280
+ // Atomics: true,
281
+ // Uint8ClampedArray: true,
282
+ // WeakRef: true,
283
+ // getComputedStyle,
284
+ // innerHeight: true,
285
+ // innerWidth: true,
286
+ // getComputedStyle: true,
287
+ };
288
+ const commonFakeWindowKeyMap = {
289
+ __VUE_OPTIONS_API__: true,
290
+ __VUE_I18N_LEGACY_API__: true,
291
+ __VUE_I18N_FULL_INSTALL__: true,
292
+ __VUE_DEVTOOLS_GLOBAL_HOOK__: true,
293
+ __VUE_DEVTOOLS_HOOK_REPLAY__: true,
294
+ __VUE_DEVTOOLS_PLUGINS__: true,
295
+ __DEV__: true,
296
+ webpackChunktrace: true,
297
+ i18n: true,
298
+ '__core-js_shared__': true,
299
+ };
300
+
301
+ function eventHandler(event, element) {
302
+ Object.defineProperties(event, {
303
+ currentTarget: {
304
+ get() {
305
+ return element;
306
+ },
307
+ },
308
+ srcElement: {
309
+ get() {
310
+ return element;
311
+ },
312
+ },
313
+ target: {
314
+ get() {
315
+ return element;
316
+ },
317
+ },
318
+ });
319
+ }
320
+ function dispatchLinkOrScriptLoad(element) {
321
+ const event = new CustomEvent('load');
322
+ eventHandler(event, element);
323
+ if (isFunction(element.onload)) {
324
+ element.onload(event);
325
+ }
326
+ else {
327
+ element.dispatchEvent(event);
328
+ }
329
+ }
330
+ function dispatchLinkOrScriptError(element) {
331
+ const event = new CustomEvent('error');
332
+ eventHandler(event, element);
333
+ if (isFunction(element.onerror)) {
334
+ element.onerror(event);
335
+ }
336
+ else {
337
+ element.dispatchEvent(event);
338
+ }
339
+ }
340
+
341
+ /* eslint-disable no-param-reassign */
342
+ class Style {
343
+ scopedCode = '';
344
+ code = '';
345
+ prefetch = false;
346
+ preload = false;
347
+ url;
348
+ scoped;
349
+ fromHtml;
350
+ initial;
351
+ constructor({ code, prefetch, preload, url, fromHtml, initial }) {
352
+ this.scoped = false;
353
+ this.code = code;
354
+ this.prefetch = prefetch ?? false;
355
+ this.preload = preload ?? false;
356
+ this.url = url;
357
+ this.fromHtml = fromHtml;
358
+ this.initial = initial ?? false;
359
+ }
360
+ async getCode(app) {
361
+ if (this.code.length || !this.url) {
362
+ return this.code;
363
+ }
364
+ let code = '';
365
+ if (app?.source?.styles?.has(this.url)) {
366
+ code = app.source.styles.get(this.url)?.code || '';
367
+ }
368
+ if (!code && appCache.getCacheStyle(this.url)) {
369
+ const style = appCache.getCacheStyle(this.url);
370
+ code = style?.code || '';
371
+ }
372
+ if (!code) {
373
+ code = await fetchSource(this.url).catch(() => '');
374
+ }
375
+ this.code = code;
376
+ return code;
377
+ }
378
+ async excuteCode(app) {
379
+ app.registerRunningApp();
380
+ let styleElement = createElement$1('style');
381
+ styleElement.setAttribute('type', 'text/css');
382
+ styleElement.textContent = this.code;
383
+ try {
384
+ if (!this.code)
385
+ await this.getCode(app);
386
+ styleElement = this.scopedStyleCSS(app, styleElement);
387
+ this.scoped = true;
388
+ }
389
+ catch (e) {
390
+ console.error('scoped style error', e);
391
+ }
392
+ return styleElement;
393
+ }
394
+ scopedStyleCSS(app, styleElement) {
395
+ const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
396
+ setMarkElement(styleElement, app, needKeepAlive);
397
+ if (this.code || styleElement.textContent) {
398
+ if (styleElement.textContent) {
399
+ styleElement.textContent = '';
400
+ styleElement.innerHTML = '';
401
+ }
402
+ disabledStyleDom.textContent = this.code;
403
+ this.commonScoped(disabledStyleDom, styleElement, app);
404
+ disabledStyleDom.textContent = '';
405
+ }
406
+ else {
407
+ const observer = new MutationObserver(() => {
408
+ if (!(styleElement.textContent || styleElement.sheet?.cssRules?.length))
409
+ return;
410
+ observer.disconnect();
411
+ this.commonScoped(styleElement, styleElement, app);
412
+ });
413
+ observer.observe(styleElement, { attributes: false, childList: true, subtree: true, characterData: true });
414
+ }
415
+ this.url && styleElement.setAttribute('origin-src', this.url);
416
+ return styleElement;
417
+ }
418
+ scopedLinkCSS(app, linkElement) {
419
+ const styleElement = createElement$1('style');
420
+ styleElement.setAttribute('type', 'text/css');
421
+ const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
422
+ setMarkElement(styleElement, app, needKeepAlive);
423
+ const container = needKeepAlive ? document.head : app.container;
424
+ try {
425
+ if (this.code) {
426
+ disabledStyleDom.textContent = styleElement.textContent || this.code;
427
+ this.commonScoped(disabledStyleDom, styleElement, app);
428
+ container?.prepend(styleElement);
429
+ linkElement && dispatchLinkOrScriptLoad(linkElement);
430
+ disabledStyleDom.textContent = '';
431
+ }
432
+ else if (linkElement.getAttribute('href')) {
433
+ this.url = fillUpPath(linkElement.getAttribute('href'), app.url);
434
+ this.getCode(app).then(() => {
435
+ this.scopedStyleCSS(app, styleElement);
436
+ linkElement.remove();
437
+ container?.prepend(styleElement);
438
+ linkElement && dispatchLinkOrScriptLoad(linkElement);
439
+ this.scoped = true;
440
+ });
441
+ }
442
+ else {
443
+ const observer = new MutationObserver(() => {
444
+ if (!linkElement.href)
445
+ return;
446
+ observer.disconnect();
447
+ this.url = fillUpPath(linkElement.getAttribute('href'), app.url);
448
+ this.getCode(app).then(() => {
449
+ this.scopedStyleCSS(app, styleElement);
450
+ linkElement.remove();
451
+ container?.prepend(styleElement);
452
+ linkElement && dispatchLinkOrScriptLoad(linkElement);
453
+ this.scoped = true;
454
+ });
455
+ });
456
+ observer.observe(linkElement, { attributeFilter: ['href'], subtree: false, childList: false });
457
+ }
458
+ }
459
+ catch {
460
+ linkElement && dispatchLinkOrScriptError(linkElement);
461
+ }
462
+ return styleElement;
463
+ }
464
+ commonScoped(templateStyle, styleElement, app) {
465
+ if (app.scopeCss && !(app.container instanceof ShadowRoot)) {
466
+ const rules = Array.from(templateStyle.sheet?.cssRules ?? []);
467
+ const cssPrefix = `#${app.name}`;
468
+ const scopedCss = this.scopeRule(rules, cssPrefix);
469
+ let cssText = this.resetUrlHost(scopedCss, app.url, this.url);
470
+ if (isSafari()) {
471
+ cssText = cssText.replace(/([;{]\s*content:\s*)([^\s"][^";}]*)/gm, (all, $1, $2) => {
472
+ if ($2 === 'none' || /^(url\()|(counter\()|(attr\()|(open-quote)|(close-quote)/.test($2)) {
473
+ return all;
474
+ }
475
+ return `${$1}"${$2}"`;
476
+ });
477
+ }
478
+ styleElement.textContent = cssText;
479
+ this.scopedCode = cssText;
480
+ }
481
+ else {
482
+ const cssText = this.resetUrlHost(styleElement.textContent || templateStyle.textContent || '', app.url, this.url);
483
+ styleElement.textContent = cssText;
484
+ }
485
+ this.scoped = true;
486
+ }
487
+ scopeRule(rules, cssPrefix) {
488
+ let result = '';
489
+ for (const rule of rules) {
490
+ switch (rule.type) {
491
+ case CSS_RULE_TYPE.STYLE_RULE:
492
+ result += this.scopeStyleRule(rule, cssPrefix);
493
+ break;
494
+ case CSS_RULE_TYPE.MEDIA_RULE:
495
+ result += this.resetPackRule(rule, cssPrefix, 'media');
496
+ break;
497
+ case CSS_RULE_TYPE.SUPPORTS_RULE:
498
+ result += this.resetPackRule(rule, cssPrefix, 'supports');
499
+ break;
500
+ default:
501
+ result += rule.cssText;
502
+ break;
503
+ }
504
+ }
505
+ return result.replace(/^\s+/, '');
506
+ }
507
+ resetPackRule(rule, prefix, packName) {
508
+ const result = this.scopeRule(Array.from(rule.cssRules), prefix);
509
+ return `@${packName} ${rule.conditionText} {${result}}`;
510
+ }
511
+ resetUrlHost(cssText, baseURI, linkpath) {
512
+ return cssText.replace(/url\(["']?([^)"']+)["']?\)/gm, (text, $1) => {
513
+ if (/^(data|blob):/.test($1) || /^(https?:)?\/\//.test($1)) {
514
+ return text;
515
+ }
516
+ if (/^((\.\.?\/)|[^/])/.test($1) && linkpath) {
517
+ baseURI = getFileDir(linkpath);
518
+ }
519
+ return `url("${fillUpPath($1, baseURI)}")`;
520
+ });
521
+ }
522
+ scopeStyleRule(rule, prefix) {
523
+ const { selectorText, cssText } = rule;
524
+ if (/^((html[\s>~,]+body)|(html|body|:root))$/.test(selectorText)) {
525
+ return cssText.replace(/^((html[\s>~,]+body)|(html|body|:root))/, prefix);
526
+ }
527
+ if (selectorText === '*') {
528
+ return cssText.replace('*', `${prefix} *`);
529
+ }
530
+ const builtInRootSelectorRE = /(^|\s+)((html[\s>~]+body)|(html|body|:root))(?=[\s>~]+|$)/;
531
+ return cssText.replace(/^[\s\S]+{/, selectors => selectors.replace(/(^|,)([^,]+)/g, (all, $1, $2) => {
532
+ if (builtInRootSelectorRE.test($2)) {
533
+ return all.replace(builtInRootSelectorRE, prefix);
534
+ }
535
+ return `${$1} ${prefix} ${$2.replace(/^\s*/, '')}`;
536
+ }));
537
+ }
538
+ }
539
+ async function excuteAppStyles(app, container) {
540
+ const styleList = Array.from(app.source.styles.values());
541
+ const promiseList = [];
542
+ styleList.forEach((style) => {
543
+ promiseList.push(style.excuteCode(app));
544
+ });
545
+ await Promise.all(promiseList).then((styleElementList) => {
546
+ const parentElemnt = container || app.container;
547
+ if (app.keepAlive && !(parentElemnt instanceof ShadowRoot)) {
548
+ document.head.append(...styleElementList);
549
+ }
550
+ else {
551
+ parentElemnt?.prepend(...styleElementList);
552
+ }
553
+ });
554
+ }
555
+
556
+ const { appendChild: bodyAppendChild$1 } = HTMLBodyElement.prototype;
557
+ function resetNewElement(parent, child, app) {
558
+ if (child instanceof HTMLStyleElement) {
559
+ if (child.hasAttribute('exclude')) {
560
+ return document.createComment('【bk-weweb】style with exclude attribute is ignored');
561
+ }
562
+ if (!child.hasAttribute('ignore')) {
563
+ const styleInstance = new Style({
564
+ code: child.textContent || '',
565
+ url: '',
566
+ fromHtml: false,
567
+ });
568
+ app.source?.setStyle(randomUrl(), styleInstance);
569
+ styleInstance.scopedStyleCSS(app, child);
570
+ }
571
+ return child;
572
+ }
573
+ if (child instanceof HTMLLinkElement) {
574
+ const result = app.source?.collectLink(child, parent, true);
575
+ if (!result)
576
+ return child;
577
+ if (result.style) {
578
+ result.style.scopedLinkCSS(app, child);
579
+ }
580
+ if (result.replace !== child) {
581
+ return result.replace;
582
+ }
583
+ return child;
584
+ }
585
+ if (child instanceof HTMLScriptElement) {
586
+ const replaceInfo = app.source.collectScript(child, parent, true);
587
+ if (!replaceInfo) {
588
+ return child;
589
+ }
590
+ if (replaceInfo.script) {
591
+ replaceInfo.script.excuteCode(app);
592
+ }
593
+ if (replaceInfo.replace !== child) {
594
+ return replaceInfo.replace;
595
+ }
596
+ if (app.scopeJs && !child.getAttribute('src') && !child.textContent) {
597
+ const observer = new MutationObserver(() => {
598
+ if (child.getAttribute('src')) {
599
+ observer.disconnect();
600
+ const scriptInfo = app.source.collectScript(child, parent, true);
601
+ if (scriptInfo?.replace) {
602
+ bodyAppendChild$1.call(app.container, scriptInfo.replace);
603
+ }
604
+ if (scriptInfo?.script) {
605
+ scriptInfo.script.excuteCode(app);
606
+ }
607
+ child.remove();
608
+ }
609
+ else if (child.textContent) {
610
+ observer.disconnect();
611
+ const scriptInstance = new Script({
612
+ code: child.textContent,
613
+ async: false,
614
+ defer: child.type === 'module',
615
+ isModule: child.type === 'module',
616
+ fromHtml: false,
617
+ });
618
+ app.source.scripts.set(randomUrl(), scriptInstance);
619
+ try {
620
+ scriptInstance.excuteCode(app);
621
+ }
622
+ catch (e) {
623
+ console.error(e);
624
+ }
625
+ finally {
626
+ !scriptInstance.isModule && dispatchLinkOrScriptLoad(child);
627
+ child.remove();
628
+ }
629
+ }
630
+ });
631
+ observer.observe(child, { attributeFilter: ['src'], childList: true, subtree: false });
632
+ return document.createComment('【bk-weweb】dynamic script or module');
633
+ }
634
+ return child;
635
+ }
636
+ return child;
637
+ }
638
+ function isSepcailElement(node) {
639
+ return node instanceof HTMLScriptElement
640
+ || node instanceof HTMLStyleElement
641
+ || node instanceof HTMLLinkElement;
642
+ }
643
+ function elmentAppendHandler(parent, newChild, rawMethod) {
644
+ if (newChild.__BK_WEWEB_APP_KEY__) {
645
+ const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
646
+ if (app?.container) {
647
+ const targetChild = resetNewElement(parent, newChild, app);
648
+ const needKeepAlive = isSepcailElement(newChild) && !!app.keepAlive && !(app.container instanceof ShadowRoot);
649
+ const container = needKeepAlive ? document.head : app?.container;
650
+ setMarkElement(targetChild, app, needKeepAlive);
651
+ return rawMethod.call(container, targetChild);
652
+ }
653
+ }
654
+ return rawMethod.call(parent, newChild);
655
+ }
656
+ function elementInsertHandler(parent, newChild, passiveChild, rawMethod) {
657
+ if (newChild.__BK_WEWEB_APP_KEY__) {
658
+ const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
659
+ if (app?.container) {
660
+ const needKeepAlive = isSepcailElement(newChild) && app.keepAlive && !(app.container instanceof ShadowRoot);
661
+ const container = needKeepAlive ? document.head : app?.container;
662
+ const targetChild = resetNewElement(parent, newChild, app);
663
+ if (needKeepAlive) {
664
+ targetChild.__KEEP_ALIVE__ = app.appCacheKey;
665
+ targetChild.setAttribute('data-from', app.name);
666
+ targetChild.setAttribute('data-keep-alive', 'true');
667
+ }
668
+ if (passiveChild && !container.contains(passiveChild)) {
669
+ return bodyAppendChild$1.call(container, targetChild);
670
+ }
671
+ return rawMethod.call(container, targetChild, passiveChild);
672
+ }
673
+ }
674
+ return rawMethod.call(parent, newChild, passiveChild);
675
+ }
676
+ function setMarkElement(element, app, keepAlive) {
677
+ if (keepAlive) {
678
+ element.__KEEP_ALIVE__ = app.appCacheKey;
679
+ element.setAttribute('data-from', app.name);
680
+ element.setAttribute('data-keep-alive', 'true');
681
+ }
682
+ element.setAttribute?.('powered-by', 'bk-weweb');
683
+ return element;
684
+ }
685
+
686
+ const { setAttribute } = Element.prototype;
687
+ const { appendChild: bodyAppendChild, removeChild: bodyRemoveChild, append, } = HTMLBodyElement.prototype;
688
+ const { appendChild: headAppendChild, removeChild: headRemoveChild, insertBefore: headInsertBefore, } = HTMLHeadElement.prototype;
689
+ const rawHead = document.head;
690
+ function rewriteBodyAndHeaderMethods() {
691
+ Element.prototype.setAttribute = function (key, value) {
692
+ const tagName = this.tagName.toLocaleUpperCase();
693
+ if (((['src', 'srcset'].includes(key) && ['SCRIPT', 'IMG'].includes(tagName))
694
+ || (key === 'href' && ['LINK'].includes(tagName)))
695
+ && this.__BK_WEWEB_APP_KEY__
696
+ && appCache.getApp(this.__BK_WEWEB_APP_KEY__ || '')) {
697
+ setAttribute.call(this, key, fillUpPath(value, appCache.getApp(this.__BK_WEWEB_APP_KEY__).url));
698
+ }
699
+ else {
700
+ setAttribute.call(this, key, value);
701
+ }
702
+ };
703
+ HTMLBodyElement.prototype.appendChild = function appendChildNew(newChild) {
704
+ if (newChild.__KEEP_ALIVE__ && isSepcailElement(newChild))
705
+ return headAppendChild.call(rawHead, newChild);
706
+ return elmentAppendHandler(this, newChild, bodyAppendChild);
707
+ };
708
+ HTMLBodyElement.prototype.append = function (...nodes) {
709
+ let i = 0;
710
+ const { length } = nodes;
711
+ while (i < length) {
712
+ if (nodes[i].__KEEP_ALIVE__ && isSepcailElement(nodes[i])) {
713
+ return headAppendChild.call(rawHead, nodes[i]);
714
+ }
715
+ elmentAppendHandler(this, nodes[i], bodyAppendChild);
716
+ i += 1;
717
+ }
718
+ };
719
+ HTMLHeadElement.prototype.appendChild = HTMLBodyElement.prototype.appendChild;
720
+ HTMLHeadElement.prototype.insertBefore = function (newChild, refChild) {
721
+ return elementInsertHandler(this, newChild, refChild, headInsertBefore);
722
+ };
723
+ HTMLBodyElement.prototype.removeChild = function removeChildNew(oldChild) {
724
+ const app = appCache.getApp(oldChild.__BK_WEWEB_APP_KEY__);
725
+ if (app?.container?.contains(oldChild)) {
726
+ const node = bodyRemoveChild.call(app.container, oldChild);
727
+ return node;
728
+ }
729
+ if (this.contains(oldChild)) {
730
+ return bodyRemoveChild.call(this, oldChild);
731
+ }
732
+ return oldChild;
733
+ };
734
+ HTMLHeadElement.prototype.removeChild = HTMLBodyElement.prototype.removeChild;
735
+ }
736
+ function resetBodyAndHeaderMethods() {
737
+ setCurrentRunningApp(null);
738
+ Element.prototype.setAttribute = setAttribute;
739
+ HTMLBodyElement.prototype.appendChild = bodyAppendChild;
740
+ HTMLBodyElement.prototype.append = append;
741
+ HTMLBodyElement.prototype.removeChild = bodyRemoveChild;
742
+ HTMLHeadElement.prototype.appendChild = headAppendChild;
743
+ HTMLHeadElement.prototype.insertBefore = headInsertBefore;
744
+ HTMLHeadElement.prototype.removeChild = headRemoveChild;
745
+ }
746
+
747
+ function beforeLoad() {
748
+ rewriteBodyAndHeaderMethods();
749
+ rewriteDocumentPrototypeMethods();
750
+ }
751
+
752
+ const constructorMap = new WeakMap();
753
+ function isConstructor(value) {
754
+ if (constructorMap.has(value)) {
755
+ return constructorMap.get(value);
756
+ }
757
+ const valueStr = value.toString();
758
+ const result = (value.prototype
759
+ && value.prototype.constructor === value
760
+ && Object.getOwnPropertyNames(value.prototype).length > 1)
761
+ || /^function\s+[A-Z]/.test(valueStr)
762
+ || /^class\s+/.test(valueStr);
763
+ constructorMap.set(value, result);
764
+ return result;
765
+ }
766
+ const rawWindowMethodMap = new WeakMap();
767
+ function bindFunctionToRawWindow(rawWindow, value) {
768
+ if (rawWindowMethodMap.has(value)) {
769
+ return rawWindowMethodMap.get(value);
770
+ }
771
+ if (isFunction(value) && !isConstructor(value)) {
772
+ const bindRawWindowValue = value.bind(rawWindow);
773
+ Object.keys(value).forEach(key => (bindRawWindowValue[key] = value[key]));
774
+ // eslint-disable-next-line no-prototype-builtins
775
+ if (value.hasOwnProperty('prototype') && !bindRawWindowValue.hasOwnProperty('prototype')) {
776
+ bindRawWindowValue.prototype = value.prototype;
777
+ }
778
+ rawWindowMethodMap.set(value, bindRawWindowValue);
779
+ return bindRawWindowValue;
780
+ }
781
+ return value;
782
+ }
783
+
784
+ /* eslint-disable no-param-reassign */
785
+ // rewrite document and body event listener
786
+ function rewriteDocumentAndBodyEvent() {
787
+ const { addEventListener, removeEventListener } = window.document;
788
+ const { addEventListener: bodyAddEventListener, removeEventListener: bodyRemoveEventListener } = window.document.body;
789
+ document.addEventListener = function (type, listener, options) {
790
+ const app = getCurrentRunningApp();
791
+ if (app) {
792
+ const appListenersMap = documentEventListenerMap.get(app.appCacheKey);
793
+ if (appListenersMap) {
794
+ const appListenerList = appListenersMap.get(type);
795
+ if (appListenerList) {
796
+ appListenerList.add(listener);
797
+ }
798
+ else {
799
+ appListenersMap.set(type, new Set([listener]));
800
+ }
801
+ }
802
+ else {
803
+ documentEventListenerMap.set(app.appCacheKey, new Map([[type, new Set([listener])]]));
804
+ }
805
+ }
806
+ addEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
807
+ };
808
+ document.body.addEventListener = document.addEventListener;
809
+ document.removeEventListener = function (type, listener, options) {
810
+ const app = getCurrentRunningApp();
811
+ if (app) {
812
+ const appListenersMap = documentEventListenerMap.get(app.appCacheKey);
813
+ if (appListenersMap) {
814
+ const appListenerList = appListenersMap.get(type);
815
+ if (appListenerList?.size && appListenerList.has(listener)) {
816
+ appListenerList.delete(listener);
817
+ }
818
+ }
819
+ }
820
+ removeEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
821
+ };
822
+ document.body.removeEventListener = document.removeEventListener;
823
+ function resetDocumentAndBodyEvent() {
824
+ document.addEventListener = addEventListener;
825
+ document.body.addEventListener = bodyAddEventListener;
826
+ document.removeEventListener = removeEventListener;
827
+ document.body.removeEventListener = bodyRemoveEventListener;
828
+ }
829
+ return {
830
+ resetDocumentAndBodyEvent,
831
+ };
832
+ }
833
+ // rewrite window funtion like settimeout setinterval ...
834
+ function rewriteWindowFunction(fakeWindow) {
835
+ const app = getCurrentRunningApp();
836
+ const eventListenerMap = new Map();
837
+ const intervalIdMap = new Map();
838
+ const timeoutIdMap = new Map();
839
+ const rawWindow = window;
840
+ const rawDocument = window.document;
841
+ const { addEventListener, removeEventListener, setInterval, setTimeout, clearInterval, clearTimeout } = window;
842
+ const { removeEventListener: documentRemoveEventListener } = window.document;
843
+ // listener may be null, e.g test-passive
844
+ fakeWindow.addEventListener = function (type, listener, options) {
845
+ const listenerList = eventListenerMap.get(type);
846
+ if (listenerList) {
847
+ listenerList.add(listener);
848
+ }
849
+ else {
850
+ eventListenerMap.set(type, new Set([listener]));
851
+ }
852
+ addEventListener.call(rawWindow, type, listener, options);
853
+ };
854
+ fakeWindow.removeEventListener = function (type, listener, options) {
855
+ const listenerList = eventListenerMap.get(type);
856
+ if (listenerList?.size && listenerList.has(listener)) {
857
+ listenerList.delete(listener);
858
+ }
859
+ removeEventListener.call(rawWindow, type, listener, options);
860
+ };
861
+ fakeWindow.setInterval = function (handler, timeout, ...args) {
862
+ const intervalId = setInterval.call(rawWindow, handler, timeout, ...args);
863
+ intervalIdMap.set(intervalId, { handler, timeout, args });
864
+ return intervalId;
865
+ };
866
+ fakeWindow.setTimeout = function (handler, timeout, ...args) {
867
+ const timeoutId = setTimeout.call(rawWindow, handler, timeout, ...args);
868
+ timeoutIdMap.set(timeoutId, { handler, timeout, args });
869
+ return timeoutId;
870
+ };
871
+ fakeWindow.clearInterval = function (intervalId) {
872
+ intervalIdMap.delete(intervalId);
873
+ clearInterval.call(rawWindow, intervalId);
874
+ };
875
+ fakeWindow.clearTimeout = function (timeoutId) {
876
+ timeoutIdMap.delete(timeoutId);
877
+ clearTimeout.call(rawWindow, timeoutId);
878
+ };
879
+ // reset all event listener & interval & timeout when unmount app
880
+ const resetWindowFunction = () => {
881
+ // clear window events listener
882
+ if (eventListenerMap.size) {
883
+ eventListenerMap.forEach((listenerList, type) => {
884
+ for (const listener of listenerList) {
885
+ removeEventListener.call(rawWindow, type, listener);
886
+ }
887
+ });
888
+ eventListenerMap.clear();
889
+ }
890
+ // clear settimeout timers
891
+ if (intervalIdMap.size) {
892
+ intervalIdMap.forEach((_, intervalId) => {
893
+ clearInterval.call(rawWindow, intervalId);
894
+ });
895
+ intervalIdMap.clear();
896
+ }
897
+ if (timeoutIdMap.size) {
898
+ timeoutIdMap.forEach((_, timeoutId) => {
899
+ clearTimeout.call(rawWindow, timeoutId);
900
+ });
901
+ timeoutIdMap.clear();
902
+ }
903
+ if (app) {
904
+ documentClickListMap.delete(app.appCacheKey);
905
+ const documentAppListenersMap = documentEventListenerMap.get(app.appCacheKey);
906
+ if (documentAppListenersMap) {
907
+ documentAppListenersMap.forEach((listenerList, type) => {
908
+ for (const listener of listenerList) {
909
+ documentRemoveEventListener.call(rawDocument, type, listener);
910
+ }
911
+ });
912
+ documentAppListenersMap.clear();
913
+ }
914
+ }
915
+ };
916
+ return {
917
+ resetWindowFunction,
918
+ };
919
+ }
920
+
921
+ /* eslint-disable no-new-func */
922
+ class SandBox {
923
+ app;
924
+ resetWindowFunction;
925
+ resetDocumentAndBodyEvent;
926
+ injectedKeySet = new Set();
927
+ escapedKeySet = new Set();
928
+ active = false;
929
+ rawWindow;
930
+ rawDocument;
931
+ proxyWindow;
932
+ fakeWindow = {};
933
+ windowSymbolKey;
934
+ constructor(app) {
935
+ this.app = app;
936
+ const descriptorMap = new Map();
937
+ const rawWindow = window;
938
+ const rawDocument = window.document;
939
+ this.fakeWindow.__POWERED_BY_BK_WEWEB__ = true;
940
+ this.fakeWindow.__BK_WEWEB_APP_KEY__ = app.appCacheKey;
941
+ this.rawWindow = rawWindow;
942
+ this.rawDocument = rawDocument;
943
+ this.fakeWindow.rawWindow = rawWindow;
944
+ this.fakeWindow.rawDocument = rawDocument;
945
+ const { resetWindowFunction } = rewriteWindowFunction(this.fakeWindow);
946
+ this.resetWindowFunction = resetWindowFunction;
947
+ this.windowSymbolKey = `__${(app.name || app.appCacheKey).replace(/(-|,|:|~|'|")/gmi, '_')}_${random(10)}__`;
948
+ this.proxyWindow = new Proxy(this.fakeWindow, {
949
+ get: (target, key) => {
950
+ if (commonRawWindowKeyMap[key] || key === Symbol.unscopables)
951
+ return rawWindow[key];
952
+ if (commonFakeWindowKeyMap[key])
953
+ return this.fakeWindow[key];
954
+ if (['window', 'self', 'globalThis'].includes(key))
955
+ return this.proxyWindow;
956
+ if (key === 'document' || key === 'eval') {
957
+ app.registerRunningApp();
958
+ // eslint-disable-next-line no-eval
959
+ return key === 'document' ? rawDocument : eval;
960
+ }
961
+ if (scopedLocationKeyList.includes(key)
962
+ && this.app instanceof MicroAppModel
963
+ && this.app.iframe
964
+ && this.app.scopeLocation) {
965
+ return this.app.iframe.contentWindow?.[key];
966
+ }
967
+ // if (key === Symbol.unscopables) return com;
968
+ if (key === 'hasOwnProperty')
969
+ return (key) => this.fakeWindow.hasOwnProperty(key) || rawWindow.hasOwnProperty(key);
970
+ if (key === 'top' || key === 'parent') {
971
+ if (rawWindow === rawWindow.parent) {
972
+ return this.proxyWindow;
973
+ }
974
+ return Reflect.get(rawWindow, key); // iframe
975
+ }
976
+ if (Reflect.has(target, key)
977
+ || scopeWindowKeyList.includes(key))
978
+ return Reflect.get(target, key);
979
+ const rawValue = Reflect.get(rawWindow, key);
980
+ return bindFunctionToRawWindow(rawWindow, rawValue);
981
+ },
982
+ set: (target, key, value) => {
983
+ if (this.active) {
984
+ if (scopedLocationKeyList.includes(key)
985
+ && this.app instanceof MicroAppModel
986
+ && this.app.iframe
987
+ && this.app.scopeLocation) {
988
+ return Reflect.set(this.app.iframe.contentWindow, key, value);
989
+ }
990
+ if (escapeSetterKeyList.includes(key)) {
991
+ Reflect.set(rawWindow, key, value);
992
+ }
993
+ else if (!target.hasOwnProperty(key)
994
+ && rawWindow.hasOwnProperty(key)
995
+ && !scopeWindowKeyList.includes(key)) {
996
+ const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
997
+ const { writable, configurable, enumerable } = descriptor;
998
+ if (writable) {
999
+ Object.defineProperty(target, key, {
1000
+ configurable,
1001
+ enumerable,
1002
+ writable,
1003
+ value,
1004
+ });
1005
+ this.injectedKeySet.add(key);
1006
+ }
1007
+ }
1008
+ else {
1009
+ Reflect.set(target, key, value);
1010
+ this.injectedKeySet.add(key);
1011
+ }
1012
+ if ((commonEScapeKeyList.includes(key) && !Reflect.has(rawWindow, key))
1013
+ && !scopeWindowKeyList.includes(key)) {
1014
+ Reflect.set(rawWindow, key, value);
1015
+ this.escapedKeySet.add(key);
1016
+ }
1017
+ }
1018
+ return true;
1019
+ },
1020
+ has: (target, key) => commonRawWindowKeyMap[key]
1021
+ || key in target
1022
+ || key in rawWindow,
1023
+ getOwnPropertyDescriptor: (target, key) => {
1024
+ if (target.hasOwnProperty(key)) {
1025
+ return Object.getOwnPropertyDescriptor(target, key);
1026
+ }
1027
+ if (rawWindow.hasOwnProperty(key)) {
1028
+ descriptorMap.set(key, DescriptorMapValue.WINDOW);
1029
+ const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
1030
+ if (descriptor && !descriptor.configurable) {
1031
+ descriptor.configurable = true;
1032
+ }
1033
+ return descriptor;
1034
+ }
1035
+ return undefined;
1036
+ },
1037
+ // Object.defineProperty(window, key, Descriptor)
1038
+ defineProperty: (target, key, value) => {
1039
+ const from = descriptorMap.get(key);
1040
+ if (from === DescriptorMapValue.WINDOW) {
1041
+ return Reflect.defineProperty(rawWindow, key, value);
1042
+ }
1043
+ return Reflect.defineProperty(target, key, value);
1044
+ },
1045
+ // Object.getOwnPropertyNames(window)
1046
+ ownKeys: (target) => arrayUnique(Reflect.ownKeys(rawWindow)
1047
+ .concat(Reflect.ownKeys(target))),
1048
+ deleteProperty: (target, key) => {
1049
+ if (target.hasOwnProperty(key)) {
1050
+ this.injectedKeySet.has(key) && this.injectedKeySet.delete(key);
1051
+ this.escapedKeySet.has(key) && Reflect.deleteProperty(rawWindow, key);
1052
+ return Reflect.deleteProperty(target, key);
1053
+ }
1054
+ return true;
1055
+ },
1056
+ });
1057
+ if (app.showSourceCode) {
1058
+ rawWindow[this.windowSymbolKey] = this.proxyWindow;
1059
+ }
1060
+ }
1061
+ activeated(data) {
1062
+ if (!this.active) {
1063
+ this.active = true;
1064
+ this.fakeWindow.__BK_WEWEB_DATA__ = data ?? {};
1065
+ const { resetDocumentAndBodyEvent } = rewriteDocumentAndBodyEvent();
1066
+ this.resetDocumentAndBodyEvent = resetDocumentAndBodyEvent;
1067
+ }
1068
+ }
1069
+ deactivated() {
1070
+ if (this.active) {
1071
+ this.active = false;
1072
+ this.resetWindowFunction();
1073
+ // this.injectedKeySet.forEach((key: PropertyKey) => Reflect.deleteProperty(this.fakeWindow, key));
1074
+ this.injectedKeySet.clear();
1075
+ this.escapedKeySet.forEach((key) => Reflect.deleteProperty(window, key));
1076
+ this.escapedKeySet.clear();
1077
+ this.resetDocumentAndBodyEvent?.();
1078
+ }
1079
+ }
1080
+ }
1081
+
1082
+ class MicroInstanceModel {
1083
+ state = AppState.UNSET;
1084
+ isPreLoad = false;
1085
+ appCacheKey;
1086
+ url;
1087
+ container;
1088
+ scopeJs = false;
1089
+ source;
1090
+ sandBox;
1091
+ name;
1092
+ showSourceCode = true;
1093
+ scopeCss = true;
1094
+ keepAlive;
1095
+ initSource;
1096
+ data;
1097
+ constructor(props) {
1098
+ this.name = props.id !== props.url ? props.id : random(5);
1099
+ this.appCacheKey = props.id || this.name;
1100
+ this.url = props.url;
1101
+ this.container = props.container ?? undefined;
1102
+ this.scopeJs = props.scopeJs ?? true;
1103
+ this.showSourceCode = props.showSourceCode ?? true;
1104
+ this.scopeCss = props.scopeCss ?? true;
1105
+ this.keepAlive = props.keepAlive ?? false;
1106
+ this.data = props.data ?? {};
1107
+ this.initSource = props.initSource ?? [];
1108
+ // 是否启用沙盒
1109
+ if (this.scopeJs) {
1110
+ this.sandBox = new SandBox(this);
1111
+ }
1112
+ }
1113
+ get status() {
1114
+ return this.state;
1115
+ }
1116
+ set status(v) {
1117
+ this.state = v;
1118
+ }
1119
+ async start() {
1120
+ if (!this.source || [AppState.UNSET, AppState.ERROR].includes(this.status)) {
1121
+ this.source = new EntrySource(this.url);
1122
+ await this.source.importEntery(this);
1123
+ }
1124
+ }
1125
+ onMount() {
1126
+ if (this.isPreLoad)
1127
+ return;
1128
+ this.state = AppState.LOADED;
1129
+ this.mount();
1130
+ }
1131
+ onError() {
1132
+ this.state = AppState.ERROR;
1133
+ }
1134
+ mount(container, callback) {
1135
+ this.isPreLoad = false;
1136
+ this.container = container ?? this.container;
1137
+ this.state = AppState.MOUNTING;
1138
+ if (this.container instanceof HTMLElement) {
1139
+ this.container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1140
+ }
1141
+ this.container.innerHTML = '';
1142
+ const instanceWrap = document.createElement('div');
1143
+ const wrapId = `${this.name}-wrapper`;
1144
+ instanceWrap.setAttribute('id', wrapId);
1145
+ if (this.source?.styles.size) {
1146
+ excuteAppStyles(this, this.container);
1147
+ }
1148
+ this.container.appendChild(instanceWrap);
1149
+ this.sandBox?.activeated();
1150
+ execAppScripts(this).finally(() => {
1151
+ this.state = AppState.MOUNTED;
1152
+ const scriptInfo = this.source?.getScript(this.url);
1153
+ if (typeof scriptInfo?.exportInstance?.render === 'function') {
1154
+ scriptInfo.exportInstance.render(instanceWrap, this.data);
1155
+ }
1156
+ callback?.(this, scriptInfo?.exportInstance);
1157
+ });
1158
+ }
1159
+ activated(container, callback) {
1160
+ this.isPreLoad = false;
1161
+ this.state = AppState.ACTIVATED;
1162
+ if (this.container && container) {
1163
+ if (container instanceof Element)
1164
+ container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1165
+ const fragment = document.createDocumentFragment();
1166
+ Array.from(this.container.childNodes).forEach((node) => {
1167
+ fragment.appendChild(node);
1168
+ });
1169
+ container.appendChild(fragment);
1170
+ this.container = container;
1171
+ this.sandBox?.activeated();
1172
+ const scriptInfo = this.source?.getScript(this.url);
1173
+ callback?.(this, scriptInfo?.exportInstance);
1174
+ }
1175
+ }
1176
+ deactivated() {
1177
+ this.state = AppState.DEACTIVATED;
1178
+ this.sandBox?.deactivated();
1179
+ }
1180
+ unmount(needDestroy) {
1181
+ this.state = AppState.UNMOUNT;
1182
+ this.sandBox?.deactivated();
1183
+ needDestroy && appCache.deleteApp(this.url);
1184
+ this.container.innerHTML = '';
1185
+ this.container = undefined;
1186
+ }
1187
+ registerRunningApp() {
1188
+ setCurrentRunningApp(this);
1189
+ Promise.resolve().then(() => setCurrentRunningApp(null));
1190
+ }
1191
+ }
1192
+
1193
+ async function load(props) {
1194
+ if (props.mode === 'app')
1195
+ return await loadApp(props);
1196
+ if (props.mode === 'js')
1197
+ return await loadInstance(props);
1198
+ return await loadApp(props);
1199
+ }
1200
+ // 加载app
1201
+ async function loadApp(props) {
1202
+ let instance = appCache.getApp(props.id);
1203
+ if (!instance) {
1204
+ instance = new MicroAppModel(props);
1205
+ appCache.setApp(instance);
1206
+ }
1207
+ await instance.start();
1208
+ return instance;
1209
+ }
1210
+ // 加载instance
1211
+ function loadInstance(props) {
1212
+ return new Promise((resolve) => {
1213
+ let instance = appCache.getApp(props.id);
1214
+ if (!instance) {
1215
+ instance = new MicroInstanceModel(props);
1216
+ appCache.setApp(instance);
1217
+ instance.start().then(() => resolve(instance));
1218
+ }
1219
+ else if ([AppState.UNSET, AppState.MOUNTING].includes(instance.status)) {
1220
+ const timer = setInterval(() => {
1221
+ if ([AppState.ERROR, AppState.MOUNTED].includes(instance.status)) {
1222
+ resolve(instance);
1223
+ clearInterval(timer);
1224
+ }
1225
+ }, 300);
1226
+ }
1227
+ else {
1228
+ resolve(instance);
1229
+ }
1230
+ });
1231
+ }
1232
+
1233
+ function unmount(appKey) {
1234
+ const app = appCache.getApp(appKey);
1235
+ if (app?.status !== AppState.UNMOUNT) {
1236
+ app?.unmount();
1237
+ }
1238
+ if (!appCache.hasActiveApp) {
1239
+ resetBodyAndHeaderMethods();
1240
+ resetDocumentPrototypeMethods();
1241
+ }
1242
+ }
1243
+
1244
+ function activated(appKey, container, callback) {
1245
+ const app = appCache.getApp(appKey);
1246
+ if (app?.status === AppState.DEACTIVATED && app.keepAlive) {
1247
+ nextTask(() => app?.activated(container, callback));
1248
+ }
1249
+ else {
1250
+ nextTask(() => app?.mount(container, callback));
1251
+ }
1252
+ }
1253
+
1254
+ function deactivated(appKey) {
1255
+ const app = appCache.getApp(appKey);
1256
+ if (app && [AppState.ACTIVATED, AppState.MOUNTED].includes(app.status)) {
1257
+ app.keepAlive ? app.deactivated() : app.unmount();
1258
+ }
1259
+ if (!appCache.hasActiveApp) {
1260
+ resetBodyAndHeaderMethods();
1261
+ resetDocumentPrototypeMethods();
1262
+ }
1263
+ }
1264
+
1265
+ // bk-weweb支持的属性配置
1266
+ var ObserveAttrs;
1267
+ (function (ObserveAttrs) {
1268
+ ObserveAttrs["URL"] = "url";
1269
+ ObserveAttrs["showSourceCode"] = "showSourceCode";
1270
+ ObserveAttrs["scopeLocation"] = "scopeLocation";
1271
+ ObserveAttrs["setShodowDom"] = "setShodowDom";
1272
+ ObserveAttrs["mode"] = "mode";
1273
+ ObserveAttrs["data"] = "data";
1274
+ ObserveAttrs["id"] = "id";
1275
+ ObserveAttrs["scopeJs"] = "scopeJs";
1276
+ ObserveAttrs["scopeCss"] = "scopeCss";
1277
+ ObserveAttrs["keepAlive"] = "keepAlive";
1278
+ })(ObserveAttrs || (ObserveAttrs = {}));
1279
+ class BkIframeElement extends HTMLElement {
1280
+ static get observedAttributes() {
1281
+ return [ObserveAttrs.URL];
1282
+ }
1283
+ connected = false;
1284
+ appUrl = '';
1285
+ // 考虑到js模式下 需要js bundle的复用性 需用户设置id属性 如果单实例下则可以不用配置
1286
+ get appKey() {
1287
+ return this.getAttribute(ObserveAttrs.id) || this.getAttribute(ObserveAttrs.URL);
1288
+ }
1289
+ get appData() {
1290
+ if (this.hasAttribute(ObserveAttrs.data)) {
1291
+ try {
1292
+ return JSON.parse(this.getAttribute(ObserveAttrs.data));
1293
+ }
1294
+ catch { }
1295
+ }
1296
+ return {};
1297
+ }
1298
+ get appProps() {
1299
+ if (this.getAttribute('mode') === 'js') {
1300
+ return {
1301
+ url: this.getAttribute(ObserveAttrs.URL),
1302
+ mode: 'js',
1303
+ id: this.appKey,
1304
+ data: this.appData,
1305
+ container: this.shadowRoot ?? this,
1306
+ showSourceCode: this.getBooleanAttr(ObserveAttrs.showSourceCode),
1307
+ scopeCss: this.getBooleanAttr(ObserveAttrs.scopeCss) && !this.getBooleanAttr(ObserveAttrs.setShodowDom),
1308
+ scopeJs: this.getBooleanAttr(ObserveAttrs.scopeJs),
1309
+ keepAlive: this.getBooleanAttr(ObserveAttrs.keepAlive),
1310
+ };
1311
+ }
1312
+ return {
1313
+ url: this.getAttribute(ObserveAttrs.URL),
1314
+ mode: 'app',
1315
+ id: this.appKey,
1316
+ data: this.appData,
1317
+ container: this.shadowRoot ?? this,
1318
+ scopeLocation: this.getBooleanAttr(ObserveAttrs.scopeLocation),
1319
+ showSourceCode: this.getBooleanAttr(ObserveAttrs.showSourceCode),
1320
+ scopeCss: !this.getBooleanAttr(ObserveAttrs.setShodowDom),
1321
+ scopeJs: !this.getBooleanAttr(ObserveAttrs.scopeJs),
1322
+ keepAlive: this.getBooleanAttr(ObserveAttrs.keepAlive),
1323
+ };
1324
+ }
1325
+ async connectedCallback() {
1326
+ beforeLoad();
1327
+ if (this.getBooleanAttr(ObserveAttrs.setShodowDom) && !this.shadowRoot) {
1328
+ this.attachShadow({ mode: 'open', delegatesFocus: true });
1329
+ }
1330
+ await load(this.appProps);
1331
+ activated(this.appKey, this.shadowRoot ?? this);
1332
+ this.connected = true;
1333
+ }
1334
+ disconnectedCallback() {
1335
+ this.connected = false;
1336
+ if (this.appProps.keepAlive) {
1337
+ deactivated(this.appKey);
1338
+ }
1339
+ else
1340
+ unmount(this.appKey);
1341
+ }
1342
+ attributeChangedCallback(attr, _oldVal, newVal) {
1343
+ if (attr !== ObserveAttrs.URL || this[attr] === newVal)
1344
+ return;
1345
+ this.appUrl = newVal;
1346
+ (this.connected || appCache.getApp(this.appKey)) && this.handleAttributeChanged();
1347
+ }
1348
+ async handleAttributeChanged() {
1349
+ if (!this.appKey)
1350
+ return;
1351
+ if (this.getBooleanAttr(ObserveAttrs.setShodowDom)) {
1352
+ this.attachShadow({ mode: 'open' });
1353
+ }
1354
+ const app = appCache.getApp(this.appKey);
1355
+ if (app && app.url === this.appUrl && (app.isPreLoad || app.status === AppState.UNMOUNT)) {
1356
+ activated(this.appKey, this.shadowRoot ?? this);
1357
+ return;
1358
+ }
1359
+ await load(this.appProps);
1360
+ }
1361
+ getBooleanAttr(name) {
1362
+ return this.hasAttribute(name) ? this.getAttribute(name) !== 'false' : undefined;
1363
+ }
1364
+ }
1365
+
1366
+ // 收集和辩证资源
1367
+ async function collectSource(soruceList) {
1368
+ let source = [];
1369
+ if (typeof soruceList === 'function') {
1370
+ source = await soruceList();
1371
+ }
1372
+ else {
1373
+ source = soruceList || [];
1374
+ }
1375
+ if (!source.length)
1376
+ return {};
1377
+ const collectScript = new Map();
1378
+ const collectStyle = new Map();
1379
+ source.forEach((str) => {
1380
+ try {
1381
+ const url = new URL(str);
1382
+ if (url.pathname.match(/\.js$/)) {
1383
+ const script = appCache.getCacheScript(str);
1384
+ collectScript.set(str, new Script({
1385
+ code: script?.code || '',
1386
+ async: false,
1387
+ defer: false,
1388
+ url: str,
1389
+ isModule: false,
1390
+ initial: true,
1391
+ fromHtml: false,
1392
+ }));
1393
+ }
1394
+ else if (url.pathname.match(/\.css$/)) {
1395
+ const style = appCache.getCacheStyle(str);
1396
+ collectStyle.set(str, new Style({
1397
+ code: style?.code || '',
1398
+ prefetch: false,
1399
+ preload: false,
1400
+ url: str,
1401
+ fromHtml: true,
1402
+ initial: true,
1403
+ }));
1404
+ }
1405
+ }
1406
+ catch {
1407
+ console.error(`【bk-weweb】: ${str} is invalid URL`);
1408
+ }
1409
+ });
1410
+ return {
1411
+ collectScript,
1412
+ collectStyle,
1413
+ };
1414
+ }
1415
+
1416
+ const CUSTOM_ELEMENT_TAG = 'bk-weweb';
1417
+ class IframeApp {
1418
+ fetchSource;
1419
+ webcomponentTag = CUSTOM_ELEMENT_TAG;
1420
+ constructor() {
1421
+ if (!window.customElements.get(CUSTOM_ELEMENT_TAG)) {
1422
+ window.customElements.define(CUSTOM_ELEMENT_TAG, BkIframeElement);
1423
+ }
1424
+ }
1425
+ // todo set some global start props
1426
+ start(option) {
1427
+ if (typeof option?.fetchSource === 'function') {
1428
+ this.fetchSource = option.fetchSource;
1429
+ }
1430
+ this.webcomponentTag = option?.webcomponentTag || CUSTOM_ELEMENT_TAG;
1431
+ this.setWebComponentTag();
1432
+ }
1433
+ // 设置自定义dom标签名
1434
+ setWebComponentTag() {
1435
+ if (!window.customElements.get(this.webcomponentTag)) {
1436
+ window.customElements.define(this.webcomponentTag, BkIframeElement);
1437
+ }
1438
+ }
1439
+ }
1440
+ const iframeApp = new IframeApp();
1441
+
1442
+ function fetchSource(url, options = {}) {
1443
+ if (iframeApp.fetchSource) {
1444
+ return iframeApp.fetchSource(url, options);
1445
+ }
1446
+ return window.fetch(url, options).then(res => res.text());
1447
+ }
1448
+
1449
+ /* eslint-disable no-restricted-syntax */
1450
+ let firstGlobalProp;
1451
+ let secondGlobalProp;
1452
+ let lastGlobalProp;
1453
+ // Script脚本实例
1454
+ class Script {
1455
+ code = '';
1456
+ async = false;
1457
+ defer = false;
1458
+ isModule = false;
1459
+ url;
1460
+ exportInstance;
1461
+ scoped;
1462
+ fromHtml;
1463
+ initial;
1464
+ constructor({ code, async, defer, isModule, url, fromHtml, initial }) {
1465
+ this.code = code;
1466
+ this.async = async;
1467
+ this.defer = defer;
1468
+ this.isModule = isModule;
1469
+ this.url = url;
1470
+ this.scoped = false;
1471
+ this.fromHtml = fromHtml ?? false;
1472
+ this.initial = initial ?? false;
1473
+ }
1474
+ async getCode(app) {
1475
+ if (this.code.length || !this.url) {
1476
+ return this.code;
1477
+ }
1478
+ let code = '';
1479
+ if (app?.source?.getScript(this.url)) {
1480
+ code = app.source.getScript(this.url)?.code || '';
1481
+ }
1482
+ if (!code && appCache.getCacheScript(this.url)) {
1483
+ code = appCache.getCacheScript(this.url)?.code || '';
1484
+ }
1485
+ if (!code) {
1486
+ code = await fetchSource(this.url).catch((e) => {
1487
+ console.error(`fetch script ${this.url} error`, e);
1488
+ return '';
1489
+ });
1490
+ }
1491
+ this.code = code;
1492
+ return code;
1493
+ }
1494
+ async excuteCode(app, needRelaceScriptElement = false) {
1495
+ try {
1496
+ if (!this.code)
1497
+ await this.getCode(app);
1498
+ if (app instanceof MicroInstanceModel) {
1499
+ noteGlobalProps(app.sandBox?.proxyWindow || window);
1500
+ }
1501
+ let scopedCode = this.code;
1502
+ scopedCode = this.transformCode(app);
1503
+ if (app.showSourceCode || this.isModule) {
1504
+ const scriptElement = createElement$1('script');
1505
+ app.registerRunningApp();
1506
+ this.executeSourceScript(scriptElement, scopedCode);
1507
+ if (needRelaceScriptElement)
1508
+ return scriptElement;
1509
+ const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
1510
+ const container = needKeepAlive ? document.head : app.container;
1511
+ setMarkElement(scriptElement, app, needKeepAlive);
1512
+ container.appendChild(scriptElement);
1513
+ }
1514
+ else {
1515
+ this.executeMemoryScript(app, scopedCode);
1516
+ if (needRelaceScriptElement)
1517
+ return document.createComment('【bk-weweb】dynamic script');
1518
+ }
1519
+ if (app instanceof MicroInstanceModel) {
1520
+ const exportProp = getGlobalProp(app.sandBox?.proxyWindow || window);
1521
+ exportProp && (this.exportInstance = (app.sandBox?.proxyWindow || window)[exportProp]);
1522
+ }
1523
+ }
1524
+ catch (e) {
1525
+ console.error('execute script code error', e);
1526
+ }
1527
+ return;
1528
+ }
1529
+ transformCode(app) {
1530
+ if (app.sandBox) {
1531
+ if (app.showSourceCode || this.isModule) {
1532
+ return `;(function(window, self){
1533
+ with(window){
1534
+ ;${this.code}\n
1535
+ }
1536
+ }).call(window.${app.sandBox.windowSymbolKey},
1537
+ window.${app.sandBox.windowSymbolKey});`;
1538
+ }
1539
+ return `
1540
+ with(window) {
1541
+ try {
1542
+ ${this.code}
1543
+ }
1544
+ catch(e) {
1545
+ console.error(e)
1546
+ }
1547
+ }
1548
+ `;
1549
+ }
1550
+ return this.code;
1551
+ }
1552
+ executeSourceScript(scriptElement, scopedCode) {
1553
+ if (this.isModule) {
1554
+ const blob = new Blob([scopedCode], { type: 'text/javascript' });
1555
+ scriptElement.src = URL.createObjectURL(blob);
1556
+ scriptElement.setAttribute('type', 'module');
1557
+ }
1558
+ else {
1559
+ scriptElement.textContent = scopedCode;
1560
+ }
1561
+ this.url && scriptElement.setAttribute('origin-src', this.url);
1562
+ }
1563
+ executeMemoryScript(app, scopedCode) {
1564
+ try {
1565
+ const isScopedLocation = app instanceof MicroAppModel && app.scopeLocation;
1566
+ app.registerRunningApp();
1567
+ // eslint-disable-next-line no-new-func
1568
+ new Function('window', 'location', 'history', scopedCode)(app.sandBox.proxyWindow, isScopedLocation ? app.iframe?.contentWindow?.location : window.location, isScopedLocation ? app.iframe?.contentWindow?.history : window.history);
1569
+ }
1570
+ catch (e) {
1571
+ console.error(e);
1572
+ }
1573
+ }
1574
+ }
1575
+ // 全局属性是否跳过标记
1576
+ function shouldSkipProperty(global, p) {
1577
+ return (!global.hasOwnProperty(p)
1578
+ || (!isNaN(p) && p < global.length)
1579
+ || (isIE11 && global[p] && typeof window !== 'undefined' && global[p].parent === window));
1580
+ }
1581
+ // 获取instance js source code 执行后 绑定的export 实例
1582
+ function getGlobalProp(global, useFirstGlobalProp) {
1583
+ let cnt = 0;
1584
+ let foundLastProp;
1585
+ let result;
1586
+ for (const p in global) {
1587
+ // do not check frames cause it could be removed during import
1588
+ if (shouldSkipProperty(global, p))
1589
+ continue;
1590
+ if ((cnt === 0 && p !== firstGlobalProp) || (cnt === 1 && p !== secondGlobalProp))
1591
+ return p;
1592
+ if (foundLastProp) {
1593
+ lastGlobalProp = p;
1594
+ result = (useFirstGlobalProp && result) || p;
1595
+ }
1596
+ else {
1597
+ foundLastProp = p === lastGlobalProp;
1598
+ }
1599
+ cnt += 1;
1600
+ }
1601
+ return result;
1602
+ }
1603
+ // 标记全局属性
1604
+ function noteGlobalProps(global) {
1605
+ secondGlobalProp = undefined;
1606
+ firstGlobalProp = secondGlobalProp;
1607
+ for (const p in global) {
1608
+ if (shouldSkipProperty(global, p))
1609
+ continue;
1610
+ if (!firstGlobalProp)
1611
+ firstGlobalProp = p;
1612
+ else if (!secondGlobalProp)
1613
+ secondGlobalProp = p;
1614
+ lastGlobalProp = p;
1615
+ }
1616
+ return lastGlobalProp;
1617
+ }
1618
+ // app初始化dom 脚本执行
1619
+ async function execAppScripts(app) {
1620
+ const appInitialScriptList = Array.from(app.source.scripts.values()).filter(script => script.initial);
1621
+ // 初始化脚本最先执行
1622
+ if (appInitialScriptList.length) {
1623
+ await Promise.all(appInitialScriptList.map(script => script.excuteCode(app)));
1624
+ }
1625
+ const appScriptList = Array.from(app.source.scripts.values()).filter(script => script.fromHtml && !script.initial);
1626
+ const commomList = appScriptList.filter(script => ((!script.async && !script.defer) || script.isModule));
1627
+ // 保证同步脚本 和 module类型 最先执行
1628
+ await Promise.all(commomList.map(script => script.excuteCode(app)));
1629
+ // 最后执行 defer 和 async 脚本
1630
+ const deferScriptList = [];
1631
+ const asyncScriptList = [];
1632
+ // async defer 脚本执行
1633
+ appScriptList.forEach((script) => {
1634
+ if ((script.defer || script.async)) {
1635
+ if (!script.code && script.defer) {
1636
+ deferScriptList.push(script.excuteCode(app));
1637
+ }
1638
+ else
1639
+ asyncScriptList.push(script.excuteCode(app));
1640
+ }
1641
+ });
1642
+ await Promise.all([...asyncScriptList, ...deferScriptList])
1643
+ .catch((e) => {
1644
+ console.error(e);
1645
+ });
1646
+ }
1647
+
1648
+ class MicroAppModel {
1649
+ state = AppState.UNSET;
1650
+ isPreLoad = false;
1651
+ mode = 'app';
1652
+ name;
1653
+ url;
1654
+ container;
1655
+ showSourceCode;
1656
+ scopeCss;
1657
+ scopeJs;
1658
+ source;
1659
+ sandBox;
1660
+ scopeLocation;
1661
+ keepAlive;
1662
+ initSource;
1663
+ iframe = null;
1664
+ data;
1665
+ constructor(props) {
1666
+ this.name = props.id !== props.url ? props.id : random(5);
1667
+ this.mode = props.mode ?? 'app';
1668
+ this.container = props.container ?? undefined;
1669
+ this.showSourceCode = props.showSourceCode ?? false;
1670
+ this.url = props.url;
1671
+ this.data = props.data || {};
1672
+ this.scopeJs = props.scopeJs ?? true;
1673
+ this.scopeCss = props.scopeCss ?? true;
1674
+ this.scopeLocation = props.scopeLocation ?? false;
1675
+ this.isPreLoad = props.isPreLoad ?? false;
1676
+ this.keepAlive = props.keepAlive ?? false;
1677
+ this.initSource = props.initSource ?? [];
1678
+ if (this.scopeJs) {
1679
+ this.sandBox = new SandBox(this);
1680
+ }
1681
+ if (this.container instanceof HTMLElement) {
1682
+ this.container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1683
+ }
1684
+ }
1685
+ get appCacheKey() {
1686
+ return this.url;
1687
+ }
1688
+ get status() {
1689
+ return this.state;
1690
+ }
1691
+ set status(v) {
1692
+ this.state = v;
1693
+ }
1694
+ async start() {
1695
+ if (!this.source || [AppState.UNSET, AppState.ERROR].includes(this.status)) {
1696
+ this.state = AppState.LOADING;
1697
+ if (this.scopeLocation) {
1698
+ const iframe = await this.createIframe();
1699
+ this.iframe = iframe;
1700
+ }
1701
+ this.source = new EntrySource(this.url);
1702
+ await this.source.importEntery(this);
1703
+ }
1704
+ }
1705
+ onMount() {
1706
+ if (this.isPreLoad)
1707
+ return;
1708
+ this.state = AppState.LOADED;
1709
+ this.mount();
1710
+ }
1711
+ onError() {
1712
+ this.state = AppState.ERROR;
1713
+ }
1714
+ mount(container, callback) {
1715
+ this.isPreLoad = false;
1716
+ this.container = container ?? this.container;
1717
+ this.state = AppState.MOUNTING;
1718
+ if (this.container) {
1719
+ if (this.container instanceof Element)
1720
+ this.container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1721
+ const clonedNode = this.source.html.cloneNode(true);
1722
+ const fragment = document.createDocumentFragment();
1723
+ Array.from(clonedNode.childNodes).forEach((node) => {
1724
+ fragment.appendChild(node);
1725
+ });
1726
+ this.container.innerHTML = '';
1727
+ this.container.appendChild(fragment);
1728
+ this.sandBox?.activeated(this.data);
1729
+ execAppScripts(this).finally(() => {
1730
+ this.state = AppState.MOUNTED;
1731
+ callback?.(this);
1732
+ });
1733
+ }
1734
+ }
1735
+ activated(container, callback) {
1736
+ this.isPreLoad = false;
1737
+ this.state = AppState.ACTIVATED;
1738
+ if (container && this.container) {
1739
+ if (container instanceof Element)
1740
+ container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1741
+ const fragment = document.createDocumentFragment();
1742
+ Array.from(this.container.childNodes).forEach((node) => {
1743
+ fragment.appendChild(node);
1744
+ });
1745
+ container.innerHTML = '';
1746
+ container.appendChild(fragment);
1747
+ this.container = container;
1748
+ this.sandBox?.activeated(this.data);
1749
+ callback?.(this);
1750
+ }
1751
+ }
1752
+ deactivated() {
1753
+ this.state = AppState.DEACTIVATED;
1754
+ this.sandBox?.deactivated();
1755
+ }
1756
+ unmount(needDestroy = false) {
1757
+ this.state = AppState.UNMOUNT;
1758
+ this.sandBox?.deactivated();
1759
+ needDestroy && appCache.deleteApp(this.url);
1760
+ this.container.innerHTML = '';
1761
+ this.container = undefined;
1762
+ }
1763
+ createIframe() {
1764
+ return new Promise((resolve) => {
1765
+ const iframe = document.createElement('iframe');
1766
+ const url = new URL(this.url);
1767
+ iframe.setAttribute('src', `about:blank${url.pathname || '/'}${url.search}${url.hash}`);
1768
+ iframe.style.cssText = 'position: fixed; top: -9999px; width: 100%; height: 1px;';
1769
+ document.body.appendChild(iframe);
1770
+ setTimeout(() => resolve(iframe), 100);
1771
+ });
1772
+ }
1773
+ registerRunningApp() {
1774
+ setCurrentRunningApp(this);
1775
+ Promise.resolve().then(() => setCurrentRunningApp(null));
1776
+ }
1777
+ }
1778
+
1779
+ class EntrySource {
1780
+ url;
1781
+ scripts;
1782
+ styles;
1783
+ html = null;
1784
+ rawHtml;
1785
+ constructor(url) {
1786
+ this.url = url;
1787
+ this.scripts = new Map();
1788
+ this.styles = new Map();
1789
+ }
1790
+ async importEntery(app) {
1791
+ let importEntry;
1792
+ if (app.initSource?.length) {
1793
+ // 初始化配置的公共source资源
1794
+ const { collectScript, collectStyle } = await collectSource(app.initSource);
1795
+ if (collectScript) {
1796
+ this.scripts = collectScript;
1797
+ }
1798
+ if (collectStyle) {
1799
+ this.styles = collectStyle;
1800
+ }
1801
+ }
1802
+ if (app instanceof MicroAppModel)
1803
+ importEntry = this.importHtmlEntry(app);
1804
+ else if (app instanceof MicroInstanceModel)
1805
+ importEntry = this.importInstanceEntry();
1806
+ importEntry && await importEntry;
1807
+ }
1808
+ async importHtmlEntry(app) {
1809
+ let htmlStr = appCache.getCacheHtml(this.url);
1810
+ if (!htmlStr) {
1811
+ htmlStr = await fetchSource(this.url, { cache: 'no-cache' });
1812
+ if (!htmlStr) {
1813
+ console.error('load app entry error, pleace check');
1814
+ return Promise.reject();
1815
+ }
1816
+ }
1817
+ this.rawHtml = htmlStr;
1818
+ const wrapElement = createElement$1('div');
1819
+ wrapElement.innerHTML = htmlStr.replace(/<\/?head>/gim, '').replace(/<\/?body>/i, '');
1820
+ this.collectScriptAndStyle(wrapElement, app);
1821
+ await excuteAppStyles(app, wrapElement);
1822
+ this.html = wrapElement;
1823
+ }
1824
+ async importInstanceEntry() {
1825
+ let jsStr = appCache.getCacheScript(this.url)?.code;
1826
+ if (!jsStr) {
1827
+ jsStr = await fetchSource(this.url, { cache: 'no-cache' });
1828
+ }
1829
+ if (!jsStr) {
1830
+ console.error('load app entry error, pleace check');
1831
+ return Promise.reject();
1832
+ }
1833
+ this.scripts.set(this.url, new Script({
1834
+ code: jsStr,
1835
+ async: false,
1836
+ defer: false,
1837
+ url: this.url,
1838
+ isModule: false,
1839
+ fromHtml: true,
1840
+ }));
1841
+ }
1842
+ collectScriptAndStyle(parent, app) {
1843
+ const children = Array.from(parent.children);
1844
+ children.length
1845
+ && children.forEach((child) => {
1846
+ this.collectScriptAndStyle(child, app);
1847
+ });
1848
+ for (const dom of children) {
1849
+ if (dom instanceof HTMLLinkElement) {
1850
+ this.collectLink(dom, parent);
1851
+ }
1852
+ else if (dom instanceof HTMLStyleElement) {
1853
+ if (dom.hasAttribute('exclude')) ;
1854
+ else if (!dom.hasAttribute('ignore')) {
1855
+ this.styles.set(randomUrl(), new Style({
1856
+ code: dom.textContent || '',
1857
+ url: '',
1858
+ fromHtml: true,
1859
+ }));
1860
+ dom.remove();
1861
+ }
1862
+ }
1863
+ else if (dom instanceof HTMLScriptElement) {
1864
+ this.collectScript(dom, parent);
1865
+ }
1866
+ else if (dom instanceof HTMLMetaElement || dom instanceof HTMLTitleElement) {
1867
+ parent.removeChild(dom);
1868
+ }
1869
+ else if (dom instanceof HTMLImageElement && dom.hasAttribute('src')) {
1870
+ dom.setAttribute('src', fillUpPath(dom.getAttribute('src'), this.url));
1871
+ }
1872
+ }
1873
+ }
1874
+ collectLink(link, parent, needReplaceELement = false) {
1875
+ if (link.hasAttribute('exclude')) {
1876
+ return { replace: document.createComment('【bk-weweb】style with exclude attribute is ignored') };
1877
+ }
1878
+ if (link.hasAttribute('ignore')) {
1879
+ return { replace: link };
1880
+ }
1881
+ const rel = link.getAttribute('rel');
1882
+ let href = link.getAttribute('href');
1883
+ let replaceElement;
1884
+ if (rel === 'stylesheet' && href) {
1885
+ href = fillUpPath(href, this.url);
1886
+ replaceElement = document.createComment(`【bk-weweb】style with href=${href}`);
1887
+ let styleInstance = this.getStyle(href);
1888
+ if (!styleInstance) {
1889
+ styleInstance = new Style({
1890
+ code: '',
1891
+ url: href,
1892
+ prefetch: !!link.getAttribute('prefetch'),
1893
+ preload: !!link.getAttribute('preload'),
1894
+ fromHtml: !needReplaceELement,
1895
+ });
1896
+ this.styles.set(href, styleInstance);
1897
+ }
1898
+ !needReplaceELement && parent.replaceChild(replaceElement, link);
1899
+ return { replace: replaceElement, style: styleInstance };
1900
+ }
1901
+ if (rel && ['prefetch', 'preload', 'prerender', 'icon', 'apple-touch-icon'].includes(rel)) {
1902
+ // preload prefetch icon ....
1903
+ replaceElement = document.createComment(`【bk-weweb】style with rel=${rel}${href ? ` & href=${href}` : ''}`);
1904
+ !needReplaceELement && parent.removeChild(link);
1905
+ return { replace: replaceElement };
1906
+ }
1907
+ if (href) {
1908
+ // dns-prefetch preconnect modulepreload search ....
1909
+ link.setAttribute('href', fillUpPath(href, this.url));
1910
+ }
1911
+ return { replace: link };
1912
+ }
1913
+ collectScript(script, parent, needReplaceELement = false) {
1914
+ if (script.hasAttribute('ignore')
1915
+ || (script.hasAttribute('type') && !['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module'].includes(script.type))
1916
+ || (!isSupportModuleScript && script.type === 'module')) {
1917
+ return;
1918
+ }
1919
+ let replaceElement = null;
1920
+ if (script.hasAttribute('exclude')) {
1921
+ replaceElement = document.createComment('【bk-weweb】script element with exclude attribute is removed');
1922
+ !needReplaceELement && parent.replaceChild(replaceElement, script);
1923
+ return { replace: replaceElement };
1924
+ }
1925
+ let src = script.getAttribute('src');
1926
+ if (src) {
1927
+ src = fillUpPath(src, this.url);
1928
+ let scriptInstance = this.getScript(src);
1929
+ if (!scriptInstance) {
1930
+ scriptInstance = new Script({
1931
+ code: '',
1932
+ async: script.hasAttribute('async'),
1933
+ defer: script.defer || script.type === 'module',
1934
+ isModule: script.type === 'module',
1935
+ url: src,
1936
+ fromHtml: !needReplaceELement,
1937
+ });
1938
+ this.scripts.set(src, scriptInstance);
1939
+ }
1940
+ replaceElement = document.createComment(`【bk-weweb】script with src='${src}'`);
1941
+ !needReplaceELement && parent.replaceChild(replaceElement, script);
1942
+ return { replace: replaceElement, script: scriptInstance };
1943
+ }
1944
+ if (script.textContent) {
1945
+ const nonceStr = randomUrl();
1946
+ const scriptInstance = new Script({
1947
+ code: script.textContent,
1948
+ async: false,
1949
+ defer: script.type === 'module',
1950
+ isModule: script.type === 'module',
1951
+ url: nonceStr,
1952
+ fromHtml: !needReplaceELement,
1953
+ });
1954
+ this.scripts.set(nonceStr, scriptInstance);
1955
+ replaceElement = document.createComment('【bk-weweb】script with texcontent');
1956
+ !needReplaceELement && parent.replaceChild(replaceElement, script);
1957
+ return { replace: replaceElement, script: scriptInstance };
1958
+ }
1959
+ return { replace: script };
1960
+ }
1961
+ setScript(url, script) {
1962
+ this.scripts.set(url, new Script(script));
1963
+ }
1964
+ getScript(url) {
1965
+ return this.scripts.get(url);
1966
+ }
1967
+ setStyle(url, style) {
1968
+ this.styles.set(url, style);
1969
+ }
1970
+ getStyle(url) {
1971
+ return this.styles.get(url);
1972
+ }
1973
+ }
1974
+
1975
+ // 所有应用缓存
1976
+ class AppCache {
1977
+ cache;
1978
+ // todo 主应用共享资源包
1979
+ baseSource;
1980
+ constructor() {
1981
+ this.cache = new Map();
1982
+ this.baseSource = new EntrySource(location.href);
1983
+ // this.baseApp = new
1984
+ }
1985
+ get hasActiveApp() {
1986
+ return Array.from(this.cache.values()).some((app) => app.status !== AppState.UNMOUNT);
1987
+ }
1988
+ setApp(app) {
1989
+ this.cache.set(app.appCacheKey, app);
1990
+ }
1991
+ getApp(name) {
1992
+ if (!name)
1993
+ return undefined;
1994
+ const app = this.cache.get(name);
1995
+ if (app)
1996
+ return app;
1997
+ return Array.from(this.cache.values()).find((item) => item.name === name);
1998
+ }
1999
+ getCacheHtml(url) {
2000
+ const list = Array.from(this.cache.values());
2001
+ const app = list.find(item => item.url === url);
2002
+ if (app)
2003
+ return app.source?.rawHtml || '';
2004
+ return '';
2005
+ }
2006
+ getCacheStyle(url) {
2007
+ let style = this.baseSource.getStyle(url);
2008
+ if (style)
2009
+ return;
2010
+ const list = Array.from(this.cache.values());
2011
+ list.some((app) => {
2012
+ style = app.source?.getStyle(url);
2013
+ return !!style;
2014
+ });
2015
+ return style;
2016
+ }
2017
+ getCacheScript(url) {
2018
+ let script = this.baseSource.getScript(url);
2019
+ if (script)
2020
+ return;
2021
+ const list = Array.from(this.cache.values());
2022
+ list.some((app) => {
2023
+ script = app.source?.getScript(url);
2024
+ return !!script;
2025
+ });
2026
+ return script;
2027
+ }
2028
+ deleteApp(url) {
2029
+ this.cache.delete(url);
2030
+ }
2031
+ setBaseAppStyle(url, style) {
2032
+ this.baseSource.setStyle(url, style);
2033
+ }
2034
+ setBaseAppScript(url, script) {
2035
+ this.baseSource.setScript(url, script);
2036
+ }
2037
+ }
2038
+ const appCache = new AppCache();
2039
+ // 注册全局获取缓存app 或者 instance
2040
+ window.__getAppOrInstance__ = function (id) {
2041
+ if (!id)
2042
+ return appCache;
2043
+ return appCache.getApp(id);
2044
+ };
2045
+
2046
+ function getStyleSource(url, style, originLink) {
2047
+ const replaceStyle = createElement$1('style');
2048
+ fetchSource(url)
2049
+ .then((data) => {
2050
+ style.code = data;
2051
+ appCache.setBaseAppStyle(url, style);
2052
+ replaceStyle.textContent = data;
2053
+ dispatchLinkOrScriptLoad(originLink);
2054
+ })
2055
+ .catch((err) => {
2056
+ console.error(err);
2057
+ dispatchLinkOrScriptError(originLink);
2058
+ });
2059
+ return replaceStyle;
2060
+ }
2061
+ function getScriptSource(url, script, originScript) {
2062
+ const replaceElement = createElement$1('script');
2063
+ fetchSource(url)
2064
+ .then((code) => {
2065
+ script.code = code;
2066
+ try {
2067
+ replaceElement.textContent = code;
2068
+ if (!url.startsWith('inline-')) {
2069
+ originScript.setAttribute('origin-src', url);
2070
+ }
2071
+ }
2072
+ catch (e) {
2073
+ console.error(e, url);
2074
+ }
2075
+ dispatchLinkOrScriptLoad(originScript);
2076
+ })
2077
+ .catch((err) => {
2078
+ console.error(err);
2079
+ dispatchLinkOrScriptError(originScript);
2080
+ });
2081
+ return replaceElement;
2082
+ }
2083
+ function rewriteNewNode(child) {
2084
+ if (child instanceof HTMLLinkElement) {
2085
+ const rel = child.getAttribute('rel');
2086
+ let href = child.getAttribute('href');
2087
+ if (rel === 'stylesheet' && href) {
2088
+ href = fillUpPath(href, location.href);
2089
+ const replaceStyle = createElement$1('style');
2090
+ const styleInstance = new Style({
2091
+ code: '',
2092
+ url: href,
2093
+ fromHtml: false,
2094
+ });
2095
+ getStyleSource(href, styleInstance, child);
2096
+ return replaceStyle;
2097
+ }
2098
+ }
2099
+ if (child instanceof HTMLScriptElement) {
2100
+ let src = child.getAttribute('src');
2101
+ if (src && child.type !== 'module') {
2102
+ src = fillUpPath(src, location.href);
2103
+ const script = new Script({
2104
+ code: '',
2105
+ async: child.hasAttribute('async'),
2106
+ defer: child.defer || child.type === 'module',
2107
+ isModule: false,
2108
+ fromHtml: false,
2109
+ });
2110
+ appCache.setBaseAppScript(src, script);
2111
+ const replaceElement = getScriptSource(src, script, child);
2112
+ return replaceElement || child;
2113
+ }
2114
+ }
2115
+ return child;
2116
+ }
2117
+ function baseElementHandle(parent, newChild, passiveChild, rawMethod, baseSource) {
2118
+ if (baseSource) {
2119
+ const targetChild = rewriteNewNode(newChild);
2120
+ return rawMethod.call(parent, targetChild, passiveChild);
2121
+ }
2122
+ return rawMethod.call(parent, newChild, passiveChild);
2123
+ }
2124
+
2125
+ (function () {
2126
+ const rawBodyAppendChild = HTMLBodyElement.prototype.appendChild;
2127
+ const rawHeadAppendChild = HTMLHeadElement.prototype.appendChild;
2128
+ const rawHeadInsertBefore = HTMLHeadElement.prototype.appendChild;
2129
+ HTMLBodyElement.prototype.appendChild = function (newChild) {
2130
+ return baseElementHandle(this, newChild, null, rawBodyAppendChild, true);
2131
+ };
2132
+ HTMLHeadElement.prototype.appendChild = function (newChild) {
2133
+ return baseElementHandle(this, newChild, null, rawHeadAppendChild, true);
2134
+ };
2135
+ HTMLHeadElement.prototype.insertBefore = function (newChild, refChild) {
2136
+ return baseElementHandle(this, newChild, refChild, rawHeadInsertBefore, true);
2137
+ };
2138
+ }());
2139
+ //# sourceMappingURL=collect-source.js.map