@blueking/bk-weweb 0.0.35 → 0.0.36-beta.17

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.esm.js CHANGED
@@ -1,13 +1,33 @@
1
+ // src/common/state.ts
2
+ var AppState = {
3
+ /** 未设置状态 */
4
+ UNSET: "UNSET",
5
+ /** 加载中 */
6
+ LOADING: "LOADING",
7
+ /** 加载完成 */
8
+ LOADED: "LOADED",
9
+ /** 挂载中 */
10
+ MOUNTING: "MOUNTING",
11
+ /** 挂载完成 */
12
+ MOUNTED: "MOUNTED",
13
+ /** 激活状态 */
14
+ ACTIVATED: "ACTIVATED",
15
+ /** 未激活状态 */
16
+ DEACTIVATED: "DEACTIVATED",
17
+ /** 卸载状态 */
18
+ UNMOUNT: "UNMOUNT",
19
+ /** 错误状态 */
20
+ ERROR: "ERROR"
21
+ };
22
+
1
23
  // src/context/cache.ts
2
24
  var currentRunningApp = null;
3
- function getCurrentRunningApp() {
4
- return currentRunningApp;
5
- }
6
- function setCurrentRunningApp(appInstance) {
25
+ var getCurrentRunningApp = () => currentRunningApp;
26
+ var setCurrentRunningApp = (appInstance) => {
7
27
  currentRunningApp = appInstance;
8
- }
28
+ };
9
29
  var windowNativeFuncMap = /* @__PURE__ */ new Map();
10
- var globalContextCode = `const { ${[
30
+ var GLOBAL_CONTEXT_VARIABLES = [
11
31
  "Array",
12
32
  "ArrayBuffer",
13
33
  "Boolean",
@@ -64,15 +84,25 @@ var globalContextCode = `const { ${[
64
84
  "URIError",
65
85
  "valueOf",
66
86
  "WeakMap",
67
- "WeakSet"
68
- ].join(",")} }= this;`;
69
- var getGlobalContextCode = () => {
70
- return globalContextCode;
87
+ "WeakSet",
88
+ "requestAnimationFrame",
89
+ "cancelAnimationFrame",
90
+ "requestIdleCallback",
91
+ "cancelIdleCallback"
92
+ ];
93
+ var getGlobalContextCode = () => `const { ${GLOBAL_CONTEXT_VARIABLES.join(",")} } = this;`;
94
+ var isNativeFunction = (func) => {
95
+ if (typeof func !== "function") return false;
96
+ try {
97
+ return Function.prototype.toString.call(func).includes("[native code]");
98
+ } catch {
99
+ return false;
100
+ }
71
101
  };
72
102
  var collectNativeWindowFunc = () => {
73
- const keyList = Object.getOwnPropertyNames(window);
74
- for (const key of keyList) {
75
- if (!windowNativeFuncMap.has(key) && key.match(/^[A-Z]/) && typeof window[key] === "function" && window[key].toString().includes("[native code]")) {
103
+ const windowKeys = Object.getOwnPropertyNames(window);
104
+ for (const key of windowKeys) {
105
+ if (!windowNativeFuncMap.has(key) && /^[A-Z]/.test(key) && isNativeFunction(window[key])) {
76
106
  windowNativeFuncMap.set(key, true);
77
107
  }
78
108
  }
@@ -93,10 +123,11 @@ var WewebMode = /* @__PURE__ */ ((WewebMode2) => {
93
123
  // src/typings/sandbox.ts
94
124
  var WINDOW_WHITE_LIST = [
95
125
  "System",
96
- // SystemJS
126
+ // SystemJS 模块加载器
97
127
  "__cjsWrapper",
98
- // SystemJS CommonJS wrapper
99
- false ? "__REACT_DEVTOOLS_GLOBAL_HOOK__" : ""
128
+ // SystemJS CommonJS 包装器
129
+ // 开发环境下允许 React DevTools
130
+ ...false ? ["__REACT_DEVTOOLS_GLOBAL_HOOK__"] : []
100
131
  ];
101
132
  var BK_WEWEB_INJECT_KEY_LIST = [
102
133
  "__POWERED_BY_BK_WEWEB__",
@@ -105,909 +136,474 @@ var BK_WEWEB_INJECT_KEY_LIST = [
105
136
  ];
106
137
  var WINDOW_ALIAS_LIST = ["window", "self", "globalThis"];
107
138
  var BK_WEWEB_LOCATION_KEY_LIST = ["location", "history"];
108
- var COMMON_MICRO_APP_WINDOE_KEY_MAP = {
139
+ var COMMON_MICRO_APP_WINDOW_KEY_MAP = {
109
140
  __bk_pop_manager: true,
110
141
  __bk_zIndex_manager: true,
111
142
  i18n: true
112
143
  };
113
- var DEV_MICRO_APP_WINDOE_KEY_MAP = false ? {
144
+ var DEV_MICRO_APP_WINDOW_KEY_MAP = false ? {
145
+ // 开发环境标识
114
146
  __DEV__: true,
147
+ // Vue DevTools 相关
115
148
  __VUE_DEVTOOLS_GLOBAL_HOOK__: true,
116
149
  __VUE_DEVTOOLS_HOOK_REPLAY__: true,
117
150
  __VUE_DEVTOOLS_PLUGINS__: true,
151
+ // Vue I18n 相关
118
152
  __VUE_I18N_FULL_INSTALL__: true,
119
153
  __VUE_I18N_LEGACY_API__: true,
154
+ // Vue 配置相关
120
155
  __VUE_OPTIONS_API__: true,
156
+ // Core-js 相关
121
157
  "__core-js_shared__": true,
158
+ // Webpack 相关
122
159
  webpackChunkapm: true,
123
160
  webpackChunkpc: true,
124
161
  webpackChunktrace: true,
125
162
  webpackJsonp: true,
126
- ...COMMON_MICRO_APP_WINDOE_KEY_MAP
127
- } : COMMON_MICRO_APP_WINDOE_KEY_MAP;
163
+ // 包含通用配置
164
+ ...COMMON_MICRO_APP_WINDOW_KEY_MAP
165
+ } : COMMON_MICRO_APP_WINDOW_KEY_MAP;
128
166
 
129
167
  // src/utils/common.ts
168
+ var PROTOCOL_REGEX = /^((((ht|f)tps?)|file):)?\/\//;
169
+ var DATA_BLOB_REGEX = /^(data|blob):/;
170
+ var FILE_EXTENSION_REGEX = /\.(\w+)$/;
171
+ var JS_EXTENSION_REGEX = /\.js$/;
172
+ var RANDOM_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
130
173
  var nextTask = (cb) => Promise.resolve().then(cb);
131
- function addUrlProtocol(url) {
174
+ var addUrlProtocol = (url) => {
132
175
  if (url.startsWith("//")) return `${location.protocol}${url}`;
133
176
  if (!url.startsWith("http")) return `${location.protocol}//${url}`;
134
177
  return url;
135
- }
136
- function fillUpPath(path, baseURI) {
137
- if (!path || /^((((ht|f)tps?)|file):)?\/\//.test(path) || /^(data|blob):/.test(path)) return path;
178
+ };
179
+ var fillUpPath = (path, baseURI) => {
180
+ if (!path || PROTOCOL_REGEX.test(path) || DATA_BLOB_REGEX.test(path)) {
181
+ return path;
182
+ }
138
183
  const { origin, pathname } = new URL(addUrlProtocol(baseURI));
139
- return new URL(path, `${origin}${pathname}`.replace(/\.(\w+)$/, "/")).toString();
140
- }
141
- function randomUrl() {
142
- return `inline-${random(16)}`;
143
- }
144
- var requestIdleCallback = window.requestIdleCallback || ((cb) => {
184
+ const basePath = `${origin}${pathname}`.replace(FILE_EXTENSION_REGEX, "/");
185
+ return new URL(path, basePath).toString();
186
+ };
187
+ var random = (length, chars = RANDOM_CHARS) => {
188
+ const charsLength = chars.length;
189
+ return Array.from({ length }, () => chars[Math.floor(Math.random() * charsLength)]).join("");
190
+ };
191
+ var randomUrl = () => `inline-${random(16)}`;
192
+ var requestIdleCallback = window.requestIdleCallback ?? ((cb) => {
145
193
  const start = Date.now();
146
194
  return setTimeout(() => {
147
195
  cb({
148
196
  didTimeout: false,
149
- timeRemaining() {
150
- return Math.max(0, 50 - (Date.now() - start));
151
- }
197
+ timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
152
198
  });
153
199
  }, 1);
154
200
  });
155
- var cancelIdleCallback = window.cancelIdleCallback || ((id) => {
156
- clearTimeout(id);
157
- });
158
- var random = (n, str = "abcdefghijklmnopqrstuvwxyz0123456789") => {
159
- let result = "";
160
- for (let i = 0; i < n; i++) {
161
- result += str[Number.parseInt((Math.random() * str.length).toString(), 10)];
162
- }
163
- return result;
164
- };
201
+ var cancelIdleCallback = window.cancelIdleCallback ?? ((id) => clearTimeout(id));
165
202
  var isJsonpUrl = (url) => {
166
203
  if (!url) return false;
167
- if (url.match(/\.js$/)) return false;
168
- const { pathname } = new URL(addUrlProtocol(url));
169
- return !pathname.match(/\.js$/);
204
+ try {
205
+ const { pathname } = new URL(addUrlProtocol(url));
206
+ return !JS_EXTENSION_REGEX.test(pathname);
207
+ } catch {
208
+ return !JS_EXTENSION_REGEX.test(url);
209
+ }
170
210
  };
171
211
 
172
- // src/context/document.ts
173
- var SPECIAL_ELEMENT_TAG = ["body", "html", "head"];
174
- var createProxyDocument = (rawDocument, app) => {
175
- const fakeDocument = {};
176
- function shadowRootInsertAdjacentHTML(where, domString) {
177
- const temporaryContainer = document.createElement("div");
178
- temporaryContainer.innerHTML = domString;
179
- const elements = Array.from(temporaryContainer.childNodes);
180
- const shadow = app.container;
181
- switch (where) {
182
- case "beforebegin":
183
- elements.forEach((el) => shadow.host.parentNode?.insertBefore(el, shadow.host));
184
- break;
185
- case "afterbegin":
186
- elements.reverse().forEach((el) => shadow.insertBefore(el, shadow.firstChild));
187
- break;
188
- case "beforeend":
189
- elements.forEach((el) => shadow.appendChild(el));
190
- break;
191
- case "afterend":
192
- elements.forEach((el) => shadow.host.parentNode?.insertBefore(el, shadow.host.nextSibling));
193
- break;
194
- }
212
+ // src/utils/custom.ts
213
+ var ELEMENT_TARGET_NAMES = ["currentTarget", "srcElement", "target"];
214
+ var defineEventSourceElement = (element, eventName = "custom") => {
215
+ const targetProperties = ELEMENT_TARGET_NAMES.reduce((properties, targetName) => {
216
+ properties[targetName] = {
217
+ get: () => element,
218
+ enumerable: true,
219
+ configurable: true
220
+ };
221
+ return properties;
222
+ }, {});
223
+ return Object.defineProperties(new CustomEvent(eventName), targetProperties);
224
+ };
225
+ var dispatchLinkOrScriptLoad = (element) => {
226
+ const loadEvent = defineEventSourceElement(element, "load");
227
+ if (typeof element.onload === "function") {
228
+ element.onload.call(element, loadEvent);
229
+ return;
195
230
  }
196
- const proxyBody = new Proxy(
197
- {},
198
- {
199
- get(_, key) {
200
- if (app.container instanceof ShadowRoot) {
201
- if (key === "insertAdjacentHTML") {
202
- return shadowRootInsertAdjacentHTML.bind(app.container);
203
- }
204
- const value2 = app.container[key];
205
- if (typeof value2 === "function") {
206
- return value2.bind(app.container);
207
- }
208
- if (value2 !== void 0) {
209
- return value2;
210
- }
211
- }
212
- const value = Reflect.get(rawDocument.body, key);
213
- return typeof value === "function" ? value.bind(rawDocument.body) : value;
214
- },
215
- set(_, key, value) {
216
- if (app.container instanceof ShadowRoot) {
217
- app.container[key] = value;
218
- return true;
219
- }
220
- Reflect.set(rawDocument.body, key, value);
221
- return true;
222
- }
223
- }
224
- );
225
- function createElement(tagName, options) {
226
- const element = rawDocument.createElement(tagName, options);
227
- element.__BK_WEWEB_APP_KEY__ = app.appCacheKey;
228
- return element;
231
+ element.dispatchEvent(loadEvent);
232
+ };
233
+ var dispatchLinkOrScriptError = (element) => {
234
+ const errorEvent = defineEventSourceElement(element, "error");
235
+ if (typeof element.onerror === "function") {
236
+ element.onerror.call(element, errorEvent);
237
+ return;
229
238
  }
230
- function querySelectorNew(selectors) {
231
- if (selectors === proxyBody) {
232
- return app.container instanceof ShadowRoot ? app.container : rawDocument.body;
233
- }
234
- if (SPECIAL_ELEMENT_TAG.includes(selectors)) {
235
- if (app?.container instanceof ShadowRoot) {
236
- return app?.container;
237
- }
238
- return rawDocument.querySelector.call(this, selectors);
239
- }
239
+ element.dispatchEvent(errorEvent);
240
+ };
241
+
242
+ // src/utils/fetch.ts
243
+ var fetchSource = async (url, options = {}, app) => {
244
+ if (typeof app?.fetchSource === "function") {
240
245
  try {
241
- return app?.container?.querySelector(selectors) ?? null;
246
+ return await app.fetchSource(url, options);
242
247
  } catch {
243
- return null;
248
+ return "";
244
249
  }
245
250
  }
246
- function querySelectorAllNew(selectors) {
247
- if (SPECIAL_ELEMENT_TAG.includes(selectors)) {
248
- if (app?.container instanceof ShadowRoot) {
249
- return app?.container;
250
- }
251
- return rawDocument.querySelector(selectors);
252
- }
253
- return app?.container?.querySelectorAll(selectors) ?? [];
251
+ if (src_default.fetchSource) {
252
+ return src_default.fetchSource(url, options);
254
253
  }
255
- function getElementByIdNew(key) {
256
- return querySelectorNew.call(rawDocument, `#${key}`);
254
+ try {
255
+ const response = await window.fetch(url, options);
256
+ return await response.text();
257
+ } catch {
258
+ return "";
257
259
  }
258
- function getElementsByClassName(key) {
259
- return querySelectorAllNew(`.${key}`);
260
+ };
261
+
262
+ // src/entry/style.ts
263
+ var CSS_SELECTORS = {
264
+ ROOT_SELECTOR: /^((html[\s>~,]+body)|(html|body|:root))$/,
265
+ BUILT_IN_ROOT_SELECTOR: /(^|\s+)((html[\s>~]+body)|(html|body|:root))(?=[\s>~]+|$)/,
266
+ FONT_FACE: /@font-face\s*\{[^}]+\}/g,
267
+ URL_PATTERN: /url\(["']?([^)"']+)["']?\)/gm,
268
+ DATA_BLOB_PROTOCOL: /^(data|blob):/,
269
+ HTTP_PROTOCOL: /^(https?:)?\/\//,
270
+ RELATIVE_PATH: /^((\.\.?\/)|[^/])/,
271
+ ROOT_HOST_PATTERN: /(:?:root|html)/gm
272
+ };
273
+ var STYLE_ATTRIBUTES = {
274
+ TYPE: "text/css",
275
+ POWERED_BY: "bk-weweb",
276
+ LINKED_FROM_BASE: "linked-from-base",
277
+ ORIGIN_SRC: "origin-src"
278
+ };
279
+ var PACK_RULE_NAMES = {
280
+ MEDIA: "media",
281
+ SUPPORTS: "supports"
282
+ };
283
+ var Style = class {
284
+ code = "";
285
+ fromHtml;
286
+ initial;
287
+ prefetch = false;
288
+ preload = false;
289
+ scoped;
290
+ scopedCode = "";
291
+ url;
292
+ constructor({ code, fromHtml, initial, prefetch, preload, url }) {
293
+ this.scoped = false;
294
+ this.code = code;
295
+ this.prefetch = prefetch ?? false;
296
+ this.preload = preload ?? false;
297
+ this.url = url;
298
+ this.fromHtml = fromHtml;
299
+ this.initial = initial ?? false;
260
300
  }
261
- function getElementsByTagName(key) {
262
- if (SPECIAL_ELEMENT_TAG.includes(key) || !app?.showSourceCode && key.toLocaleLowerCase() === "script") {
263
- return rawDocument.getElementsByTagName(key);
301
+ /**
302
+ * 通用样式作用域处理
303
+ * @param styleElement 样式元素
304
+ * @param app 应用实例
305
+ */
306
+ commonScoped(styleElement, app) {
307
+ if (app.scopeCss && !(app.container instanceof ShadowRoot)) {
308
+ this.applyScopedCSS(styleElement, app);
309
+ } else {
310
+ this.applyUnscopedCSS(styleElement, app);
264
311
  }
265
- return querySelectorAllNew(key);
312
+ this.scoped = true;
266
313
  }
267
- function getElementsByNameNew(key) {
268
- return querySelectorAllNew(`[name=${key}]`);
314
+ /**
315
+ * 创建样式元素
316
+ */
317
+ createStyleElement() {
318
+ const styleElement = document.createElement("style");
319
+ if (styleElement.__BK_WEWEB_APP_KEY__) {
320
+ styleElement.__BK_WEWEB_APP_KEY__ = void 0;
321
+ }
322
+ return styleElement;
269
323
  }
270
- return new Proxy(fakeDocument, {
271
- get(_, key) {
272
- if (key === "createElement") {
273
- return createElement.bind(rawDocument);
274
- }
275
- if (key === "querySelector") {
276
- return querySelectorNew.bind(rawDocument);
277
- }
278
- if (key === "querySelectorAll") {
279
- return querySelectorAllNew.bind(rawDocument);
280
- }
281
- if (key === "getElementById") {
282
- return getElementByIdNew.bind(rawDocument);
283
- }
284
- if (key === "getElementsByClassName") {
285
- return getElementsByClassName.bind(rawDocument);
286
- }
287
- if (key === "getElementsByTagName") {
288
- return getElementsByTagName.bind(rawDocument);
324
+ /**
325
+ * 执行样式代码
326
+ * @param app 应用实例
327
+ * @returns 返回执行后的style标签
328
+ */
329
+ async executeCode(app) {
330
+ app.registerRunningApp();
331
+ let styleElement = this.createStyleElement();
332
+ styleElement.setAttribute("type", STYLE_ATTRIBUTES.TYPE);
333
+ styleElement.textContent = this.code;
334
+ try {
335
+ if (!this.code) {
336
+ await this.getCode(app);
289
337
  }
290
- if (key === "getElementsByName") {
291
- return getElementsByNameNew.bind(rawDocument);
338
+ styleElement = this.scopedStyleCSS(app, styleElement);
339
+ this.scoped = true;
340
+ } catch (error) {
341
+ console.error("scoped style error", error);
342
+ }
343
+ return styleElement;
344
+ }
345
+ /**
346
+ * 获取样式代码
347
+ */
348
+ async getCode(app) {
349
+ if (this.code.length || !this.url) {
350
+ return this.code;
351
+ }
352
+ const code = this.getCodeFromAppSource(app) || this.getCodeFromCache() || await this.fetchCodeFromRemote(app);
353
+ this.code = code;
354
+ return code;
355
+ }
356
+ /**
357
+ * 检查并链接基础应用样式
358
+ * @param styleElement 样式元素
359
+ * @param app 应用实例
360
+ * @returns 是否已链接基础样式
361
+ */
362
+ linkedBaseStyle(styleElement, app) {
363
+ if (!(app.container instanceof ShadowRoot) && styleElement.textContent && appCache.getBaseAppStyle(styleElement.textContent)) {
364
+ this.clearStyleElement(styleElement);
365
+ styleElement.setAttribute(STYLE_ATTRIBUTES.LINKED_FROM_BASE, "true");
366
+ return true;
367
+ }
368
+ return false;
369
+ }
370
+ /**
371
+ * 重置包装规则
372
+ */
373
+ resetPackRule(rule, prefix, packName) {
374
+ const result = this.scopeRule(Array.from(rule.cssRules), prefix);
375
+ return `@${packName} ${rule.conditionText} {${result}}`;
376
+ }
377
+ /**
378
+ * 重置URL地址
379
+ */
380
+ resetUrlHost(cssText, uri, linkPath) {
381
+ let baseURI = uri;
382
+ return cssText.replace(CSS_SELECTORS.URL_PATTERN, (text, matchedUrl) => {
383
+ if (CSS_SELECTORS.DATA_BLOB_PROTOCOL.test(matchedUrl) || CSS_SELECTORS.HTTP_PROTOCOL.test(matchedUrl)) {
384
+ return text;
292
385
  }
293
- if (key === "body") {
294
- return proxyBody;
386
+ if (CSS_SELECTORS.RELATIVE_PATH.test(matchedUrl) && linkPath) {
387
+ baseURI = this.buildBaseURI(linkPath);
295
388
  }
296
- const result = Reflect.get(rawDocument, key);
297
- if (typeof result === "function") {
298
- return result.bind(rawDocument);
389
+ return `url("${fillUpPath(matchedUrl, baseURI)}")`;
390
+ });
391
+ }
392
+ /**
393
+ * css rule 处理
394
+ */
395
+ scopeRule(rules, cssPrefix) {
396
+ let result = "";
397
+ for (const rule of rules) {
398
+ switch (rule.type) {
399
+ case 1 /* STYLE_RULE */:
400
+ result += this.scopeStyleRule(rule, cssPrefix);
401
+ break;
402
+ case 4 /* MEDIA_RULE */:
403
+ result += this.resetPackRule(rule, cssPrefix, PACK_RULE_NAMES.MEDIA);
404
+ break;
405
+ case 12 /* SUPPORTS_RULE */:
406
+ result += this.resetPackRule(rule, cssPrefix, PACK_RULE_NAMES.SUPPORTS);
407
+ break;
408
+ default:
409
+ result += rule.cssText;
410
+ break;
299
411
  }
300
- return result;
301
- }
302
- });
303
- };
304
-
305
- // src/context/event.ts
306
- function rewriteDocumentAndBodyEvent() {
307
- const { addEventListener, removeEventListener } = window.document;
308
- const { addEventListener: bodyAddEventListener, removeEventListener: bodyRemoveEventListener } = window.document.body;
309
- const documentListenerMap = /* @__PURE__ */ new Map();
310
- document.addEventListener = function(type, listener, options) {
311
- const app = getCurrentRunningApp();
312
- if (app?.keepAlive) {
313
- const listeners = documentListenerMap.get(type) || [];
314
- documentListenerMap.set(type, [...listeners, listener]);
315
412
  }
316
- addEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
317
- };
318
- document.body.addEventListener = document.addEventListener;
319
- document.removeEventListener = function(type, listener, options) {
320
- const app = getCurrentRunningApp();
321
- if (app?.keepAlive) {
322
- const listeners = documentListenerMap.get(type) || [];
323
- if (listeners.length && listeners.some((l) => l === listener)) {
324
- listeners.splice(listeners.indexOf(listener), 1);
325
- }
413
+ return result.replace(/^\s+/, "");
414
+ }
415
+ /**
416
+ * style rule 处理
417
+ */
418
+ scopeStyleRule(rule, prefix) {
419
+ const { cssText, selectorText } = rule;
420
+ if (CSS_SELECTORS.ROOT_SELECTOR.test(selectorText)) {
421
+ return cssText.replace(CSS_SELECTORS.ROOT_SELECTOR, prefix);
326
422
  }
327
- removeEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
328
- };
329
- document.body.removeEventListener = document.removeEventListener;
330
- function resetDocumentAndBodyEvent() {
331
- const app = getCurrentRunningApp();
332
- if (app?.keepAlive && documentListenerMap.values()) {
333
- Array.from(documentListenerMap.entries()).forEach(([type, listeners]) => {
334
- listeners?.forEach((listener) => {
335
- document.removeEventListener.call(document, type, listener);
336
- });
337
- });
423
+ if (selectorText === "*") {
424
+ return cssText.replace("*", `${prefix} *`);
338
425
  }
339
- document.addEventListener = addEventListener;
340
- document.body.addEventListener = bodyAddEventListener;
341
- document.removeEventListener = removeEventListener;
342
- document.body.removeEventListener = bodyRemoveEventListener;
343
- documentListenerMap.clear();
426
+ return cssText.replace(
427
+ /^[\s\S]+{/,
428
+ (selectors) => selectors.replace(/(^|,)([^,]+)/g, (all, delimiter, selector) => {
429
+ if (CSS_SELECTORS.BUILT_IN_ROOT_SELECTOR.test(selector)) {
430
+ return all.replace(CSS_SELECTORS.BUILT_IN_ROOT_SELECTOR, prefix);
431
+ }
432
+ return `${delimiter} ${prefix} ${selector.replace(/^\s*/, "")}`;
433
+ })
434
+ );
344
435
  }
345
- return {
346
- resetDocumentAndBodyEvent
347
- };
348
- }
349
-
350
- // src/context/function.ts
351
- var CLASS_REGEX = /^class\b/;
352
- var COMMON_CONTRUCT_FU_REGEX = /^function\b\s[A-Z].*/;
353
- var ConstructFunCacheMap = /* @__PURE__ */ new WeakMap();
354
- function isConstructFun(fn) {
355
- if (fn.prototype?.constructor === fn && Object.getOwnPropertyNames(fn.prototype).length > 1) {
356
- return true;
357
- }
358
- if (ConstructFunCacheMap.has(fn)) {
359
- return ConstructFunCacheMap.get(fn);
360
- }
361
- const constructable = COMMON_CONTRUCT_FU_REGEX.test(fn.toString()) || CLASS_REGEX.test(fn.toString());
362
- ConstructFunCacheMap.set(fn, constructable);
363
- return constructable;
364
- }
365
- var functionBoundedValueMap = /* @__PURE__ */ new WeakMap();
366
- function bindFunctionToRawWindow(rawWindow, value) {
367
- if (functionBoundedValueMap.has(value)) {
368
- return functionBoundedValueMap.get(value);
369
- }
370
- if (typeof value === "function" && !isConstructFun(value)) {
371
- const boundValue = Function.prototype.bind.call(value, rawWindow);
372
- for (const key in value) {
373
- boundValue[key] = value[key];
374
- }
375
- if (value.hasOwnProperty("prototype") && !boundValue.hasOwnProperty("prototype")) {
376
- Object.defineProperty(boundValue, "prototype", { enumerable: false, value: value.prototype, writable: true });
377
- }
378
- if (typeof value.toString === "function") {
379
- const valueHasInstanceToString = value.hasOwnProperty("toString") && !boundValue.hasOwnProperty("toString");
380
- const boundValueHasPrototypeToString = boundValue.toString === Function.prototype.toString;
381
- if (valueHasInstanceToString || boundValueHasPrototypeToString) {
382
- const originToStringDescriptor = Object.getOwnPropertyDescriptor(
383
- valueHasInstanceToString ? value : Function.prototype,
384
- "toString"
385
- );
386
- Object.defineProperty(boundValue, "toString", {
387
- ...originToStringDescriptor,
388
- ...originToStringDescriptor?.get ? null : { value: () => value.toString() }
389
- });
436
+ /**
437
+ * link style 处理
438
+ */
439
+ scopedLinkCSS(app, linkElement) {
440
+ const styleElement = this.createStyleElement();
441
+ styleElement.setAttribute("type", STYLE_ATTRIBUTES.TYPE);
442
+ const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
443
+ setMarkElement(styleElement, app, needKeepAlive);
444
+ const container = needKeepAlive ? document.head : app.container;
445
+ try {
446
+ if (this.code) {
447
+ this.handleExistingCode(styleElement, app, container, linkElement);
448
+ } else if (linkElement.getAttribute("href")) {
449
+ this.handleHrefAttribute(styleElement, app, container, linkElement);
450
+ } else {
451
+ this.handleMissingHref(styleElement, app, container, linkElement);
390
452
  }
453
+ } catch {
454
+ linkElement && dispatchLinkOrScriptError(linkElement);
391
455
  }
392
- functionBoundedValueMap.set(value, boundValue);
393
- return boundValue;
456
+ return styleElement;
394
457
  }
395
- return value;
396
- }
397
-
398
- // src/context/window.ts
399
- function rewriteWindowFunction(fakeWindow) {
400
- const windowEventLisenerMap = /* @__PURE__ */ new Map();
401
- const intervalTimerList = [];
402
- const rawWindow = window;
403
- const { addEventListener, clearInterval: clearInterval2, removeEventListener, setInterval: setInterval2 } = window;
404
- fakeWindow.addEventListener = (type, listener, options) => {
405
- windowEventLisenerMap.set(type, [...windowEventLisenerMap.get(type) || [], listener]);
406
- addEventListener.call(rawWindow, type, listener, options);
407
- };
408
- fakeWindow.removeEventListener = (type, listener, options) => {
409
- const listenerList = windowEventLisenerMap.get(type);
410
- if (listenerList?.length) {
411
- const index = listenerList.indexOf(listener);
412
- index > -1 && listenerList.splice(index, 1);
413
- }
414
- removeEventListener.call(rawWindow, type, listener, options);
415
- };
416
- fakeWindow.setInterval = (handler, timeout, ...args) => {
417
- const timer = setInterval2.call(rawWindow, handler, timeout, ...args);
418
- intervalTimerList.push(timer);
419
- return timer;
420
- };
421
- fakeWindow.clearInterval = (timer) => {
422
- const index = intervalTimerList.indexOf(timer);
423
- index > -1 && intervalTimerList.splice(index, 1);
424
- clearInterval2.call(rawWindow, timer);
425
- };
426
- function resetWindowFunction() {
427
- if (windowEventLisenerMap.size) {
428
- windowEventLisenerMap.forEach((listenerList, type) => {
429
- listenerList.forEach((listener) => removeEventListener.call(rawWindow, type, listener));
430
- });
431
- windowEventLisenerMap.clear();
458
+ /**
459
+ * 隔离 style
460
+ */
461
+ scopedStyleCSS(app, styleElement) {
462
+ const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
463
+ setMarkElement(styleElement, app, needKeepAlive);
464
+ if (this.code || styleElement.textContent) {
465
+ this.processExistingContent(styleElement, app);
466
+ } else {
467
+ this.observeContentChanges(styleElement, app);
432
468
  }
433
- if (intervalTimerList.length) {
434
- intervalTimerList.forEach((timer) => {
435
- clearInterval2.call(rawWindow, timer);
436
- });
469
+ if (this.url) {
470
+ styleElement.setAttribute(STYLE_ATTRIBUTES.ORIGIN_SRC, this.url);
437
471
  }
472
+ return styleElement;
438
473
  }
439
- return {
440
- resetWindowFunction
441
- };
442
- }
443
-
444
- // src/context/sandbox.ts
445
- var SandBox = class {
446
- constructor(app) {
447
- this.app = app;
448
- const windowDescriptorSet = /* @__PURE__ */ new Set();
449
- const rawWindow = window;
450
- this.rawWindow = rawWindow;
451
- this.rawDocument = createProxyDocument(document, app);
452
- const fakeWindow = /* @__PURE__ */ Object.create({});
453
- fakeWindow.__BK_WEWEB_APP_KEY__ = app.appCacheKey;
454
- fakeWindow.__POWERED_BY_BK_WEWEB__ = true;
455
- fakeWindow.rawDocument = document;
456
- fakeWindow.rawWindow = rawWindow;
457
- fakeWindow.__proto__ = Window;
458
- this.fakeWindow = fakeWindow;
459
- const { resetWindowFunction } = rewriteWindowFunction(this.fakeWindow);
460
- this.resetWindowFunction = resetWindowFunction;
461
- this.windowSymbolKey = `__${(app.name || app.appCacheKey).replace(/(-|,|:|~|'|")/gim, "_")}_${random(
462
- 10
463
- )}__`;
464
- this.proxyWindow = new Proxy(this.fakeWindow, {
465
- // Object.defineProperty(window, key, Descriptor)
466
- defineProperty: (target, key, value) => {
467
- if (windowDescriptorSet.has(key)) {
468
- return Reflect.defineProperty(rawWindow, key, value);
469
- }
470
- return Reflect.defineProperty(target, key, value);
471
- },
472
- deleteProperty: (target, key) => {
473
- if (Object.hasOwn(target, key)) {
474
- this.sameRawWindowKeySet.has(key) && this.sameRawWindowKeySet.delete(key);
475
- this.inRawWindowKeySet.has(key) && Reflect.deleteProperty(rawWindow, key);
476
- return Reflect.deleteProperty(target, key);
477
- }
478
- return true;
479
- },
480
- get: (target, key) => {
481
- if (key === Symbol.unscopables || windowNativeFuncMap.has(key)) return rawWindow[key];
482
- if (DEV_MICRO_APP_WINDOE_KEY_MAP[key]) return this.fakeWindow[key];
483
- if (WINDOW_ALIAS_LIST.includes(key)) return this.proxyWindow;
484
- if (key === "document") {
485
- app.registerRunningApp();
486
- return this.rawDocument;
487
- }
488
- if (key === "eval") {
489
- app.registerRunningApp();
490
- return eval;
491
- }
492
- if (BK_WEWEB_LOCATION_KEY_LIST.includes(key) && this.app instanceof MicroAppModel && this.app.iframe && this.app.scopeLocation) {
493
- return this.app.iframe.contentWindow?.[key];
494
- }
495
- if (key === "hasOwnProperty")
496
- return (key2) => Object.hasOwn(this.fakeWindow, key2) || Object.hasOwn(rawWindow, key2);
497
- if (key === "top" || key === "parent") {
498
- if (rawWindow === rawWindow.parent) {
499
- return this.proxyWindow;
500
- }
501
- return Reflect.get(rawWindow, key);
502
- }
503
- if (key === "getComputedStyle") {
504
- return (element, pseudoElt) => {
505
- if (element instanceof Element) {
506
- return rawWindow.getComputedStyle(element, pseudoElt);
507
- }
508
- return rawWindow.getComputedStyle(document.body, pseudoElt);
509
- };
510
- }
511
- if (Reflect.has(target, key) || BK_WEWEB_INJECT_KEY_LIST.includes(key)) return Reflect.get(target, key);
512
- const rawValue = Reflect.get(rawWindow, key);
513
- return bindFunctionToRawWindow(rawWindow, rawValue);
514
- },
515
- getOwnPropertyDescriptor: (target, key) => {
516
- if (Object.hasOwn(target, key)) {
517
- return Object.getOwnPropertyDescriptor(target, key);
518
- }
519
- if (Object.hasOwn(rawWindow, key)) {
520
- windowDescriptorSet.add(key);
521
- const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
522
- if (descriptor && !descriptor.configurable) {
523
- descriptor.configurable = true;
524
- }
525
- return descriptor;
526
- }
527
- return void 0;
528
- },
529
- has: (target, key) => windowNativeFuncMap.has(key) || key in target || key in rawWindow,
530
- // Object.getOwnPropertyNames(window)
531
- ownKeys: (target) => Array.from(new Set(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)))),
532
- set: (target, key, value) => {
533
- if (this.active) {
534
- if (BK_WEWEB_LOCATION_KEY_LIST.includes(key) && this.app instanceof MicroAppModel && this.app.iframe && this.app.scopeLocation) {
535
- return Reflect.set(this.app.iframe.contentWindow, key, value);
536
- }
537
- if (key === "location") {
538
- Reflect.set(rawWindow, key, value);
539
- } else if (!Object.hasOwn(target, key) && Object.hasOwn(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
540
- const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
541
- const { configurable, enumerable, writable } = descriptor;
542
- if (writable) {
543
- Object.defineProperty(target, key, {
544
- configurable,
545
- enumerable,
546
- value,
547
- writable
548
- });
549
- this.sameRawWindowKeySet.add(key);
550
- }
551
- } else {
552
- Reflect.set(target, key, value);
553
- this.sameRawWindowKeySet.add(key);
554
- }
555
- if (WINDOW_WHITE_LIST.includes(key) && !Reflect.has(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
556
- Reflect.set(rawWindow, key, value);
557
- this.inRawWindowKeySet.add(key);
558
- }
559
- }
560
- return true;
561
- }
562
- });
563
- rawWindow[this.windowSymbolKey] = this.proxyWindow;
564
- }
565
- active = false;
566
- inRawWindowKeySet = /* @__PURE__ */ new Set();
567
- resetDocumentAndBodyEvent;
568
- resetWindowFunction;
569
- sameRawWindowKeySet = /* @__PURE__ */ new Set();
570
- fakeWindow;
571
- proxyDocument;
572
- proxyWindow;
573
- rawDocument;
574
- rawWindow;
575
- windowSymbolKey;
576
474
  /**
577
- *
578
- * @param data data for sandbox
579
- * @description active hook for sandbox
475
+ * 应用隔离 style
580
476
  */
581
- activated(data) {
582
- if (!this.active) {
583
- this.active = true;
584
- this.rawDocument = createProxyDocument(document, this.app);
585
- this.fakeWindow.__BK_WEWEB_DATA__ = data ?? {};
586
- const { resetDocumentAndBodyEvent } = rewriteDocumentAndBodyEvent();
587
- this.resetDocumentAndBodyEvent = resetDocumentAndBodyEvent;
588
- }
477
+ applyScopedCSS(styleElement, app) {
478
+ const cssStyleSheet = new CSSStyleSheet({ disabled: true });
479
+ cssStyleSheet.replaceSync(styleElement.textContent || this.code);
480
+ const rules = Array.from(cssStyleSheet?.cssRules ?? []);
481
+ const cssPrefix = `#${app.name}`;
482
+ const scopedCss = this.scopeRule(rules, cssPrefix);
483
+ const cssText = this.resetUrlHost(scopedCss, app.url, this.url);
484
+ styleElement.textContent = cssText;
485
+ this.scopedCode = cssText;
486
+ }
487
+ applyUnscopedCSS(styleElement, app) {
488
+ const cssText = this.resetUrlHost(styleElement.textContent || this.code || "", app.url, this.url);
489
+ if (cssText && app.container instanceof ShadowRoot) {
490
+ this.handleShadowRootFonts(cssText, app);
491
+ }
492
+ styleElement.textContent = cssText.replace(CSS_SELECTORS.ROOT_HOST_PATTERN, ":host");
589
493
  }
590
494
  /**
591
- *
592
- * @description decativated hook for sandbox
495
+ * 处理ShadowRoot中的字体
593
496
  */
594
- deactivated() {
595
- if (!this.active) return;
596
- this.active = false;
597
- this.resetWindowFunction();
598
- for (const key of this.inRawWindowKeySet) {
599
- Reflect.deleteProperty(window, key);
600
- }
601
- this.inRawWindowKeySet.clear();
602
- this.resetDocumentAndBodyEvent?.();
603
- }
604
- };
605
-
606
- // src/utils/custom.ts
607
- var ELEMENT_TARGET_NAME = ["currentTarget", "srcElement", "target"];
608
- function defineEventSourceElement(element, eventName = "custom") {
609
- return Object.defineProperties(
610
- new CustomEvent(eventName),
611
- ELEMENT_TARGET_NAME.reduce((props, name) => {
612
- props[name] = {
613
- get() {
614
- return element;
615
- }
616
- };
617
- return props;
618
- }, {})
619
- );
620
- }
621
- function dispatchLinkOrScriptLoad(element) {
622
- const event = defineEventSourceElement(element, "load");
623
- if (typeof element.onload === "function") {
624
- element.onload(event);
625
- return;
626
- }
627
- element.dispatchEvent(event);
628
- }
629
- function dispatchLinkOrScriptError(element) {
630
- const event = defineEventSourceElement(element, "error");
631
- if (typeof element.onerror === "function") {
632
- element.onerror(event);
633
- return;
634
- }
635
- element.dispatchEvent(event);
636
- }
637
-
638
- // src/utils/element.ts
639
- var { appendChild: bodyAppendChild } = HTMLBodyElement.prototype;
640
- function resetNewElement(parent, child, app) {
641
- if (child instanceof HTMLStyleElement) {
642
- if (child.hasAttribute("exclude")) {
643
- return document.createComment("\u3010bk-weweb\u3011style with exclude attribute is ignored");
644
- }
645
- if (child.textContent) {
646
- if (!(app.container instanceof ShadowRoot) && appCache.getBaseAppStyle(child.textContent)) {
647
- return document.createComment("\u3010bk-weweb\u3011style is effective in base app");
648
- }
649
- }
650
- if (!child.hasAttribute("ignore")) {
651
- const styleInstance = new Style({
652
- code: child.textContent || "",
653
- fromHtml: false,
654
- url: ""
655
- });
656
- app.source?.setStyle(randomUrl(), styleInstance);
657
- styleInstance.scopedStyleCSS(app, child);
658
- }
659
- return child;
660
- }
661
- if (child instanceof HTMLLinkElement) {
662
- const result = app.source?.collectLink(child, parent, true);
663
- if (!result) return child;
664
- if (result.style) {
665
- result.style.scopedLinkCSS(app, child);
497
+ handleShadowRootFonts(cssText, app) {
498
+ let fontContent = "";
499
+ const fontFaces = cssText.match(CSS_SELECTORS.FONT_FACE) || [];
500
+ for (const fontFace of fontFaces) {
501
+ fontContent += `${fontFace}
502
+ `;
666
503
  }
667
- if (result.replace !== child) {
668
- return result.replace;
504
+ const rawDocument = app.sandBox?.rawDocument;
505
+ if (rawDocument && fontContent) {
506
+ const fontStyle = rawDocument.createElement("style");
507
+ fontStyle.setAttribute("type", STYLE_ATTRIBUTES.TYPE);
508
+ fontStyle.setAttribute("powered-by", STYLE_ATTRIBUTES.POWERED_BY);
509
+ fontStyle.textContent = fontContent;
510
+ rawDocument?.head?.append(fontStyle);
669
511
  }
670
- return child;
671
512
  }
672
- if (child instanceof HTMLScriptElement) {
673
- const replaceInfo = app.source.collectScript(child, parent, true);
674
- if (!replaceInfo) {
675
- return child;
676
- }
677
- if (replaceInfo.script) {
678
- replaceInfo.script.executeCode(app);
679
- }
680
- if (replaceInfo.replace !== child) {
681
- return replaceInfo.replace;
682
- }
683
- if (app.scopeJs && !child.getAttribute("src") && !child.textContent) {
684
- const observer = new MutationObserver(() => {
685
- if (child.getAttribute("src")) {
686
- observer.disconnect();
687
- const scriptInfo = app.source.collectScript(child, parent, true);
688
- if (scriptInfo?.replace) {
689
- bodyAppendChild.call(app.container, scriptInfo.replace);
690
- }
691
- if (isJsonpUrl(child.getAttribute("src"))) {
692
- app.container?.append(child);
693
- return;
694
- }
695
- if (scriptInfo?.script) {
696
- scriptInfo.script.executeCode(app);
697
- }
698
- child.remove();
699
- } else if (child.textContent) {
700
- observer.disconnect();
701
- const scriptInstance = new Script({
702
- async: false,
703
- code: child.textContent,
704
- defer: child.type === "module",
705
- fromHtml: false,
706
- isModule: child.type === "module"
707
- });
708
- app.source.scripts.set(randomUrl(), scriptInstance);
709
- try {
710
- scriptInstance.executeCode(app);
711
- } catch (e) {
712
- console.error(e);
713
- } finally {
714
- !scriptInstance.isModule && dispatchLinkOrScriptLoad(child);
715
- child.remove();
716
- }
717
- }
718
- });
719
- observer.observe(child, { attributeFilter: ["src"], childList: true, subtree: false });
720
- return document.createComment("\u3010bk-weweb\u3011dynamic script or module");
513
+ getCodeFromAppSource(app) {
514
+ if (this.url && app?.source?.styles?.has(this.url)) {
515
+ return app.source.styles.get(this.url)?.code || "";
721
516
  }
722
- return child;
517
+ return "";
723
518
  }
724
- return child;
725
- }
726
- function isSpecialElement(node) {
727
- return node instanceof HTMLScriptElement || node instanceof HTMLStyleElement || node instanceof HTMLLinkElement;
728
- }
729
- function elementAppendHandler(parent, newChild, rawMethod) {
730
- if (newChild.__BK_WEWEB_APP_KEY__) {
731
- const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
732
- if (app?.container) {
733
- const targetChild = resetNewElement(parent, newChild, app);
734
- const needKeepAlive = isSpecialElement(newChild) && !!app.keepAlive && !(app.container instanceof ShadowRoot);
735
- const container = needKeepAlive ? document.head : app?.container;
736
- setMarkElement(targetChild, app, needKeepAlive);
737
- return rawMethod.call(container, targetChild);
519
+ getCodeFromCache() {
520
+ if (this.url && appCache.getCacheStyle(this.url)) {
521
+ const style = appCache.getCacheStyle(this.url);
522
+ return style?.code || "";
738
523
  }
524
+ return "";
739
525
  }
740
- return rawMethod.call(parent, newChild);
741
- }
742
- function elementInsertHandler(parent, newChild, passiveChild, rawMethod) {
743
- if (newChild.__BK_WEWEB_APP_KEY__) {
744
- const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
745
- if (app?.container) {
746
- const needKeepAlive = isSpecialElement(newChild) && app.keepAlive && !(app.container instanceof ShadowRoot);
747
- const container = needKeepAlive ? document.head : app?.container;
748
- const targetChild = resetNewElement(parent, newChild, app);
749
- if (needKeepAlive) {
750
- setMarkElement(targetChild, app, needKeepAlive);
751
- }
752
- if (passiveChild && !container.contains(passiveChild)) {
753
- return bodyAppendChild.call(container, targetChild);
754
- }
755
- return rawMethod.call(container, targetChild, passiveChild);
756
- }
526
+ async fetchCodeFromRemote(app) {
527
+ return await fetchSource(this.url, {}, app).catch(() => "");
757
528
  }
758
- return rawMethod.call(parent, newChild, passiveChild);
759
- }
760
- function setMarkElement(element, app, keepAlive) {
761
- if (keepAlive && app) {
762
- element.__KEEP_ALIVE__ = app.appCacheKey;
763
- element.setAttribute("data-from", app.name);
764
- element.setAttribute("data-keep-alive", "true");
529
+ clearStyleElement(styleElement) {
530
+ styleElement.textContent = "";
531
+ styleElement.innerHTML = "";
765
532
  }
766
- element.setAttribute?.("powered-by", "bk-weweb");
767
- return element;
768
- }
769
-
770
- // src/utils/fetch.ts
771
- function fetchSource(url, options = {}, app) {
772
- if (typeof app?.fetchSource === "function") {
773
- return app.fetchSource(url, options).catch(() => "");
533
+ buildBaseURI(linkPath) {
534
+ const pathArr = linkPath.split("/");
535
+ pathArr.pop();
536
+ return addUrlProtocol(`${pathArr.join("/")}/`);
774
537
  }
775
- if (src_default.fetchSource) {
776
- return src_default.fetchSource(url, options);
777
- }
778
- return window.fetch(url, options).then((res) => res.text());
779
- }
780
-
781
- // src/entry/style.ts
782
- var Style = class {
783
- code = "";
784
- fromHtml;
785
- initial;
786
- prefetch = false;
787
- preload = false;
788
- scoped;
789
- scopedCode = "";
790
- url;
791
- constructor({ code, fromHtml, initial, prefetch, preload, url }) {
792
- this.scoped = false;
793
- this.code = code;
794
- this.prefetch = prefetch ?? false;
795
- this.preload = preload ?? false;
796
- this.url = url;
797
- this.fromHtml = fromHtml;
798
- this.initial = initial ?? false;
538
+ handleExistingCode(styleElement, app, container, linkElement) {
539
+ this.commonScoped(styleElement, app);
540
+ container?.prepend(styleElement);
541
+ linkElement && dispatchLinkOrScriptLoad(linkElement);
799
542
  }
800
543
  /**
801
- * @param styleElement 样式node
802
- * @param app 应用实例
544
+ * 处理href属性
803
545
  */
804
- commonScoped(styleElement, app) {
805
- if (app.scopeCss && !(app.container instanceof ShadowRoot)) {
806
- const cssStyleSheet = new CSSStyleSheet({ disabled: true });
807
- cssStyleSheet.replaceSync(styleElement.textContent || this.code);
808
- const rules = Array.from(cssStyleSheet?.cssRules ?? []);
809
- const cssPrefix = `#${app.name}`;
810
- const scopedCss = this.scopeRule(rules, cssPrefix);
811
- const cssText = this.resetUrlHost(scopedCss, app.url, this.url);
812
- styleElement.textContent = cssText;
813
- this.scopedCode = cssText;
814
- } else {
815
- const cssText = this.resetUrlHost(styleElement.textContent || this.code || "", app.url, this.url);
816
- if (cssText && app.container instanceof ShadowRoot) {
817
- let fontContent = "";
818
- for (const fontFace of cssText.match(/@font-face\s*\{[^}]+\}/g) || []) {
819
- fontContent += `${fontFace}
820
- `;
821
- }
822
- const rawDocument = app.sandBox?.rawDocument;
823
- if (rawDocument && fontContent) {
824
- const fontStyle = rawDocument.createElement("style");
825
- fontStyle.setAttribute("type", "text/css");
826
- fontStyle.setAttribute("powered-by", "bk-weweb");
827
- fontStyle.textContent = fontContent;
828
- rawDocument?.head?.append(fontStyle);
829
- }
830
- }
831
- styleElement.textContent = cssText.replace(/(:?:root|html)/gm, ":host");
832
- }
833
- this.scoped = true;
834
- }
835
- createStyleElement() {
836
- const styleElement = document.createElement("style");
837
- if (styleElement.__BK_WEWEB_APP_KEY__) {
838
- styleElement.__BK_WEWEB_APP_KEY__ = void 0;
839
- }
840
- return styleElement;
546
+ handleHrefAttribute(styleElement, app, container, linkElement) {
547
+ this.url = fillUpPath(linkElement.getAttribute("href"), app.url);
548
+ this.getCode(app).then(() => {
549
+ this.scopedStyleCSS(app, styleElement);
550
+ linkElement.remove();
551
+ container?.prepend(styleElement);
552
+ linkElement && dispatchLinkOrScriptLoad(linkElement);
553
+ this.scoped = true;
554
+ });
841
555
  }
842
556
  /**
843
- * @param app 应用实例
844
- * @returns 返回执行后的style标签
557
+ * 处理缺失的href
845
558
  */
846
- async executeCode(app) {
847
- app.registerRunningApp();
848
- let styleElement = this.createStyleElement();
849
- styleElement.setAttribute("type", "text/css");
850
- styleElement.textContent = this.code;
851
- try {
852
- if (!this.code) await this.getCode(app);
853
- styleElement = this.scopedStyleCSS(app, styleElement);
854
- this.scoped = true;
855
- } catch (e) {
856
- console.error("scoped style error", e);
857
- }
858
- return styleElement;
859
- }
860
- async getCode(app) {
861
- if (this.code.length || !this.url) {
862
- return this.code;
863
- }
864
- let code = "";
865
- if (app?.source?.styles?.has(this.url)) {
866
- code = app.source.styles.get(this.url)?.code || "";
867
- }
868
- if (!code && appCache.getCacheStyle(this.url)) {
869
- const style = appCache.getCacheStyle(this.url);
870
- code = style?.code || "";
871
- }
872
- if (!code) {
873
- code = await fetchSource(this.url, {}, app).catch(() => "");
874
- }
875
- this.code = code;
876
- return code;
877
- }
878
- // 主应用已生效的样式 不再应用在子应用
879
- linkedBaseStyle(styleElement, app) {
880
- if (!(app.container instanceof ShadowRoot) && styleElement.textContent && appCache.getBaseAppStyle(styleElement.textContent)) {
881
- styleElement.textContent = "";
882
- styleElement.innerHTML = "";
883
- styleElement.setAttribute("linked-from-base", "true");
884
- return true;
885
- }
886
- return false;
887
- }
888
- resetPackRule(rule, prefix, packName) {
889
- const result = this.scopeRule(Array.from(rule.cssRules), prefix);
890
- return `@${packName} ${rule.conditionText} {${result}}`;
891
- }
892
- resetUrlHost(cssText, uri, linkPath) {
893
- let baseURI = uri;
894
- return cssText.replace(/url\(["']?([^)"']+)["']?\)/gm, (text, $1) => {
895
- if (/^(data|blob):/.test($1) || /^(https?:)?\/\//.test($1)) {
896
- return text;
897
- }
898
- if (/^((\.\.?\/)|[^/])/.test($1) && linkPath) {
899
- const pathArr = linkPath.split("/");
900
- pathArr.pop();
901
- baseURI = addUrlProtocol(`${pathArr.join("/")}/`);
902
- }
903
- return `url("${fillUpPath($1, baseURI)}")`;
559
+ handleMissingHref(styleElement, app, container, linkElement) {
560
+ const observer = new MutationObserver(() => {
561
+ const href = linkElement.getAttribute("href");
562
+ if (!href) return;
563
+ observer.disconnect();
564
+ this.url = fillUpPath(href, app.url);
565
+ this.getCode(app).then(() => {
566
+ this.scopedStyleCSS(app, styleElement);
567
+ linkElement.remove();
568
+ container?.prepend(styleElement);
569
+ linkElement && dispatchLinkOrScriptLoad(linkElement);
570
+ this.scoped = true;
571
+ });
904
572
  });
573
+ const observerConfig = {
574
+ attributeFilter: ["href"],
575
+ childList: false,
576
+ subtree: false
577
+ };
578
+ observer.observe(linkElement, observerConfig);
905
579
  }
906
- scopeRule(rules, cssPrefix) {
907
- let result = "";
908
- for (const rule of rules) {
909
- switch (rule.type) {
910
- case 1 /* STYLE_RULE */:
911
- result += this.scopeStyleRule(rule, cssPrefix);
912
- break;
913
- case 4 /* MEDIA_RULE */:
914
- result += this.resetPackRule(rule, cssPrefix, "media");
915
- break;
916
- case 12 /* SUPPORTS_RULE */:
917
- result += this.resetPackRule(rule, cssPrefix, "supports");
918
- break;
919
- default:
920
- result += rule.cssText;
921
- break;
922
- }
923
- }
924
- return result.replace(/^\s+/, "");
925
- }
926
- scopeStyleRule(rule, prefix) {
927
- const { cssText, selectorText } = rule;
928
- if (/^((html[\s>~,]+body)|(html|body|:root))$/.test(selectorText)) {
929
- return cssText.replace(/^((html[\s>~,]+body)|(html|body|:root))/, prefix);
580
+ processExistingContent(styleElement, app) {
581
+ if (styleElement.textContent) {
582
+ this.clearStyleElement(styleElement);
930
583
  }
931
- if (selectorText === "*") {
932
- return cssText.replace("*", `${prefix} *`);
584
+ if (!this.linkedBaseStyle(styleElement, app)) {
585
+ this.commonScoped(styleElement, app);
933
586
  }
934
- const builtInRootSelectorRE = /(^|\s+)((html[\s>~]+body)|(html|body|:root))(?=[\s>~]+|$)/;
935
- return cssText.replace(
936
- /^[\s\S]+{/,
937
- (selectors) => selectors.replace(/(^|,)([^,]+)/g, (all, $1, $2) => {
938
- if (builtInRootSelectorRE.test($2)) {
939
- return all.replace(builtInRootSelectorRE, prefix);
940
- }
941
- return `${$1} ${prefix} ${$2.replace(/^\s*/, "")}`;
942
- })
943
- );
944
587
  }
945
- scopedLinkCSS(app, linkElement) {
946
- const styleElement = this.createStyleElement();
947
- styleElement.setAttribute("type", "text/css");
948
- const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
949
- setMarkElement(styleElement, app, needKeepAlive);
950
- const container = needKeepAlive ? document.head : app.container;
951
- try {
952
- if (this.code) {
588
+ observeContentChanges(styleElement, app) {
589
+ const observer = new MutationObserver(() => {
590
+ if (!(styleElement.textContent || styleElement.sheet?.cssRules?.length)) return;
591
+ observer.disconnect();
592
+ if (!this.linkedBaseStyle(styleElement, app)) {
953
593
  this.commonScoped(styleElement, app);
954
- container?.prepend(styleElement);
955
- linkElement && dispatchLinkOrScriptLoad(linkElement);
956
- } else if (linkElement.getAttribute("href")) {
957
- this.url = fillUpPath(linkElement.getAttribute("href"), app.url);
958
- this.getCode(app).then(() => {
959
- this.scopedStyleCSS(app, styleElement);
960
- linkElement.remove();
961
- container?.prepend(styleElement);
962
- linkElement && dispatchLinkOrScriptLoad(linkElement);
963
- this.scoped = true;
964
- });
965
- } else {
966
- const observer = new MutationObserver(() => {
967
- if (!linkElement.href) return;
968
- observer.disconnect();
969
- this.url = fillUpPath(linkElement.getAttribute("href"), app.url);
970
- this.getCode(app).then(() => {
971
- this.scopedStyleCSS(app, styleElement);
972
- linkElement.remove();
973
- container?.prepend(styleElement);
974
- linkElement && dispatchLinkOrScriptLoad(linkElement);
975
- this.scoped = true;
976
- });
977
- });
978
- observer.observe(linkElement, { attributeFilter: ["href"], childList: false, subtree: false });
979
- }
980
- } catch {
981
- linkElement && dispatchLinkOrScriptError(linkElement);
982
- }
983
- return styleElement;
984
- }
985
- scopedStyleCSS(app, styleElement) {
986
- const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
987
- setMarkElement(styleElement, app, needKeepAlive);
988
- if (this.code || styleElement.textContent) {
989
- if (styleElement.textContent) {
990
- styleElement.textContent = "";
991
- styleElement.innerHTML = "";
992
594
  }
993
- if (this.linkedBaseStyle(styleElement, app)) return styleElement;
994
- this.commonScoped(styleElement, app);
995
- } else {
996
- const observer = new MutationObserver(() => {
997
- if (!(styleElement.textContent || styleElement.sheet?.cssRules?.length)) return;
998
- observer.disconnect();
999
- if (!this.linkedBaseStyle(styleElement, app)) {
1000
- this.commonScoped(styleElement, app);
1001
- }
1002
- });
1003
- observer.observe(styleElement, { attributes: false, characterData: true, childList: true, subtree: true });
1004
- }
1005
- this.url && styleElement.setAttribute("origin-src", this.url);
1006
- return styleElement;
595
+ });
596
+ const observerConfig = {
597
+ attributes: false,
598
+ characterData: true,
599
+ childList: true,
600
+ subtree: true
601
+ };
602
+ observer.observe(styleElement, observerConfig);
1007
603
  }
1008
604
  };
1009
605
  async function executeAppStyles(app, container) {
1010
- const styleList = Array.from(app.source.styles.values());
606
+ const styleList = Array.from(app.source?.styles?.values() || []);
1011
607
  const promiseList = [];
1012
608
  for (const style of styleList) {
1013
609
  promiseList.push(style.executeCode(app));
@@ -1023,38 +619,26 @@ async function executeAppStyles(app, container) {
1023
619
  }
1024
620
 
1025
621
  // src/mode/instance.ts
622
+ var DEFAULT_RANDOM_LENGTH = 5;
623
+ var WRAPPER_SUFFIX = "-wrapper";
1026
624
  var MicroInstanceModel = class {
1027
- state = "UNSET" /* UNSET */;
1028
- // 当前实例状态
625
+ state = AppState.UNSET;
1029
626
  appCacheKey;
1030
- // 缓存key
1031
627
  container;
1032
- // 容器
1033
628
  data;
1034
- // 数据
629
+ fetchSource;
1035
630
  initSource;
1036
- // 初始资源
1037
631
  isPreLoad = false;
1038
- // 是否预加载
1039
632
  keepAlive;
1040
- // 是否缓存
1041
633
  name;
1042
- // 名称
1043
634
  sandBox;
1044
- // 沙箱
1045
635
  scopeCss = true;
1046
- // 是否隔离样式
1047
636
  scopeJs = false;
1048
- // 是否隔离js
1049
637
  showSourceCode = true;
1050
- // 是否显示源码
1051
638
  source;
1052
- // 入口资源
1053
639
  url;
1054
- // url
1055
- fetchSource;
1056
640
  constructor(props) {
1057
- this.name = props.id !== props.url ? props.id : random(5);
641
+ this.name = props.id !== props.url ? props.id : random(DEFAULT_RANDOM_LENGTH);
1058
642
  this.appCacheKey = props.id || this.name;
1059
643
  this.url = props.url;
1060
644
  this.container = props.container ?? void 0;
@@ -1064,106 +648,178 @@ var MicroInstanceModel = class {
1064
648
  this.keepAlive = props.keepAlive ?? false;
1065
649
  this.data = props.data ?? {};
1066
650
  this.initSource = props.initSource ?? [];
1067
- if (this.scopeJs) {
1068
- this.sandBox = new SandBox(this);
1069
- }
1070
651
  this.fetchSource = props.fetchSource;
652
+ this.initializeSandBox();
1071
653
  }
654
+ /** 激活微模块 */
1072
655
  activated(container, callback) {
1073
656
  this.isPreLoad = false;
1074
- this.state = "ACTIVATED" /* ACTIVATED */;
657
+ this.state = AppState.ACTIVATED;
1075
658
  if (this.container && container) {
1076
- if (container instanceof Element) container?.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1077
- const fragment = document.createDocumentFragment();
1078
- for (const node of Array.from(this.container.childNodes)) {
1079
- fragment.appendChild(node);
1080
- }
1081
- container.appendChild(fragment);
659
+ this.setContainerAttribute(container);
660
+ this.transferNodes(container);
1082
661
  this.container = container;
662
+ this.initShadowRootContainer();
1083
663
  this.sandBox?.activated();
1084
- const scriptInfo = this.source?.getScript(this.url);
664
+ const scriptInfo = this.getScriptInfo();
1085
665
  callback?.(this, scriptInfo?.exportInstance);
1086
666
  }
1087
667
  }
668
+ /** 停用微模块 */
1088
669
  deactivated() {
1089
- this.state = "DEACTIVATED" /* DEACTIVATED */;
670
+ this.state = AppState.DEACTIVATED;
1090
671
  this.sandBox?.deactivated();
1091
672
  }
673
+ /** 挂载微模块 */
1092
674
  mount(container, callback) {
1093
675
  this.isPreLoad = false;
1094
676
  this.container = container ?? this.container;
1095
- this.state = "MOUNTING" /* MOUNTING */;
1096
- if (this.container instanceof HTMLElement) {
1097
- this.container?.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1098
- }
1099
- this.container.innerHTML = "";
1100
- const instanceWrap = document.createElement("div");
1101
- const wrapId = `${this.name}-wrapper`;
1102
- instanceWrap.setAttribute("id", wrapId);
1103
- if (this.source?.styles.size) {
1104
- executeAppStyles(this, this.container);
1105
- }
1106
- this.container.appendChild(instanceWrap);
677
+ this.initShadowRootContainer();
678
+ this.state = AppState.MOUNTING;
679
+ this.setContainerAttribute(this.container);
680
+ this.setupContainer();
681
+ this.executeStyles();
1107
682
  this.sandBox?.activated();
1108
683
  execAppScripts(this).finally(() => {
1109
- this.state = "MOUNTED" /* MOUNTED */;
1110
- const scriptInfo = this.source?.getScript(this.url);
1111
- if (typeof scriptInfo?.exportInstance?.render === "function") {
1112
- scriptInfo.exportInstance.render(instanceWrap, this.data);
1113
- }
684
+ this.state = AppState.MOUNTED;
685
+ this.renderInstance();
686
+ const scriptInfo = this.getScriptInfo();
1114
687
  callback?.(this, scriptInfo?.exportInstance);
1115
688
  });
1116
689
  }
690
+ /** 错误处理 */
1117
691
  onError() {
1118
- this.state = "ERROR" /* ERROR */;
692
+ this.state = AppState.ERROR;
1119
693
  }
694
+ /** 挂载处理 */
1120
695
  onMount() {
1121
696
  if (this.isPreLoad) return;
1122
- this.state = "LOADED" /* LOADED */;
697
+ this.state = AppState.LOADED;
1123
698
  this.mount();
1124
699
  }
700
+ /** 注册运行中的应用 */
1125
701
  registerRunningApp() {
1126
702
  setCurrentRunningApp(this);
1127
703
  Promise.resolve().then(() => setCurrentRunningApp(null));
1128
704
  }
705
+ /** 启动微模块 */
1129
706
  async start() {
1130
- if (!this.source || ["ERROR" /* ERROR */, "UNSET" /* UNSET */].includes(this.status)) {
707
+ if (!this.source || this.needsReload()) {
1131
708
  this.source = new EntrySource(this.url);
1132
709
  await this.source.importEntry(this);
1133
710
  }
1134
711
  }
712
+ /** 卸载微模块 */
1135
713
  unmount(needDestroy) {
1136
- this.state = "UNMOUNT" /* UNMOUNT */;
714
+ this.state = AppState.UNMOUNT;
1137
715
  this.sandBox?.deactivated();
1138
- needDestroy && appCache.deleteApp(this.url);
1139
- this.container.innerHTML = "";
1140
- this.container = void 0;
716
+ if (needDestroy) {
717
+ appCache.deleteApp(this.url);
718
+ }
719
+ if (this.container) {
720
+ this.container.innerHTML = "";
721
+ this.container = void 0;
722
+ }
723
+ }
724
+ /** 初始化ShadowRoot容器 */
725
+ initShadowRootContainer() {
726
+ if (this.container instanceof ShadowRoot) {
727
+ Object.defineProperties(this.container, {
728
+ getBoundingClientRect: {
729
+ get() {
730
+ return this.host.getBoundingClientRect;
731
+ }
732
+ }
733
+ });
734
+ }
1141
735
  }
1142
- set status(v) {
1143
- this.state = v;
736
+ set status(value) {
737
+ this.state = value;
1144
738
  }
1145
739
  get status() {
1146
740
  return this.state;
1147
741
  }
742
+ /** 初始化沙盒 */
743
+ initializeSandBox() {
744
+ if (this.scopeJs) {
745
+ this.sandBox = new SandBox(this);
746
+ }
747
+ }
748
+ /** 设置容器属性 */
749
+ setContainerAttribute(container) {
750
+ if (container instanceof HTMLElement) {
751
+ container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
752
+ }
753
+ }
754
+ /** 转移节点到新容器 */
755
+ transferNodes(container) {
756
+ if (!this.container) return;
757
+ const fragment = document.createDocumentFragment();
758
+ const nodeList = Array.from(this.container.childNodes);
759
+ for (const node of nodeList) {
760
+ fragment.appendChild(node);
761
+ }
762
+ container.appendChild(fragment);
763
+ }
764
+ /** 设置容器 */
765
+ setupContainer() {
766
+ if (this.container) {
767
+ this.container.innerHTML = "";
768
+ const instanceWrapper = this.createInstanceWrapper();
769
+ this.container.appendChild(instanceWrapper);
770
+ }
771
+ }
772
+ /** 执行样式 */
773
+ executeStyles() {
774
+ if (this.source?.styles.size && this.container) {
775
+ executeAppStyles(this, this.container);
776
+ }
777
+ }
778
+ /** 创建实例包装器 */
779
+ createInstanceWrapper() {
780
+ const wrapper = document.createElement("div");
781
+ wrapper.id = `${this.name}${WRAPPER_SUFFIX}`;
782
+ return wrapper;
783
+ }
784
+ /** 渲染实例 */
785
+ renderInstance() {
786
+ const scriptInfo = this.getScriptInfo();
787
+ if (scriptInfo?.exportInstance?.render && this.container) {
788
+ const targetContainer = this.container.querySelector(`#${this.name}${WRAPPER_SUFFIX}`);
789
+ if (targetContainer) {
790
+ scriptInfo.exportInstance.render(targetContainer, this.data);
791
+ }
792
+ }
793
+ }
794
+ /** 获取脚本信息 */
795
+ getScriptInfo() {
796
+ const script = this.source?.getScript(this.url);
797
+ return script ? { exportInstance: script.exportInstance } : void 0;
798
+ }
799
+ /** 检查是否需要重新加载 */
800
+ needsReload() {
801
+ return this.status === AppState.ERROR || this.status === AppState.UNSET;
802
+ }
1148
803
  };
1149
804
 
1150
805
  // src/entry/script.ts
1151
806
  var firstGlobalProp;
1152
807
  var secondGlobalProp;
1153
808
  var lastGlobalProp;
809
+ var STRICT_MODE_REGEX = /^"use\sstrict";$/gim;
1154
810
  var Script = class {
1155
811
  async = false;
1156
812
  code = "";
1157
813
  defer = false;
1158
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1159
814
  exportInstance;
1160
815
  fromHtml;
816
+ blobUrl;
1161
817
  initial;
1162
818
  isModule = false;
1163
819
  scoped;
1164
820
  url;
1165
821
  constructor({ async, code, defer, fromHtml, initial, isModule, url }) {
1166
- this.code = code;
822
+ this.code = code?.replace(STRICT_MODE_REGEX, "");
1167
823
  this.async = async;
1168
824
  this.defer = defer;
1169
825
  this.isModule = isModule;
@@ -1171,12 +827,9 @@ var Script = class {
1171
827
  this.scoped = false;
1172
828
  this.fromHtml = fromHtml ?? false;
1173
829
  this.initial = initial ?? false;
830
+ this.blobUrl = void 0;
1174
831
  }
1175
- /**
1176
- * @param app 应用
1177
- * @param needReplaceScriptElement 是否需要替换script标签
1178
- * @returns 返回执行后的script标签或注释
1179
- */
832
+ /** 执行脚本代码 */
1180
833
  async executeCode(app, needReplaceScriptElement = false) {
1181
834
  try {
1182
835
  if (!this.code) await this.getCode(app);
@@ -1184,9 +837,29 @@ var Script = class {
1184
837
  const globalWindow = app.scopeJs ? app.sandBox?.proxyWindow || window : window;
1185
838
  noteGlobalProps(globalWindow);
1186
839
  }
1187
- let scopedCode = this.code;
1188
- scopedCode = this.transformCode(app);
1189
- if (app.showSourceCode || this.isModule) {
840
+ const scopedCode = this.transformCode(app);
841
+ if (this.isModule) {
842
+ app.registerRunningApp();
843
+ const scriptElement = document.createElement("script");
844
+ let blobUrl = "";
845
+ if (scriptElement.__BK_WEWEB_APP_KEY__) {
846
+ scriptElement.__BK_WEWEB_APP_KEY__ = void 0;
847
+ }
848
+ if (this.url) {
849
+ blobUrl = `${this.url.replace(/^\//, `${app.url}/`)}?key=${Date.now()}`;
850
+ } else {
851
+ const blob = new Blob([scopedCode], { type: "text/javascript" });
852
+ blobUrl = URL.createObjectURL(blob);
853
+ }
854
+ scriptElement.src = blobUrl;
855
+ scriptElement.type = "module";
856
+ if (needReplaceScriptElement) return scriptElement;
857
+ const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
858
+ const container = needKeepAlive ? document.head : app.container;
859
+ setMarkElement(scriptElement, app, needKeepAlive);
860
+ container.appendChild(scriptElement);
861
+ URL.revokeObjectURL(blobUrl);
862
+ } else if (app.showSourceCode) {
1190
863
  const scriptElement = document.createElement("script");
1191
864
  if (scriptElement.__BK_WEWEB_APP_KEY__) {
1192
865
  scriptElement.__BK_WEWEB_APP_KEY__ = void 0;
@@ -1204,200 +877,954 @@ var Script = class {
1204
877
  }
1205
878
  if (app instanceof MicroInstanceModel) {
1206
879
  const globalWindow = app.scopeJs ? app.sandBox?.proxyWindow || window : window;
1207
- const exportProp = getGlobalProp(globalWindow);
880
+ const isIifeVar = !!this.code.replace(/\/\*[\s\S]*?\*\//g, "").match(/^\s*var\s/);
881
+ const exportProp = getGlobalProp(globalWindow, isIifeVar);
1208
882
  if (exportProp) {
1209
883
  this.exportInstance = globalWindow[exportProp];
1210
884
  if (!app.scopeJs) {
1211
- delete globalWindow[exportProp];
885
+ const descriptor = Object.getOwnPropertyDescriptor(globalWindow, exportProp);
886
+ if (descriptor?.configurable) {
887
+ delete globalWindow[exportProp];
888
+ }
1212
889
  }
1213
890
  }
1214
891
  }
1215
- } catch (e) {
1216
- console.error("execute script code error", e);
892
+ } catch (error) {
893
+ console.error("execute script code error", error);
894
+ }
895
+ return;
896
+ }
897
+ /** 内存脚本执行 */
898
+ executeMemoryScript(app, scopedCode) {
899
+ try {
900
+ const isScopedLocation = app instanceof MicroAppModel && app.scopeLocation;
901
+ app.registerRunningApp();
902
+ new Function("window", "location", "history", scopedCode)(
903
+ app.sandBox.proxyWindow || window,
904
+ isScopedLocation ? app.iframe.contentWindow.location : window.location,
905
+ isScopedLocation ? app.iframe.contentWindow.history : window.history
906
+ );
907
+ } catch (error) {
908
+ console.error(error);
909
+ }
910
+ }
911
+ /** 脚本标签执行 */
912
+ executeSourceScript(scriptElement, scopedCode) {
913
+ if (this.isModule) {
914
+ scriptElement.src = `${this.url}?key=${Date.now()}`;
915
+ scriptElement.setAttribute("type", "module");
916
+ } else {
917
+ scriptElement.textContent = scopedCode;
918
+ }
919
+ this.url && scriptElement.setAttribute("origin-src", this.url);
920
+ }
921
+ /** 获取脚本内容 */
922
+ async getCode(app) {
923
+ if (this.code.length || !this.url || this.isModule) {
924
+ return this.code;
925
+ }
926
+ let code = "";
927
+ if (app?.source?.getScript(this.url)) {
928
+ code = app.source.getScript(this.url)?.code || "";
929
+ }
930
+ if (!code && appCache.getCacheScript(this.url)) {
931
+ code = appCache.getCacheScript(this.url)?.code || "";
932
+ }
933
+ if (!code) {
934
+ code = await fetchSource(this.url, {}, app).catch((error) => {
935
+ console.error(`fetch script ${this.url} error`, error);
936
+ return "";
937
+ });
938
+ }
939
+ code = code.replace(STRICT_MODE_REGEX, "");
940
+ this.code = code;
941
+ return code;
942
+ }
943
+ setCode(code) {
944
+ this.code = code;
945
+ }
946
+ /** 转换脚本内容 */
947
+ transformCode(app) {
948
+ const sourceMapUrl = this.url ? `//# sourceURL=${this.url}
949
+ ` : "";
950
+ if (app.sandBox) {
951
+ if (this.isModule) {
952
+ if (this.url) {
953
+ return this.code;
954
+ }
955
+ const importList = this.code.match(/import\s*.*(?:from)?\s*"([^"]+)";/gm);
956
+ for (const item of importList || []) {
957
+ this.code = this.code.replace(item, item.replace(/"\//, `"${app.url}/`).replace(/"$/, `?key=${Date.now()}"`));
958
+ }
959
+ return `
960
+ ${this.code};
961
+ `;
962
+ }
963
+ if (app.showSourceCode) {
964
+ return `;(function(window, self, globalThis){
965
+ with(window){
966
+ ${getGlobalContextCode()}
967
+
968
+ ${this.code}
969
+
970
+ ${sourceMapUrl}
971
+ }
972
+ }).call(window['${app.sandBox.windowSymbolKey}'],
973
+ window['${app.sandBox.windowSymbolKey}'], window['${app.sandBox.windowSymbolKey}'], window['${app.sandBox.windowSymbolKey}']);`;
974
+ }
975
+ return `
976
+ with(window) {
977
+ try {
978
+ ${getGlobalContextCode()}
979
+
980
+ ${this.code}
981
+
982
+ ${sourceMapUrl}
983
+ }
984
+ catch(e) {
985
+ console.error(e)
986
+ }
987
+ }
988
+ `;
989
+ }
990
+ return this.code;
991
+ }
992
+ };
993
+ function shouldSkipProperty(global, property) {
994
+ const globalWindow = global;
995
+ return (
996
+ // biome-ignore lint/suspicious/noPrototypeBuiltins: <explanation>
997
+ !global.hasOwnProperty(property) || !Number.isNaN(property) && property < global.length || typeof navigator !== "undefined" && navigator.userAgent.indexOf("Trident") !== -1 && Boolean(globalWindow[property]) && typeof window !== "undefined" && globalWindow[property]?.parent === window
998
+ );
999
+ }
1000
+ function getGlobalProp(global, useFirstGlobalProp) {
1001
+ let cnt = 0;
1002
+ let foundLastProp;
1003
+ let result;
1004
+ for (const property in global) {
1005
+ if (shouldSkipProperty(global, property)) continue;
1006
+ if (cnt === 0 && property !== firstGlobalProp || cnt === 1 && property !== secondGlobalProp) {
1007
+ return property;
1008
+ }
1009
+ if (foundLastProp) {
1010
+ lastGlobalProp = property;
1011
+ result = useFirstGlobalProp && result || property;
1012
+ } else {
1013
+ foundLastProp = property === lastGlobalProp;
1014
+ }
1015
+ cnt += 1;
1016
+ }
1017
+ return result;
1018
+ }
1019
+ function noteGlobalProps(global) {
1020
+ secondGlobalProp = void 0;
1021
+ firstGlobalProp = secondGlobalProp;
1022
+ for (const property in global) {
1023
+ if (shouldSkipProperty(global, property)) continue;
1024
+ if (!firstGlobalProp) {
1025
+ firstGlobalProp = property;
1026
+ } else if (!secondGlobalProp) {
1027
+ secondGlobalProp = property;
1028
+ }
1029
+ lastGlobalProp = property;
1030
+ }
1031
+ return lastGlobalProp;
1032
+ }
1033
+ async function execAppScripts(app) {
1034
+ const appScriptList = Array.from(app.source.scripts.values()).filter((script) => script.fromHtml || script.initial);
1035
+ const commonList = appScriptList.filter(
1036
+ (script) => !script.async && !script.defer || script.isModule && !script.fromHtml
1037
+ );
1038
+ await Promise.all(commonList.map((script) => script.getCode(app)));
1039
+ await Promise.all(commonList.map((script) => script.executeCode(app)));
1040
+ const deferScriptList = [];
1041
+ const asyncScriptList = [];
1042
+ for (const script of appScriptList) {
1043
+ if (script.defer || script.async) {
1044
+ if (!script.code && script.defer) {
1045
+ deferScriptList.push(script.executeCode(app));
1046
+ } else {
1047
+ asyncScriptList.push(script.executeCode(app));
1048
+ }
1049
+ }
1050
+ }
1051
+ await Promise.all([...asyncScriptList, ...deferScriptList]).catch((error) => {
1052
+ console.error(error);
1053
+ });
1054
+ }
1055
+
1056
+ // src/utils/element.ts
1057
+ var { appendChild: bodyAppendChild } = HTMLBodyElement.prototype;
1058
+ var handleStyleElement = (child, app) => {
1059
+ if (child.hasAttribute("exclude")) {
1060
+ return document.createComment("\u3010bk-weweb\u3011style with exclude attribute is ignored");
1061
+ }
1062
+ if (child.textContent) {
1063
+ if (!(app.container instanceof ShadowRoot) && appCache.getBaseAppStyle(child.textContent)) {
1064
+ return document.createComment("\u3010bk-weweb\u3011style is effective in base app");
1065
+ }
1066
+ }
1067
+ if (!child.hasAttribute("ignore")) {
1068
+ const styleInstance = new Style({
1069
+ code: child.textContent || "",
1070
+ fromHtml: false,
1071
+ url: ""
1072
+ });
1073
+ app.source?.setStyle(randomUrl(), styleInstance);
1074
+ styleInstance.scopedStyleCSS(app, child);
1075
+ }
1076
+ return child;
1077
+ };
1078
+ var handleLinkElement = (child, parent, app) => {
1079
+ const result = app.source?.collectLink(child, parent, true);
1080
+ if (!result) return child;
1081
+ if (result.style) {
1082
+ result.style.scopedLinkCSS(app, child);
1083
+ }
1084
+ return result.replace !== child ? result.replace : child;
1085
+ };
1086
+ var createScriptObserver = (child, parent, app) => {
1087
+ const observer = new MutationObserver(() => {
1088
+ if (child.getAttribute("src")) {
1089
+ observer.disconnect();
1090
+ const scriptInfo = app.source.collectScript(child, parent, true);
1091
+ if (scriptInfo?.replace) {
1092
+ bodyAppendChild.call(app.container, scriptInfo.replace);
1093
+ }
1094
+ if (isJsonpUrl(child.getAttribute("src"))) {
1095
+ app.container?.append(child);
1096
+ return;
1097
+ }
1098
+ if (scriptInfo?.script) {
1099
+ scriptInfo.script.executeCode(app);
1100
+ }
1101
+ child.remove();
1102
+ } else if (child.textContent) {
1103
+ observer.disconnect();
1104
+ const scriptInstance = new Script({
1105
+ async: false,
1106
+ code: child.textContent,
1107
+ defer: child.type === "module",
1108
+ fromHtml: false,
1109
+ isModule: child.type === "module"
1110
+ });
1111
+ app.source.scripts.set(randomUrl(), scriptInstance);
1112
+ try {
1113
+ scriptInstance.executeCode(app);
1114
+ } catch (error) {
1115
+ console.error(error);
1116
+ } finally {
1117
+ if (!scriptInstance.isModule) {
1118
+ dispatchLinkOrScriptLoad(child);
1119
+ }
1120
+ child.remove();
1121
+ }
1122
+ }
1123
+ });
1124
+ return observer;
1125
+ };
1126
+ var handleScriptElement = (child, parent, app) => {
1127
+ const replaceInfo = app.source.collectScript(child, parent, true);
1128
+ if (!replaceInfo) {
1129
+ return child;
1130
+ }
1131
+ if (replaceInfo.script) {
1132
+ replaceInfo.script.executeCode(app);
1133
+ }
1134
+ if (replaceInfo.replace !== child) {
1135
+ return replaceInfo.replace;
1136
+ }
1137
+ if (app.scopeJs && !child.getAttribute("src") && !child.textContent) {
1138
+ const observer = createScriptObserver(child, parent, app);
1139
+ observer.observe(child, { attributeFilter: ["src"], childList: true, subtree: false });
1140
+ return document.createComment("\u3010bk-weweb\u3011dynamic script or module");
1141
+ }
1142
+ return child;
1143
+ };
1144
+ var resetNewElement = (parent, child, app) => {
1145
+ if (child instanceof HTMLStyleElement) {
1146
+ return handleStyleElement(child, app);
1147
+ }
1148
+ if (child instanceof HTMLLinkElement) {
1149
+ return handleLinkElement(child, parent, app);
1150
+ }
1151
+ if (child instanceof HTMLScriptElement) {
1152
+ return handleScriptElement(child, parent, app);
1153
+ }
1154
+ return child;
1155
+ };
1156
+ var isSpecialElement = (node) => {
1157
+ return node instanceof HTMLScriptElement || node instanceof HTMLStyleElement || node instanceof HTMLLinkElement;
1158
+ };
1159
+ var getTargetContainer = (app, isSpecial) => {
1160
+ const needKeepAlive = isSpecial && !!app.keepAlive && !(app.container instanceof ShadowRoot);
1161
+ return needKeepAlive ? document.head : app.container;
1162
+ };
1163
+ var elementAppendHandler = (parent, newChild, rawMethod) => {
1164
+ if (!newChild.__BK_WEWEB_APP_KEY__) {
1165
+ return rawMethod.call(parent, newChild);
1166
+ }
1167
+ const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
1168
+ if (!app?.container) {
1169
+ return rawMethod.call(parent, newChild);
1170
+ }
1171
+ const targetChild = resetNewElement(parent, newChild, app);
1172
+ const isSpecial = isSpecialElement(newChild);
1173
+ const needKeepAlive = isSpecial && !!app.keepAlive && !(app.container instanceof ShadowRoot);
1174
+ const container = getTargetContainer(app, isSpecial);
1175
+ setMarkElement(targetChild, app, needKeepAlive);
1176
+ return rawMethod.call(container, targetChild);
1177
+ };
1178
+ var elementInsertHandler = (parent, newChild, passiveChild, rawMethod) => {
1179
+ if (!newChild.__BK_WEWEB_APP_KEY__) {
1180
+ return rawMethod.call(parent, newChild, passiveChild);
1181
+ }
1182
+ const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
1183
+ if (!app?.container) {
1184
+ return rawMethod.call(parent, newChild, passiveChild);
1185
+ }
1186
+ const isSpecial = isSpecialElement(newChild);
1187
+ const needKeepAlive = isSpecial && app.keepAlive && !(app.container instanceof ShadowRoot);
1188
+ const container = getTargetContainer(app, isSpecial);
1189
+ const targetChild = resetNewElement(parent, newChild, app);
1190
+ if (needKeepAlive) {
1191
+ setMarkElement(targetChild, app, needKeepAlive);
1192
+ }
1193
+ if (passiveChild && !container.contains(passiveChild)) {
1194
+ return bodyAppendChild.call(container, targetChild);
1195
+ }
1196
+ return rawMethod.call(container, targetChild, passiveChild);
1197
+ };
1198
+ var setMarkElement = (element, app, keepAlive) => {
1199
+ if (keepAlive && app) {
1200
+ element.__KEEP_ALIVE__ = app.appCacheKey;
1201
+ element.setAttribute("data-from", app.name);
1202
+ element.setAttribute("data-keep-alive", "true");
1203
+ }
1204
+ element.setAttribute?.("powered-by", "bk-weweb");
1205
+ return element;
1206
+ };
1207
+
1208
+ // src/context/document.ts
1209
+ var SPECIAL_ELEMENT_TAGS = ["body", "html", "head"];
1210
+ var APP_KEY_PROPERTY = "__BK_WEWEB_APP_KEY__";
1211
+ function createShadowRootInsertAdjacentHTML(app) {
1212
+ return function shadowRootInsertAdjacentHTML(where, domString) {
1213
+ const temporaryContainer = document.createElement("div");
1214
+ temporaryContainer.innerHTML = domString;
1215
+ const elements = Array.from(temporaryContainer.childNodes);
1216
+ const shadow = app.container;
1217
+ switch (where) {
1218
+ case "beforebegin":
1219
+ for (const item of elements) {
1220
+ shadow.host.parentNode?.insertBefore(item, shadow.host);
1221
+ }
1222
+ break;
1223
+ case "afterbegin":
1224
+ for (const item of elements.reverse()) {
1225
+ shadow.insertBefore(item, shadow.firstChild);
1226
+ }
1227
+ break;
1228
+ case "beforeend":
1229
+ for (const item of elements) {
1230
+ shadow.appendChild(item);
1231
+ }
1232
+ break;
1233
+ case "afterend":
1234
+ for (const item of elements) {
1235
+ shadow.host.parentNode?.insertBefore(item, shadow.host.nextSibling);
1236
+ }
1237
+ break;
1238
+ }
1239
+ };
1240
+ }
1241
+ function createProxyBody(rawDocument, app) {
1242
+ return new Proxy(
1243
+ {},
1244
+ {
1245
+ get(_, key) {
1246
+ if (app.container instanceof ShadowRoot) {
1247
+ if (key === "insertAdjacentHTML") {
1248
+ return createShadowRootInsertAdjacentHTML(app);
1249
+ }
1250
+ const value2 = Reflect.get(app.container, key);
1251
+ if (typeof value2 === "function") {
1252
+ return value2.bind(app.container);
1253
+ }
1254
+ if (value2 !== void 0) {
1255
+ return value2;
1256
+ }
1257
+ }
1258
+ const value = Reflect.get(rawDocument.body, key);
1259
+ return typeof value === "function" ? value.bind(rawDocument.body) : value;
1260
+ },
1261
+ set(_, key, value) {
1262
+ if (app.container instanceof ShadowRoot) {
1263
+ Reflect.set(app.container, key, value);
1264
+ return true;
1265
+ }
1266
+ Reflect.set(rawDocument.body, key, value);
1267
+ return true;
1268
+ }
1269
+ }
1270
+ );
1271
+ }
1272
+ function createElementWithAppKey(rawDocument, app) {
1273
+ return function createElement(tagName, options) {
1274
+ const element = rawDocument.createElement(tagName, options);
1275
+ element[APP_KEY_PROPERTY] = app.appCacheKey;
1276
+ if (element instanceof HTMLImageElement) {
1277
+ Object.defineProperty(element, "src", {
1278
+ get() {
1279
+ return element.getAttribute("src");
1280
+ },
1281
+ set(value) {
1282
+ element.setAttribute("src", fillUpPath(value, app.url));
1283
+ }
1284
+ });
1285
+ }
1286
+ return element;
1287
+ };
1288
+ }
1289
+ function isSpecialElementTag(selector) {
1290
+ return SPECIAL_ELEMENT_TAGS.includes(selector);
1291
+ }
1292
+ function safeQuerySelector(container, selector) {
1293
+ try {
1294
+ return container?.querySelector(selector) ?? null;
1295
+ } catch {
1296
+ return null;
1297
+ }
1298
+ }
1299
+ function safeQuerySelectorAll(container, selector) {
1300
+ try {
1301
+ return container?.querySelectorAll(selector) ?? [];
1302
+ } catch {
1303
+ return [];
1304
+ }
1305
+ }
1306
+ function createProxyQuerySelector(rawDocument, app, proxyBody) {
1307
+ return function querySelectorNew(selectors) {
1308
+ if (selectors === proxyBody) {
1309
+ return app.container instanceof ShadowRoot ? app.container : rawDocument.body;
1310
+ }
1311
+ if (isSpecialElementTag(selectors)) {
1312
+ if (app?.container instanceof ShadowRoot) {
1313
+ return app?.container;
1314
+ }
1315
+ return rawDocument.querySelector.call(this, selectors);
1316
+ }
1317
+ return safeQuerySelector(app?.container, selectors);
1318
+ };
1319
+ }
1320
+ function createProxyQuerySelectorAll(rawDocument, app) {
1321
+ return function querySelectorAllNew(selectors) {
1322
+ if (isSpecialElementTag(selectors)) {
1323
+ if (app?.container instanceof ShadowRoot) {
1324
+ return [app?.container];
1325
+ }
1326
+ const result = rawDocument.querySelector(selectors);
1327
+ return result ? [result] : [];
1328
+ }
1329
+ return safeQuerySelectorAll(app?.container, selectors);
1330
+ };
1331
+ }
1332
+ function createProxyGetElementById(rawDocument, querySelector) {
1333
+ return function getElementByIdNew(id) {
1334
+ return querySelector.call(rawDocument, `#${id}`);
1335
+ };
1336
+ }
1337
+ function createProxyGetElementsByClassName(querySelectorAll) {
1338
+ return function getElementsByClassName(className) {
1339
+ return querySelectorAll(`.${className}`);
1340
+ };
1341
+ }
1342
+ function createProxyGetElementsByTagName(rawDocument, app, querySelectorAll) {
1343
+ return function getElementsByTagName(tagName) {
1344
+ if (isSpecialElementTag(tagName) || !app?.showSourceCode && tagName.toLowerCase() === "script") {
1345
+ return rawDocument.getElementsByTagName(tagName);
1346
+ }
1347
+ return querySelectorAll(tagName);
1348
+ };
1349
+ }
1350
+ function createProxyGetElementsByName(querySelectorAll) {
1351
+ return function getElementsByNameNew(name) {
1352
+ return querySelectorAll(`[name="${name}"]`);
1353
+ };
1354
+ }
1355
+ function createProxyMethodMap(rawDocument, app, proxyBody) {
1356
+ const createElement = createElementWithAppKey(rawDocument, app);
1357
+ const querySelector = createProxyQuerySelector(rawDocument, app, proxyBody);
1358
+ const querySelectorAll = createProxyQuerySelectorAll(rawDocument, app);
1359
+ const getElementById = createProxyGetElementById(rawDocument, querySelector);
1360
+ const getElementsByClassName = createProxyGetElementsByClassName(querySelectorAll);
1361
+ const getElementsByTagName = createProxyGetElementsByTagName(rawDocument, app, querySelectorAll);
1362
+ const getElementsByName = createProxyGetElementsByName(querySelectorAll);
1363
+ return {
1364
+ createElement: createElement.bind(rawDocument),
1365
+ querySelector: querySelector.bind(rawDocument),
1366
+ querySelectorAll: querySelectorAll.bind(rawDocument),
1367
+ getElementById: getElementById.bind(rawDocument),
1368
+ getElementsByClassName: getElementsByClassName.bind(rawDocument),
1369
+ getElementsByTagName: getElementsByTagName.bind(rawDocument),
1370
+ getElementsByName: getElementsByName.bind(rawDocument)
1371
+ };
1372
+ }
1373
+ var createProxyDocument = (rawDocument, app) => {
1374
+ const fakeDocument = {};
1375
+ const proxyBody = createProxyBody(rawDocument, app);
1376
+ const methodMap = createProxyMethodMap(rawDocument, app, proxyBody);
1377
+ return new Proxy(fakeDocument, {
1378
+ get(_, key) {
1379
+ if (key === "body") {
1380
+ return proxyBody;
1381
+ }
1382
+ if (typeof key === "string" && key in methodMap) {
1383
+ return methodMap[key];
1384
+ }
1385
+ const result = Reflect.get(rawDocument, key);
1386
+ return typeof result === "function" ? result.bind(rawDocument) : result;
1387
+ }
1388
+ });
1389
+ };
1390
+
1391
+ // src/context/event.ts
1392
+ function rewriteDocumentAndBodyEvent() {
1393
+ const { addEventListener, removeEventListener } = window.document;
1394
+ const { addEventListener: bodyAddEventListener, removeEventListener: bodyRemoveEventListener } = window.document.body;
1395
+ const documentListenerMap = /* @__PURE__ */ new Map();
1396
+ document.addEventListener = function(type, listener, options) {
1397
+ const app = getCurrentRunningApp();
1398
+ if (app?.keepAlive) {
1399
+ const listeners = documentListenerMap.get(type) || [];
1400
+ documentListenerMap.set(type, [...listeners, listener]);
1401
+ }
1402
+ addEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
1403
+ };
1404
+ document.body.addEventListener = document.addEventListener;
1405
+ document.removeEventListener = function(type, listener, options) {
1406
+ const app = getCurrentRunningApp();
1407
+ if (app?.keepAlive) {
1408
+ const listeners = documentListenerMap.get(type) || [];
1409
+ if (listeners.length && listeners.some((l) => l === listener)) {
1410
+ listeners.splice(listeners.indexOf(listener), 1);
1411
+ }
1412
+ }
1413
+ removeEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
1414
+ };
1415
+ document.body.removeEventListener = document.removeEventListener;
1416
+ function resetDocumentAndBodyEvent() {
1417
+ const app = getCurrentRunningApp();
1418
+ if (app?.keepAlive && documentListenerMap.values()) {
1419
+ for (const [type, listeners] of documentListenerMap.entries()) {
1420
+ for (const listener of listeners || []) {
1421
+ document.removeEventListener.call(document, type, listener);
1422
+ }
1423
+ }
1424
+ }
1425
+ document.addEventListener = addEventListener;
1426
+ document.body.addEventListener = bodyAddEventListener;
1427
+ document.removeEventListener = removeEventListener;
1428
+ document.body.removeEventListener = bodyRemoveEventListener;
1429
+ documentListenerMap.clear();
1430
+ }
1431
+ return {
1432
+ resetDocumentAndBodyEvent
1433
+ };
1434
+ }
1435
+
1436
+ // src/context/function.ts
1437
+ var CLASS_REGEX = /^class\b/;
1438
+ var COMMON_CONSTRUCT_FU_REGEX = /^function\b\s[A-Z].*/;
1439
+ var ConstructFunCacheMap = /* @__PURE__ */ new WeakMap();
1440
+ function isConstructFun(fn) {
1441
+ if (fn.prototype?.constructor === fn && Object.getOwnPropertyNames(fn.prototype).length > 1) {
1442
+ return true;
1443
+ }
1444
+ if (ConstructFunCacheMap.has(fn)) {
1445
+ return ConstructFunCacheMap.get(fn);
1446
+ }
1447
+ const constructable = COMMON_CONSTRUCT_FU_REGEX.test(fn.toString()) || CLASS_REGEX.test(fn.toString());
1448
+ ConstructFunCacheMap.set(fn, constructable);
1449
+ return constructable;
1450
+ }
1451
+ var functionBoundedValueMap = /* @__PURE__ */ new WeakMap();
1452
+ function bindFunctionToRawWindow(rawWindow, value) {
1453
+ if (functionBoundedValueMap.has(value)) {
1454
+ return functionBoundedValueMap.get(value);
1455
+ }
1456
+ if (typeof value === "function" && !isConstructFun(value)) {
1457
+ const boundValue = Function.prototype.bind.call(value, rawWindow);
1458
+ for (const key in value) {
1459
+ boundValue[key] = value[key];
1460
+ }
1461
+ if (Object.hasOwn(value, "prototype") && !Object.hasOwn(boundValue, "prototype")) {
1462
+ Object.defineProperty(boundValue, "prototype", {
1463
+ enumerable: false,
1464
+ value: value.prototype,
1465
+ writable: true
1466
+ });
1467
+ }
1468
+ if (typeof value.toString === "function") {
1469
+ const valueHasInstanceToString = Object.hasOwn(value, "toString") && !Object.hasOwn(boundValue, "toString");
1470
+ const boundValueHasPrototypeToString = boundValue.toString === Function.prototype.toString;
1471
+ if (valueHasInstanceToString || boundValueHasPrototypeToString) {
1472
+ const originToStringDescriptor = Object.getOwnPropertyDescriptor(
1473
+ valueHasInstanceToString ? value : Function.prototype,
1474
+ "toString"
1475
+ );
1476
+ Object.defineProperty(boundValue, "toString", {
1477
+ ...originToStringDescriptor,
1478
+ ...originToStringDescriptor?.get ? null : { value: () => value.toString() }
1479
+ });
1480
+ }
1481
+ }
1482
+ functionBoundedValueMap.set(value, boundValue);
1483
+ return boundValue;
1484
+ }
1485
+ return value;
1486
+ }
1487
+
1488
+ // src/context/window.ts
1489
+ function rewriteWindowFunction(fakeWindow) {
1490
+ const windowEventListenerMap = /* @__PURE__ */ new Map();
1491
+ const intervalTimerList = [];
1492
+ const rawWindow = window;
1493
+ const { addEventListener, clearInterval: clearInterval2, removeEventListener, setInterval: setInterval2 } = window;
1494
+ fakeWindow.addEventListener = (type, listener, options) => {
1495
+ windowEventListenerMap.set(type, [...windowEventListenerMap.get(type) || [], listener]);
1496
+ addEventListener.call(rawWindow, type, listener, options);
1497
+ };
1498
+ fakeWindow.removeEventListener = (type, listener, options) => {
1499
+ const listenerList = windowEventListenerMap.get(type);
1500
+ if (listenerList?.length) {
1501
+ const index = listenerList.indexOf(listener);
1502
+ index > -1 && listenerList.splice(index, 1);
1503
+ }
1504
+ removeEventListener.call(rawWindow, type, listener, options);
1505
+ };
1506
+ fakeWindow.setInterval = (handler, timeout, ...args) => {
1507
+ const timer = setInterval2(handler, timeout, ...args);
1508
+ intervalTimerList.push(timer);
1509
+ return timer;
1510
+ };
1511
+ fakeWindow.clearInterval = (timer) => {
1512
+ const index = intervalTimerList.indexOf(timer);
1513
+ index > -1 && intervalTimerList.splice(index, 1);
1514
+ clearInterval2.call(rawWindow, timer);
1515
+ };
1516
+ function resetWindowFunction() {
1517
+ if (windowEventListenerMap.size) {
1518
+ windowEventListenerMap.forEach((listenerList, type) => {
1519
+ for (const listener of listenerList) {
1520
+ removeEventListener.call(rawWindow, type, listener);
1521
+ }
1522
+ });
1523
+ windowEventListenerMap.clear();
1524
+ }
1525
+ if (intervalTimerList.length) {
1526
+ for (const timer of intervalTimerList) {
1527
+ clearInterval2.call(rawWindow, timer);
1528
+ }
1529
+ }
1530
+ }
1531
+ return {
1532
+ resetWindowFunction
1533
+ };
1534
+ }
1535
+
1536
+ // src/context/sandbox.ts
1537
+ var SandBox = class {
1538
+ /** 初始化沙箱环境 */
1539
+ constructor(app) {
1540
+ this.app = app;
1541
+ const windowDescriptorSet = /* @__PURE__ */ new Set();
1542
+ const rawWindow = window;
1543
+ this.rawWindow = rawWindow;
1544
+ this.rawDocument = createProxyDocument(document, app);
1545
+ const fakeWindow = /* @__PURE__ */ Object.create({});
1546
+ fakeWindow.__BK_WEWEB_APP_KEY__ = app.appCacheKey;
1547
+ fakeWindow.__POWERED_BY_BK_WEWEB__ = true;
1548
+ fakeWindow.rawDocument = document;
1549
+ fakeWindow.rawWindow = rawWindow;
1550
+ fakeWindow.__proto__ = Window;
1551
+ this.fakeWindow = fakeWindow;
1552
+ const { resetWindowFunction } = rewriteWindowFunction(this.fakeWindow);
1553
+ this.resetWindowFunction = resetWindowFunction;
1554
+ this.windowSymbolKey = `${app.name || app.appCacheKey}`;
1555
+ this.proxyWindow = new Proxy(this.fakeWindow, {
1556
+ defineProperty: (target, key, value) => {
1557
+ if (windowDescriptorSet.has(key)) {
1558
+ return Reflect.defineProperty(rawWindow, key, value);
1559
+ }
1560
+ return Reflect.defineProperty(target, key, value);
1561
+ },
1562
+ deleteProperty: (target, key) => {
1563
+ if (Object.hasOwn(target, key)) {
1564
+ if (this.sameRawWindowKeySet.has(key)) {
1565
+ this.sameRawWindowKeySet.delete(key);
1566
+ }
1567
+ if (this.inRawWindowKeySet.has(key)) {
1568
+ Reflect.deleteProperty(rawWindow, key);
1569
+ }
1570
+ return Reflect.deleteProperty(target, key);
1571
+ }
1572
+ return true;
1573
+ },
1574
+ get: (target, key) => {
1575
+ return this.handleProxyGet(target, key, rawWindow);
1576
+ },
1577
+ getOwnPropertyDescriptor: (target, key) => {
1578
+ if (Object.hasOwn(target, key)) {
1579
+ return Object.getOwnPropertyDescriptor(target, key);
1580
+ }
1581
+ if (Object.hasOwn(rawWindow, key)) {
1582
+ windowDescriptorSet.add(key);
1583
+ const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
1584
+ if (descriptor && !descriptor.configurable) {
1585
+ descriptor.configurable = true;
1586
+ }
1587
+ return descriptor;
1588
+ }
1589
+ return void 0;
1590
+ },
1591
+ has: (target, key) => windowNativeFuncMap.has(key) || key in target || key in rawWindow,
1592
+ ownKeys: (target) => Array.from(new Set(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)))),
1593
+ set: (target, key, value) => {
1594
+ return this.handleProxySet(target, key, value, rawWindow);
1595
+ }
1596
+ });
1597
+ rawWindow[this.windowSymbolKey] = this.proxyWindow;
1598
+ }
1599
+ /** 沙箱激活状态标识 */
1600
+ active = false;
1601
+ /** 记录在原始 window 上新增的属性键集合 */
1602
+ inRawWindowKeySet = /* @__PURE__ */ new Set();
1603
+ /** 重置文档和 body 事件的函数 */
1604
+ resetDocumentAndBodyEvent;
1605
+ /** 重置 window 函数的方法 */
1606
+ resetWindowFunction;
1607
+ /** 记录与原始 window 相同的属性键集合 */
1608
+ sameRawWindowKeySet = /* @__PURE__ */ new Set();
1609
+ /** 伪造的 window 对象 */
1610
+ fakeWindow;
1611
+ /** 代理的 document 对象 */
1612
+ proxyDocument;
1613
+ /** 代理的 window 对象 */
1614
+ proxyWindow;
1615
+ /** 原始 document 对象 */
1616
+ rawDocument;
1617
+ /** 原始 window 对象 */
1618
+ rawWindow;
1619
+ /** 在 window 上的唯一标识键 */
1620
+ windowSymbolKey;
1621
+ /** 处理代理对象的 get 操作 */
1622
+ handleProxyGet(target, key, rawWindow) {
1623
+ if (key === Symbol.unscopables || windowNativeFuncMap.has(key)) {
1624
+ return rawWindow[key];
1625
+ }
1626
+ if (DEV_MICRO_APP_WINDOW_KEY_MAP[key]) {
1627
+ return this.fakeWindow[key];
1628
+ }
1629
+ if (WINDOW_ALIAS_LIST.includes(key)) {
1630
+ return this.proxyWindow;
1631
+ }
1632
+ if (key === "document") {
1633
+ this.app.registerRunningApp();
1634
+ return this.rawDocument;
1635
+ }
1636
+ if (key === "eval") {
1637
+ this.app.registerRunningApp();
1638
+ return eval;
1639
+ }
1640
+ if (this.shouldUseIframeLocation(key)) {
1641
+ if (this.app instanceof MicroAppModel && this.app.iframe?.contentWindow) {
1642
+ return this.app.iframe.contentWindow[key];
1643
+ }
1644
+ return void 0;
1217
1645
  }
1218
- return;
1219
- }
1220
- // 内存脚本执行
1221
- executeMemoryScript(app, scopedCode) {
1222
- try {
1223
- const isScopedLocation = app instanceof MicroAppModel && app.scopeLocation;
1224
- app.registerRunningApp();
1225
- new Function("window", "location", "history", scopedCode)(
1226
- app.sandBox.proxyWindow,
1227
- isScopedLocation ? app.iframe.contentWindow.location : window.location,
1228
- isScopedLocation ? app.iframe.contentWindow.history : window.history
1229
- );
1230
- } catch (e) {
1231
- console.error(e);
1646
+ if (key === "hasOwnProperty") {
1647
+ return (checkKey) => Object.hasOwn(this.fakeWindow, checkKey) || Object.hasOwn(rawWindow, checkKey);
1232
1648
  }
1233
- }
1234
- // 脚本标签执行
1235
- executeSourceScript(scriptElement, scopedCode) {
1236
- if (this.isModule) {
1237
- scriptElement.src = `${this.url}?key=${Date.now()}`;
1238
- scriptElement.setAttribute("type", "module");
1239
- } else {
1240
- scriptElement.textContent = scopedCode;
1649
+ if (key === "top" || key === "parent") {
1650
+ if (rawWindow === rawWindow.parent) {
1651
+ return this.proxyWindow;
1652
+ }
1653
+ return Reflect.get(rawWindow, key);
1241
1654
  }
1242
- this.url && scriptElement.setAttribute("origin-src", this.url);
1243
- }
1244
- // 获取脚本内容
1245
- async getCode(app) {
1246
- if (this.code.length || !this.url) {
1247
- return this.code;
1655
+ if (key === "getComputedStyle") {
1656
+ return this.createGetComputedStyleProxy(rawWindow);
1248
1657
  }
1249
- let code = "";
1250
- if (app?.source?.getScript(this.url)) {
1251
- code = app.source.getScript(this.url)?.code || "";
1658
+ if (Reflect.has(target, key) || BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
1659
+ return Reflect.get(target, key);
1252
1660
  }
1253
- if (!code && appCache.getCacheScript(this.url)) {
1254
- code = appCache.getCacheScript(this.url)?.code || "";
1661
+ const rawValue = Reflect.get(rawWindow, key);
1662
+ return bindFunctionToRawWindow(rawWindow, rawValue);
1663
+ }
1664
+ /**
1665
+ * 处理代理对象的 set 操作
1666
+ * @description 统一处理代理对象属性设置的复杂逻辑
1667
+ * @param target - 目标对象
1668
+ * @param key - 属性键
1669
+ * @param value - 属性值
1670
+ * @param rawWindow - 原始 window 对象
1671
+ * @returns boolean - 设置是否成功
1672
+ * @private
1673
+ */
1674
+ handleProxySet(target, key, value, rawWindow) {
1675
+ if (!this.active) {
1676
+ return true;
1255
1677
  }
1256
- if (!code) {
1257
- code = await fetchSource(this.url, {}, app).catch((e) => {
1258
- console.error(`fetch script ${this.url} error`, e);
1259
- return "";
1260
- });
1678
+ if (this.shouldUseIframeLocation(key)) {
1679
+ const iframe = this.app instanceof MicroAppModel ? this.app.iframe : null;
1680
+ return iframe?.contentWindow ? Reflect.set(iframe.contentWindow, key, value) : true;
1261
1681
  }
1262
- code = code.replace(/^"use\sstrict";$/gim, "");
1263
- this.code = code;
1264
- return code;
1682
+ if (key === "location") {
1683
+ Reflect.set(rawWindow, key, value);
1684
+ } else if (this.shouldSetOnTarget(target, key, rawWindow)) {
1685
+ this.setPropertyOnTarget(target, key, value, rawWindow);
1686
+ } else {
1687
+ Reflect.set(target, key, value);
1688
+ this.sameRawWindowKeySet.add(key);
1689
+ }
1690
+ this.handleWhiteListProperty(key, value, rawWindow);
1691
+ return true;
1265
1692
  }
1266
- setCode(code) {
1267
- this.code = code;
1693
+ /**
1694
+ * 判断是否应该使用 iframe 的 location
1695
+ * @description 检查是否在 iframe 模式下访问 location 相关属性
1696
+ * @param key - 属性键
1697
+ * @returns boolean - 是否使用 iframe location
1698
+ * @private
1699
+ */
1700
+ shouldUseIframeLocation(key) {
1701
+ return !!(BK_WEWEB_LOCATION_KEY_LIST.includes(key) && this.app instanceof MicroAppModel && this.app.iframe && this.app.scopeLocation);
1268
1702
  }
1269
- // 转换脚本内容
1270
- transformCode(app) {
1271
- const sourceMapUrl = "";
1272
- if (app.sandBox) {
1273
- if (this.isModule) {
1274
- return ` with(window.${app.sandBox.windowSymbolKey}){
1275
- ;${this.code}
1276
-
1277
- ${sourceMapUrl}
1278
- }`;
1279
- }
1280
- if (app.showSourceCode) {
1281
- return `;(function(window, self, globalThis){
1282
- with(window){
1283
- ${getGlobalContextCode()}
1284
-
1285
- ${this.code}
1286
-
1287
- ${sourceMapUrl}
1288
- }
1289
- }).call(window.${app.sandBox.windowSymbolKey},
1290
- window.${app.sandBox.windowSymbolKey}, window.${app.sandBox.windowSymbolKey}, window.${app.sandBox.windowSymbolKey});`;
1703
+ /**
1704
+ * 创建 getComputedStyle 方法的代理
1705
+ * @description getComputedStyle 方法创建安全的代理实现
1706
+ * @param rawWindow - 原始 window 对象
1707
+ * @returns Function - 代理后的 getComputedStyle 方法
1708
+ * @private
1709
+ */
1710
+ createGetComputedStyleProxy(rawWindow) {
1711
+ return (element, pseudoElt) => {
1712
+ if (element instanceof Element) {
1713
+ return rawWindow.getComputedStyle(element, pseudoElt);
1291
1714
  }
1292
- return `
1293
- with(window) {
1294
- try {
1295
- ${getGlobalContextCode()}
1296
-
1297
- ${this.code}
1298
-
1299
- ${sourceMapUrl}
1300
- }
1301
- catch(e) {
1302
- console.error(e)
1303
- }
1304
- }
1305
- `;
1715
+ return rawWindow.getComputedStyle(document.body, pseudoElt);
1716
+ };
1717
+ }
1718
+ /**
1719
+ * 判断是否应该在目标对象上设置属性
1720
+ * @description 检查属性设置的逻辑条件
1721
+ * @param target - 目标对象
1722
+ * @param key - 属性键
1723
+ * @param rawWindow - 原始 window 对象
1724
+ * @returns boolean - 是否在目标对象上设置
1725
+ * @private
1726
+ */
1727
+ shouldSetOnTarget(target, key, rawWindow) {
1728
+ return !Object.hasOwn(target, key) && Object.hasOwn(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key);
1729
+ }
1730
+ /**
1731
+ * 在目标对象上设置属性
1732
+ * @description 安全地在目标对象上设置属性,保持描述符特性
1733
+ * @param target - 目标对象
1734
+ * @param key - 属性键
1735
+ * @param value - 属性值
1736
+ * @param rawWindow - 原始 window 对象
1737
+ * @private
1738
+ */
1739
+ setPropertyOnTarget(target, key, value, rawWindow) {
1740
+ const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
1741
+ if (!descriptor) {
1742
+ return;
1743
+ }
1744
+ const { configurable, enumerable, writable } = descriptor;
1745
+ if (writable) {
1746
+ Object.defineProperty(target, key, {
1747
+ configurable,
1748
+ enumerable,
1749
+ value,
1750
+ writable
1751
+ });
1752
+ this.sameRawWindowKeySet.add(key);
1306
1753
  }
1307
- return this.code;
1308
1754
  }
1309
- };
1310
- function shouldSkipProperty(global, p) {
1311
- return (
1312
- // biome-ignore lint/suspicious/noPrototypeBuiltins: <explanation>
1313
- !global.hasOwnProperty(p) || !Number.isNaN(p) && p < global.length || typeof navigator !== "undefined" && navigator.userAgent.indexOf("Trident") !== -1 && global[p] && typeof window !== "undefined" && global[p].parent === window
1314
- );
1315
- }
1316
- function getGlobalProp(global, useFirstGlobalProp) {
1317
- let cnt = 0;
1318
- let foundLastProp;
1319
- let result;
1320
- for (const p in global) {
1321
- if (shouldSkipProperty(global, p)) continue;
1322
- if (cnt === 0 && p !== firstGlobalProp || cnt === 1 && p !== secondGlobalProp) return p;
1323
- if (foundLastProp) {
1324
- lastGlobalProp = p;
1325
- result = useFirstGlobalProp && result || p;
1326
- } else {
1327
- foundLastProp = p === lastGlobalProp;
1755
+ /**
1756
+ * 处理白名单属性
1757
+ * @description 处理需要在原始 window 上设置的白名单属性
1758
+ * @param key - 属性键
1759
+ * @param value - 属性值
1760
+ * @param rawWindow - 原始 window 对象
1761
+ * @private
1762
+ */
1763
+ handleWhiteListProperty(key, value, rawWindow) {
1764
+ if (WINDOW_WHITE_LIST.includes(key) && !Reflect.has(rawWindow, key) && !BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
1765
+ Reflect.set(rawWindow, key, value);
1766
+ this.inRawWindowKeySet.add(key);
1328
1767
  }
1329
- cnt += 1;
1330
1768
  }
1331
- return result;
1332
- }
1333
- function noteGlobalProps(global) {
1334
- secondGlobalProp = void 0;
1335
- firstGlobalProp = secondGlobalProp;
1336
- for (const p in global) {
1337
- if (shouldSkipProperty(global, p)) continue;
1338
- if (!firstGlobalProp) firstGlobalProp = p;
1339
- else if (!secondGlobalProp) secondGlobalProp = p;
1340
- lastGlobalProp = p;
1769
+ /**
1770
+ * 激活沙箱
1771
+ * @description 启动沙箱环境,初始化代理对象和事件处理
1772
+ * @param data - 传递给沙箱的数据(可选)
1773
+ */
1774
+ activated(data) {
1775
+ if (!this.active) {
1776
+ this.active = true;
1777
+ this.rawDocument = createProxyDocument(document, this.app);
1778
+ this.fakeWindow.__BK_WEWEB_DATA__ = data ?? {};
1779
+ const { resetDocumentAndBodyEvent } = rewriteDocumentAndBodyEvent();
1780
+ this.resetDocumentAndBodyEvent = resetDocumentAndBodyEvent;
1781
+ }
1341
1782
  }
1342
- return lastGlobalProp;
1343
- }
1344
- async function execAppScripts(app) {
1345
- const appScriptList = Array.from(app.source.scripts.values()).filter((script) => script.fromHtml || script.initial);
1346
- const commonList = appScriptList.filter((script) => !script.async && !script.defer || script.isModule);
1347
- await Promise.all(commonList.map((script) => script.getCode(app)));
1348
- await Promise.all(commonList.map((script) => script.executeCode(app)));
1349
- const deferScriptList = [];
1350
- const asyncScriptList = [];
1351
- for (const script of appScriptList) {
1352
- if (script.defer || script.async) {
1353
- if (!script.code && script.defer) {
1354
- deferScriptList.push(script.executeCode(app));
1355
- } else asyncScriptList.push(script.executeCode(app));
1783
+ /**
1784
+ * 停用沙箱
1785
+ * @description 关闭沙箱环境,清理所有副作用和修改
1786
+ */
1787
+ deactivated() {
1788
+ if (!this.active) return;
1789
+ this.active = false;
1790
+ this.resetWindowFunction();
1791
+ for (const key of this.inRawWindowKeySet) {
1792
+ Reflect.deleteProperty(window, key);
1356
1793
  }
1794
+ this.inRawWindowKeySet.clear();
1795
+ this.resetDocumentAndBodyEvent?.();
1357
1796
  }
1358
- await Promise.all([...asyncScriptList, ...deferScriptList]).catch((e) => {
1359
- console.error(e);
1360
- });
1361
- }
1797
+ };
1362
1798
 
1363
1799
  // src/mode/app.ts
1364
- var BLANK_ORIGN = "about:blank";
1800
+ var IFRAME_CONSTANTS = {
1801
+ BLANK_ORIGIN: "about:blank",
1802
+ STYLE_HIDDEN: "display: none;",
1803
+ CHROME_USER_AGENT: "Chrome",
1804
+ DEFAULT_HTML: "<head></head><body></body>",
1805
+ POLLING_INTERVAL: 0
1806
+ };
1807
+ var DEFAULT_RANDOM_LENGTH2 = 5;
1365
1808
  var MicroAppModel = class {
1366
- state = "UNSET" /* UNSET */;
1367
- // 状态
1809
+ state = AppState.UNSET;
1368
1810
  container;
1369
- // 容器
1370
1811
  data;
1371
- // 数据
1372
1812
  iframe = null;
1373
- // scoped iframe
1374
1813
  initSource;
1375
- // 初始资源
1376
1814
  isModuleApp = false;
1377
- // 是否预加载
1378
1815
  isPreLoad = false;
1379
- // 是否缓存
1380
1816
  keepAlive;
1381
1817
  mode = "app" /* APP */;
1382
- // 名称
1383
1818
  name;
1384
- // 沙箱
1385
1819
  sandBox;
1386
- // 是否隔离样式
1387
1820
  scopeCss;
1388
- // 是否隔离js
1389
1821
  scopeJs;
1390
- // 是否隔离location
1391
1822
  scopeLocation;
1392
- // 是否显示源码
1393
1823
  showSourceCode;
1394
- // 入口资源
1395
1824
  source;
1396
- // url
1397
1825
  url;
1398
- // 是否是esm应用
1399
1826
  constructor(props) {
1400
- this.name = props.id !== props.url ? props.id : random(5);
1827
+ this.name = props.id !== props.url ? props.id || random(DEFAULT_RANDOM_LENGTH2) : random(DEFAULT_RANDOM_LENGTH2);
1401
1828
  this.mode = props.mode ?? "app" /* APP */;
1402
1829
  this.container = props.container ?? void 0;
1403
1830
  this.showSourceCode = props.showSourceCode ?? false;
@@ -1409,71 +1836,40 @@ var MicroAppModel = class {
1409
1836
  this.isPreLoad = props.isPreLoad ?? false;
1410
1837
  this.keepAlive = props.keepAlive ?? false;
1411
1838
  this.initSource = props.initSource ?? [];
1412
- if (this.scopeJs) {
1413
- this.sandBox = new SandBox(this);
1414
- }
1415
- if (this.container instanceof HTMLElement) {
1416
- this.container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1417
- }
1839
+ this.initializeSandBox();
1840
+ this.setContainerAttribute();
1418
1841
  }
1419
- // 激活
1842
+ /** 激活微应用 */
1420
1843
  activated(container, callback) {
1421
1844
  this.isPreLoad = false;
1422
- this.state = "ACTIVATED" /* ACTIVATED */;
1423
- const app = this;
1845
+ this.state = AppState.ACTIVATED;
1424
1846
  if (container && this.container) {
1425
- if (container instanceof Element) container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1426
- const fragment = document.createDocumentFragment();
1427
- const list = Array.from(this.container.childNodes);
1428
- for (const node of list) {
1429
- node.__BK_WEWEB_APP_KEY__ = this.appCacheKey;
1430
- Object.defineProperties(node, {
1431
- ownerDocument: {
1432
- get() {
1433
- return app.sandBox?.rawDocument;
1434
- }
1435
- }
1436
- });
1437
- fragment.appendChild(node);
1438
- }
1439
- container.innerHTML = "";
1440
- container.appendChild(fragment);
1847
+ this.setContainerAttribute(container);
1848
+ this.transferNodes(container);
1441
1849
  this.container = container;
1442
1850
  this.initShadowRootContainer();
1443
1851
  this.sandBox?.activated(this.data);
1444
1852
  callback?.(this);
1445
1853
  }
1446
1854
  }
1447
- // 创建隔离iframe
1855
+ /** 创建隔离iframe */
1448
1856
  createIframe() {
1449
1857
  return new Promise((resolve) => {
1450
- const iframe = document.createElement("iframe");
1451
- const url = new URL(addUrlProtocol(this.url));
1452
- const isChrome = navigator.userAgent.indexOf("Chrome") > -1;
1453
- iframe.setAttribute(
1454
- "src",
1455
- `${isChrome ? BLANK_ORIGN : location.origin}${url.pathname || "/"}${url.search}${url.hash}`
1456
- );
1457
- iframe.style.cssText = "display: none;";
1858
+ const iframe = this.createIframeElement();
1458
1859
  document.body.appendChild(iframe);
1459
- if (isChrome) {
1460
- setTimeout(() => resolve(iframe), 0);
1860
+ if (this.isChromeUserAgent()) {
1861
+ setTimeout(() => resolve(iframe), IFRAME_CONSTANTS.POLLING_INTERVAL);
1461
1862
  } else {
1462
- const interval = setInterval(() => {
1463
- if (iframe.contentWindow && iframe.contentWindow.location.href !== BLANK_ORIGN) {
1464
- iframe.contentWindow.stop();
1465
- iframe.contentDocument.body.parentElement.innerHTML = "<head></head><body></body>";
1466
- clearInterval(interval);
1467
- resolve(iframe);
1468
- }
1469
- }, 0);
1863
+ this.handleNonChromeIframe(iframe, resolve);
1470
1864
  }
1471
1865
  });
1472
1866
  }
1867
+ /** 停用微应用 */
1473
1868
  deactivated() {
1474
- this.state = "DEACTIVATED" /* DEACTIVATED */;
1869
+ this.state = AppState.DEACTIVATED;
1475
1870
  this.sandBox?.deactivated();
1476
1871
  }
1872
+ /** 初始化ShadowRoot容器 */
1477
1873
  initShadowRootContainer() {
1478
1874
  if (this.container instanceof ShadowRoot) {
1479
1875
  Object.defineProperties(this.container, {
@@ -1485,51 +1881,41 @@ var MicroAppModel = class {
1485
1881
  });
1486
1882
  }
1487
1883
  }
1884
+ /** 挂载微应用 */
1488
1885
  mount(container, callback) {
1489
1886
  this.isPreLoad = false;
1490
1887
  this.container = container ?? this.container;
1491
1888
  this.initShadowRootContainer();
1492
- this.state = "MOUNTING" /* MOUNTING */;
1493
- const app = this;
1889
+ this.state = AppState.MOUNTING;
1494
1890
  if (this.container) {
1495
- if (this.container instanceof Element) this.container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1496
- const clonedNode = this.source.html.cloneNode(true);
1497
- const fragment = document.createDocumentFragment();
1498
- for (const node of Array.from(clonedNode.childNodes)) {
1499
- node.__BK_WEWEB_APP_KEY__ = this.appCacheKey;
1500
- Object.defineProperties(node, {
1501
- ownerDocument: {
1502
- get() {
1503
- return app.sandBox?.rawDocument;
1504
- }
1505
- }
1506
- });
1507
- fragment.appendChild(node);
1508
- }
1509
- this.container.innerHTML = "";
1510
- this.container.appendChild(fragment);
1891
+ this.setContainerAttribute(this.container);
1892
+ this.renderAppContent();
1511
1893
  this.sandBox?.activated(this.data);
1512
1894
  execAppScripts(this).finally(() => {
1513
- this.state = "MOUNTED" /* MOUNTED */;
1895
+ this.state = AppState.MOUNTED;
1514
1896
  callback?.(this);
1515
1897
  });
1516
1898
  }
1517
1899
  }
1900
+ /** 错误处理 */
1518
1901
  onError() {
1519
- this.state = "ERROR" /* ERROR */;
1902
+ this.state = AppState.ERROR;
1520
1903
  }
1904
+ /** 挂载处理 */
1521
1905
  onMount() {
1522
1906
  if (this.isPreLoad) return;
1523
- this.state = "LOADED" /* LOADED */;
1907
+ this.state = AppState.LOADED;
1524
1908
  this.mount();
1525
1909
  }
1910
+ /** 注册运行中的微应用 */
1526
1911
  registerRunningApp() {
1527
1912
  setCurrentRunningApp(this);
1528
1913
  Promise.resolve().then(() => setCurrentRunningApp(null));
1529
1914
  }
1915
+ /** 启动微应用 */
1530
1916
  async start() {
1531
- if (!this.source || ["ERROR" /* ERROR */, "UNSET" /* UNSET */].includes(this.status)) {
1532
- this.state = "LOADING" /* LOADING */;
1917
+ if (!this.source || this.needsReload()) {
1918
+ this.state = AppState.LOADING;
1533
1919
  if (this.scopeLocation || this.isModuleApp) {
1534
1920
  const iframe = await this.createIframe();
1535
1921
  this.iframe = iframe;
@@ -1538,12 +1924,17 @@ var MicroAppModel = class {
1538
1924
  await this.source.importEntry(this);
1539
1925
  }
1540
1926
  }
1927
+ /** 卸载微应用 */
1541
1928
  unmount(needDestroy = false) {
1542
- this.state = "UNMOUNT" /* UNMOUNT */;
1929
+ this.state = AppState.UNMOUNT;
1543
1930
  this.sandBox?.deactivated();
1544
- needDestroy && appCache.deleteApp(this.url);
1545
- this.container.innerHTML = "";
1546
- this.container = void 0;
1931
+ if (needDestroy) {
1932
+ appCache.deleteApp(this.url);
1933
+ }
1934
+ if (this.container) {
1935
+ this.container.innerHTML = "";
1936
+ this.container = void 0;
1937
+ }
1547
1938
  }
1548
1939
  get appCacheKey() {
1549
1940
  return this.url;
@@ -1551,77 +1942,159 @@ var MicroAppModel = class {
1551
1942
  get status() {
1552
1943
  return this.state;
1553
1944
  }
1554
- set status(v) {
1555
- this.state = v;
1945
+ set status(value) {
1946
+ this.state = value;
1947
+ }
1948
+ /** 初始化沙盒 */
1949
+ initializeSandBox() {
1950
+ if (this.scopeJs) {
1951
+ this.sandBox = new SandBox(this);
1952
+ }
1953
+ }
1954
+ /** 设置容器属性 */
1955
+ setContainerAttribute(container) {
1956
+ const targetContainer = container || this.container;
1957
+ if (targetContainer instanceof HTMLElement) {
1958
+ targetContainer.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
1959
+ }
1960
+ }
1961
+ /** 转移节点到新容器 */
1962
+ transferNodes(container) {
1963
+ if (!this.container) return;
1964
+ const fragment = document.createDocumentFragment();
1965
+ const nodeList = Array.from(this.container.childNodes);
1966
+ for (const node of nodeList) {
1967
+ this.setupNodeProperties(node);
1968
+ fragment.appendChild(node);
1969
+ }
1970
+ container.innerHTML = "";
1971
+ container.appendChild(fragment);
1972
+ }
1973
+ /** 设置节点属性 */
1974
+ setupNodeProperties(node) {
1975
+ const app = this;
1976
+ const nodeWithProps = node;
1977
+ nodeWithProps.__BK_WEWEB_APP_KEY__ = this.appCacheKey;
1978
+ Object.defineProperties(node, {
1979
+ ownerDocument: {
1980
+ get() {
1981
+ return app.sandBox?.rawDocument;
1982
+ }
1983
+ }
1984
+ });
1985
+ }
1986
+ /** 创建iframe元素 */
1987
+ createIframeElement() {
1988
+ const iframe = document.createElement("iframe");
1989
+ const url = new URL(addUrlProtocol(this.url));
1990
+ iframe.src = this.buildIframeSrc(url);
1991
+ iframe.style.cssText = IFRAME_CONSTANTS.STYLE_HIDDEN;
1992
+ return iframe;
1993
+ }
1994
+ /** 构建iframe源地址 */
1995
+ buildIframeSrc(url) {
1996
+ const isChrome = this.isChromeUserAgent();
1997
+ return `${isChrome ? IFRAME_CONSTANTS.BLANK_ORIGIN : location.origin}${url.pathname || "/"}${url.search}${url.hash}`;
1998
+ }
1999
+ /** 检查是否为Chrome浏览器 */
2000
+ isChromeUserAgent() {
2001
+ return navigator.userAgent.includes(IFRAME_CONSTANTS.CHROME_USER_AGENT);
2002
+ }
2003
+ /** 处理非Chrome浏览器iframe */
2004
+ handleNonChromeIframe(iframe, resolve) {
2005
+ const interval = setInterval(() => {
2006
+ if (iframe.contentWindow && iframe.contentWindow.location.href !== IFRAME_CONSTANTS.BLANK_ORIGIN) {
2007
+ iframe.contentWindow.stop();
2008
+ iframe.contentDocument.body.parentElement.innerHTML = IFRAME_CONSTANTS.DEFAULT_HTML;
2009
+ clearInterval(interval);
2010
+ resolve(iframe);
2011
+ }
2012
+ }, IFRAME_CONSTANTS.POLLING_INTERVAL);
2013
+ }
2014
+ /** 渲染应用内容 */
2015
+ renderAppContent() {
2016
+ if (!this.source) return;
2017
+ const clonedNode = this.source.html.cloneNode(true);
2018
+ const fragment = document.createDocumentFragment();
2019
+ for (const node of Array.from(clonedNode.childNodes)) {
2020
+ this.setupNodeProperties(node);
2021
+ fragment.appendChild(node);
2022
+ }
2023
+ this.container.innerHTML = "";
2024
+ this.container.appendChild(fragment);
2025
+ }
2026
+ /** 检查是否需要重新加载 */
2027
+ needsReload() {
2028
+ return this.status === AppState.ERROR || this.status === AppState.UNSET;
1556
2029
  }
1557
2030
  };
1558
2031
 
1559
2032
  // src/utils/load-source.ts
1560
- async function collectSource(soruceList) {
1561
- let source = [];
1562
- if (typeof soruceList === "function") {
1563
- source = await soruceList();
1564
- } else {
1565
- source = soruceList || [];
2033
+ var JS_FILE_REGEX = /\.js$/;
2034
+ var CSS_FILE_REGEX = /\.css$/;
2035
+ var createScriptInstance = (url) => {
2036
+ const cachedScript = appCache.getCacheScript(url);
2037
+ return new Script({
2038
+ async: false,
2039
+ code: cachedScript?.code || "",
2040
+ defer: false,
2041
+ fromHtml: false,
2042
+ initial: true,
2043
+ isModule: false,
2044
+ url
2045
+ });
2046
+ };
2047
+ var createStyleInstance = (url) => {
2048
+ const cachedStyle = appCache.getCacheStyle(url);
2049
+ return new Style({
2050
+ code: cachedStyle?.code || "",
2051
+ fromHtml: true,
2052
+ initial: true,
2053
+ prefetch: false,
2054
+ preload: false,
2055
+ url
2056
+ });
2057
+ };
2058
+ var processResourceUrl = (url, collectScript, collectStyle) => {
2059
+ try {
2060
+ const urlObj = new URL(url);
2061
+ const { pathname } = urlObj;
2062
+ if (JS_FILE_REGEX.test(pathname)) {
2063
+ collectScript.set(url, createScriptInstance(url));
2064
+ } else if (CSS_FILE_REGEX.test(pathname)) {
2065
+ collectStyle.set(url, createStyleInstance(url));
2066
+ }
2067
+ } catch {
2068
+ console.error(`\u3010bk-weweb\u3011: ${url} is invalid URL`);
1566
2069
  }
2070
+ };
2071
+ var collectSource = async (sourceList) => {
2072
+ const source = typeof sourceList === "function" ? await sourceList() : sourceList || [];
1567
2073
  if (!source.length) return {};
1568
2074
  const collectScript = /* @__PURE__ */ new Map();
1569
2075
  const collectStyle = /* @__PURE__ */ new Map();
1570
- source.forEach((str) => {
1571
- try {
1572
- const url = new URL(str);
1573
- if (url.pathname.match(/\.js$/)) {
1574
- const script = appCache.getCacheScript(str);
1575
- collectScript.set(
1576
- str,
1577
- new Script({
1578
- async: false,
1579
- code: script?.code || "",
1580
- defer: false,
1581
- fromHtml: false,
1582
- initial: true,
1583
- isModule: false,
1584
- url: str
1585
- })
1586
- );
1587
- } else if (url.pathname.match(/\.css$/)) {
1588
- const style = appCache.getCacheStyle(str);
1589
- collectStyle.set(
1590
- str,
1591
- new Style({
1592
- code: style?.code || "",
1593
- fromHtml: true,
1594
- initial: true,
1595
- prefetch: false,
1596
- preload: false,
1597
- url: str
1598
- })
1599
- );
1600
- }
1601
- } catch {
1602
- console.error(`\u3010bk-weweb\u3011: ${str} is invalid URL`);
2076
+ for (const url of source) {
2077
+ processResourceUrl(url, collectScript, collectStyle);
2078
+ }
2079
+ return { collectScript, collectStyle };
2080
+ };
2081
+ var loadGlobalSource = async (sourceList) => {
2082
+ const { collectScript, collectStyle } = await collectSource(sourceList);
2083
+ const loadPromises = [];
2084
+ if (collectScript) {
2085
+ for (const [url, script] of collectScript.entries()) {
2086
+ loadPromises.push(script.getCode());
2087
+ appCache.setBaseAppScript(url, script);
1603
2088
  }
1604
- });
1605
- return {
1606
- collectScript,
1607
- collectStyle
1608
- };
1609
- }
1610
- async function loadGlobalSource(soruceList) {
1611
- const { collectScript, collectStyle } = await collectSource(soruceList);
1612
- const promiseList = [];
1613
- collectScript && Array.from(collectScript.entries()).forEach((item) => {
1614
- promiseList.push(item[1].getCode());
1615
- appCache.setBaseAppScript(...item);
1616
- });
1617
- collectStyle && Array.from(collectStyle.entries()).forEach((item) => {
1618
- promiseList.push(item[1].getCode());
1619
- appCache.setBaseAppStyle(...item);
1620
- });
1621
- await Promise.all(promiseList).catch((e) => {
1622
- throw e;
1623
- });
1624
- }
2089
+ }
2090
+ if (collectStyle) {
2091
+ for (const [url, style] of collectStyle.entries()) {
2092
+ loadPromises.push(style.getCode());
2093
+ appCache.setBaseAppStyle(url, style);
2094
+ }
2095
+ }
2096
+ await Promise.all(loadPromises);
2097
+ };
1625
2098
 
1626
2099
  // src/entry/entry.ts
1627
2100
  var SCRIPT_TYPE_NAMES = [
@@ -1631,6 +2104,12 @@ var SCRIPT_TYPE_NAMES = [
1631
2104
  "application/ecmascript",
1632
2105
  "module"
1633
2106
  ];
2107
+ var ICON_REL_TYPES = ["apple-touch-icon", "icon", "prefetch", "preload", "prerender"];
2108
+ var HTML_FILTER_REGEX = {
2109
+ HEAD: /<\/?head>/gim,
2110
+ BODY: /<\/?body>/i,
2111
+ TS_EXTENSION: /\.ts$/
2112
+ };
1634
2113
  var EntrySource = class {
1635
2114
  constructor(url) {
1636
2115
  this.url = url;
@@ -1641,101 +2120,211 @@ var EntrySource = class {
1641
2120
  rawHtml;
1642
2121
  scripts;
1643
2122
  styles;
1644
- collectLink(link, parent, needReplaceELement = false) {
2123
+ /** 收集链接元素 */
2124
+ collectLink = (link, parent, needReplaceElement = false) => {
1645
2125
  if (link.hasAttribute("exclude")) {
1646
- return { replace: document.createComment("\u3010bk-weweb\u3011style with exclude attribute is ignored") };
2126
+ return {
2127
+ replace: document.createComment("\u3010bk-weweb\u3011style with exclude attribute is ignored")
2128
+ };
1647
2129
  }
1648
2130
  if (link.hasAttribute("ignore")) {
1649
2131
  return { replace: link };
1650
2132
  }
1651
2133
  const rel = link.getAttribute("rel");
1652
- let href = link.getAttribute("href");
1653
- let replaceElement;
2134
+ const href = link.getAttribute("href");
1654
2135
  if (rel === "stylesheet" && href) {
1655
- href = fillUpPath(href, this.url);
1656
- replaceElement = document.createComment(`\u3010bk-weweb\u3011style with href=${href}`);
1657
- let styleInstance = this.getStyle(href);
1658
- if (!styleInstance) {
1659
- styleInstance = new Style({
1660
- code: "",
1661
- fromHtml: !needReplaceELement,
1662
- prefetch: !!link.getAttribute("prefetch"),
1663
- preload: !!link.getAttribute("preload"),
1664
- url: href
1665
- });
1666
- this.styles.set(href, styleInstance);
1667
- }
1668
- !needReplaceELement && parent.replaceChild(replaceElement, link);
1669
- return { replace: replaceElement, style: styleInstance };
2136
+ return this.handleStylesheetLink(link, parent, href, needReplaceElement);
1670
2137
  }
1671
- if (rel && ["apple-touch-icon", "icon", "prefetch", "preload", "prerender"].includes(rel)) {
1672
- replaceElement = document.createComment(`\u3010bk-weweb\u3011style with rel=${rel}${href ? ` & href=${href}` : ""}`);
1673
- !needReplaceELement && parent.removeChild(link);
1674
- return { replace: replaceElement };
2138
+ if (rel && ICON_REL_TYPES.includes(rel)) {
2139
+ return this.handleIconLink(link, parent, rel, href, needReplaceElement);
1675
2140
  }
1676
2141
  if (href) {
1677
2142
  link.setAttribute("href", fillUpPath(href, this.url));
1678
2143
  }
1679
2144
  return { replace: link };
2145
+ };
2146
+ /** 收集脚本元素 */
2147
+ collectScript = (script, parent, needReplaceElement = false) => {
2148
+ if (this.shouldIgnoreScript(script)) {
2149
+ return;
2150
+ }
2151
+ if (script.hasAttribute("exclude")) {
2152
+ return this.handleExcludedScript(script, parent, needReplaceElement);
2153
+ }
2154
+ const src = script.getAttribute("src");
2155
+ if (src) {
2156
+ return this.handleExternalScript(script, parent, src, needReplaceElement);
2157
+ }
2158
+ if (script.textContent) {
2159
+ return this.handleInlineScript(script, parent, needReplaceElement);
2160
+ }
2161
+ return { replace: script };
2162
+ };
2163
+ /** 收集样式和脚本 */
2164
+ collectScriptAndStyle = (parent) => {
2165
+ this.processLinks(parent);
2166
+ this.processStyles(parent);
2167
+ this.processScripts(parent);
2168
+ this.processMetas(parent);
2169
+ this.processImages(parent);
2170
+ };
2171
+ getScript = (url) => this.scripts.get(url);
2172
+ getStyle = (urlOrCode) => {
2173
+ return this.styles.get(urlOrCode) || Array.from(this.styles.values()).find((style) => style.code === urlOrCode);
2174
+ };
2175
+ /** html entry */
2176
+ async importEntry(app) {
2177
+ await this.loadInitialSources(app);
2178
+ if (app instanceof MicroAppModel) {
2179
+ await this.importHtmlEntry(app);
2180
+ } else if (app instanceof MicroInstanceModel) {
2181
+ await this.importInstanceEntry(app);
2182
+ }
2183
+ }
2184
+ /** 微应用入口 */
2185
+ async importHtmlEntry(app) {
2186
+ const htmlStr = await this.fetchHtmlContent(app);
2187
+ if (!htmlStr) {
2188
+ console.error("load app entry error, place check");
2189
+ return Promise.reject();
2190
+ }
2191
+ this.rawHtml = htmlStr;
2192
+ const wrapElement = this.createWrapElement(htmlStr);
2193
+ this.collectScriptAndStyle(wrapElement);
2194
+ await executeAppStyles(app, wrapElement);
2195
+ this.html = wrapElement;
2196
+ }
2197
+ /** 微模块入口 */
2198
+ async importInstanceEntry(app) {
2199
+ const jsStr = await this.fetchJsContent(app);
2200
+ if (!jsStr) {
2201
+ console.error("load app entry error, place check");
2202
+ return Promise.reject();
2203
+ }
2204
+ this.scripts.set(
2205
+ this.url,
2206
+ new Script({
2207
+ async: false,
2208
+ code: jsStr,
2209
+ defer: false,
2210
+ fromHtml: true,
2211
+ isModule: HTML_FILTER_REGEX.TS_EXTENSION.test(this.url),
2212
+ url: this.url
2213
+ })
2214
+ );
1680
2215
  }
1681
- collectScript(script, parent, needReplaceELement = false) {
1682
- if (script.hasAttribute("ignore") || script.type !== "module" && isJsonpUrl(script.getAttribute("src")) || script.hasAttribute("type") && !SCRIPT_TYPE_NAMES.includes(script.type)) {
1683
- return;
2216
+ setScript = (url, script) => {
2217
+ this.scripts.set(url, script instanceof Script ? script : new Script(script));
2218
+ };
2219
+ setStyle = (url, style) => {
2220
+ this.styles.set(url, style);
2221
+ };
2222
+ /** 处理样式表链接 */
2223
+ handleStylesheetLink = (link, parent, href, needReplaceElement) => {
2224
+ const fullHref = fillUpPath(href, this.url);
2225
+ const replaceElement = document.createComment(`\u3010bk-weweb\u3011style with href=${fullHref}`);
2226
+ let styleInstance = this.getStyle(fullHref);
2227
+ if (!styleInstance) {
2228
+ styleInstance = new Style({
2229
+ code: "",
2230
+ fromHtml: !needReplaceElement,
2231
+ prefetch: !!link.getAttribute("prefetch"),
2232
+ preload: !!link.getAttribute("preload"),
2233
+ url: fullHref
2234
+ });
2235
+ this.styles.set(fullHref, styleInstance);
1684
2236
  }
1685
- let replaceElement = null;
1686
- if (script.hasAttribute("exclude")) {
1687
- replaceElement = document.createComment("\u3010bk-weweb\u3011script element with exclude attribute is removed");
1688
- !needReplaceELement && parent.replaceChild(replaceElement, script);
1689
- return { replace: replaceElement };
2237
+ if (!needReplaceElement) {
2238
+ parent.replaceChild(replaceElement, link);
1690
2239
  }
1691
- let src = script.getAttribute("src");
1692
- if (src) {
1693
- src = fillUpPath(src, this.url);
1694
- let scriptInstance = this.getScript(src);
1695
- if (!scriptInstance) {
1696
- scriptInstance = new Script({
1697
- async: script.hasAttribute("async"),
1698
- code: "",
1699
- defer: script.defer || script.type === "module",
1700
- fromHtml: !needReplaceELement,
1701
- isModule: script.type === "module",
1702
- url: src
1703
- });
1704
- this.scripts.set(src, scriptInstance);
1705
- }
1706
- replaceElement = document.createComment(`\u3010bk-weweb\u3011script with src='${src}'`);
1707
- !needReplaceELement && parent.replaceChild(replaceElement, script);
1708
- return { replace: replaceElement, script: scriptInstance };
2240
+ return { replace: replaceElement, style: styleInstance };
2241
+ };
2242
+ /**
2243
+ * 处理图标链接
2244
+ */
2245
+ handleIconLink = (link, parent, rel, href, needReplaceElement) => {
2246
+ const replaceElement = document.createComment(`\u3010bk-weweb\u3011style with rel=${rel}${href ? ` & href=${href}` : ""}`);
2247
+ if (!needReplaceElement) {
2248
+ parent.removeChild(link);
1709
2249
  }
1710
- if (script.textContent) {
1711
- const nonceStr = randomUrl();
1712
- const scriptInstance = new Script({
1713
- async: false,
1714
- // code: script.textContent.replace(/var\s+(\w+)=/gm, `window.$1 = `),
1715
- code: script.textContent,
1716
- defer: script.type === "module",
1717
- fromHtml: !needReplaceELement,
1718
- initial: false,
2250
+ return { replace: replaceElement };
2251
+ };
2252
+ /**
2253
+ * 检查是否应该忽略脚本
2254
+ */
2255
+ shouldIgnoreScript = (script) => {
2256
+ return script.hasAttribute("ignore") || // (script.type !== 'module' && isJsonpUrl(script.getAttribute('src'))) ||
2257
+ script.hasAttribute("type") && !SCRIPT_TYPE_NAMES.includes(script.type);
2258
+ };
2259
+ /**
2260
+ * 处理被排除的脚本
2261
+ */
2262
+ handleExcludedScript = (script, parent, needReplaceElement) => {
2263
+ const replaceElement = document.createComment("\u3010bk-weweb\u3011script element with exclude attribute is removed");
2264
+ if (!needReplaceElement) {
2265
+ parent.replaceChild(replaceElement, script);
2266
+ }
2267
+ return { replace: replaceElement };
2268
+ };
2269
+ /**
2270
+ * 处理外部脚本
2271
+ */
2272
+ handleExternalScript = (script, parent, src, needReplaceElement) => {
2273
+ const fullSrc = fillUpPath(src, this.url);
2274
+ let scriptInstance = this.getScript(fullSrc);
2275
+ if (!scriptInstance) {
2276
+ scriptInstance = new Script({
2277
+ async: script.hasAttribute("async"),
2278
+ code: "",
2279
+ defer: script.defer || script.type === "module",
2280
+ fromHtml: !needReplaceElement,
1719
2281
  isModule: script.type === "module",
1720
- url: nonceStr
2282
+ url: fullSrc
1721
2283
  });
1722
- this.scripts.set(nonceStr, scriptInstance);
1723
- replaceElement = document.createComment("\u3010bk-weweb\u3011script with text content");
1724
- !needReplaceELement && parent.replaceChild(replaceElement, script);
1725
- return {
1726
- replace: replaceElement,
1727
- script: scriptInstance
1728
- };
2284
+ this.scripts.set(fullSrc, scriptInstance);
1729
2285
  }
1730
- return { replace: script };
1731
- }
1732
- collectScriptAndStyle(parent) {
2286
+ const replaceElement = document.createComment(`\u3010bk-weweb\u3011script with src='${fullSrc}'`);
2287
+ if (!needReplaceElement) {
2288
+ parent.replaceChild(replaceElement, script);
2289
+ }
2290
+ return { replace: replaceElement, script: scriptInstance };
2291
+ };
2292
+ /**
2293
+ * 处理内联脚本
2294
+ */
2295
+ handleInlineScript = (script, parent, needReplaceElement) => {
2296
+ const nonceStr = randomUrl();
2297
+ const scriptInstance = new Script({
2298
+ async: false,
2299
+ code: script.textContent || "",
2300
+ defer: script.type === "module",
2301
+ fromHtml: !needReplaceElement,
2302
+ initial: false,
2303
+ isModule: script.type === "module",
2304
+ url: nonceStr
2305
+ });
2306
+ this.scripts.set(nonceStr, scriptInstance);
2307
+ const replaceElement = document.createComment("\u3010bk-weweb\u3011script with text content");
2308
+ if (!needReplaceElement) {
2309
+ parent.replaceChild(replaceElement, script);
2310
+ }
2311
+ return { replace: replaceElement, script: scriptInstance };
2312
+ };
2313
+ /**
2314
+ * 处理链接元素
2315
+ */
2316
+ processLinks = (parent) => {
1733
2317
  const links = Array.from(parent.querySelectorAll("link"));
1734
- for (const link of links || []) {
1735
- this.collectLink(link, link.parentElement);
2318
+ for (const link of links) {
2319
+ link.parentElement && this.collectLink(link, link.parentElement);
1736
2320
  }
2321
+ };
2322
+ /**
2323
+ * 处理样式元素
2324
+ */
2325
+ processStyles = (parent) => {
1737
2326
  const styles = Array.from(parent.querySelectorAll("style"));
1738
- for (const style of styles || []) {
2327
+ for (const style of styles) {
1739
2328
  if (!style.hasAttribute("exclude") && !style.hasAttribute("ignore")) {
1740
2329
  this.styles.set(
1741
2330
  randomUrl(),
@@ -1748,121 +2337,156 @@ var EntrySource = class {
1748
2337
  style.remove();
1749
2338
  }
1750
2339
  }
2340
+ };
2341
+ /**
2342
+ * 处理脚本元素
2343
+ */
2344
+ processScripts = (parent) => {
1751
2345
  const scripts = Array.from(parent.querySelectorAll("script"));
1752
2346
  for (const script of scripts) {
1753
- this.collectScript(script, script.parentElement);
2347
+ script.parentElement && this.collectScript(script, script.parentElement);
1754
2348
  }
2349
+ };
2350
+ /**
2351
+ * 处理Meta元素
2352
+ */
2353
+ processMetas = (parent) => {
1755
2354
  const metas = Array.from(parent.querySelectorAll("meta"));
1756
2355
  for (const meta of metas) {
1757
- meta.parentElement.removeChild(meta);
2356
+ meta.parentElement?.removeChild(meta);
1758
2357
  }
2358
+ };
2359
+ /**
2360
+ * 处理图片元素
2361
+ */
2362
+ processImages = (parent) => {
1759
2363
  const imgs = Array.from(parent.querySelectorAll("img"));
1760
2364
  for (const img of imgs) {
1761
2365
  if (img.hasAttribute("src")) {
1762
- img.setAttribute("src", fillUpPath(img.getAttribute("src"), this.url));
2366
+ img.setAttribute("src", fillUpPath(img.getAttribute("src") || "", this.url));
1763
2367
  }
1764
2368
  }
1765
- }
1766
- getScript(url) {
1767
- return this.scripts.get(url);
1768
- }
1769
- getStyle(urlOrCode) {
1770
- return this.styles.get(urlOrCode) || Array.from(this.styles.values()).find((style) => style.code === urlOrCode);
1771
- }
1772
- async importEntry(app) {
1773
- if (app.initSource?.length) {
1774
- const { collectScript, collectStyle } = await collectSource(app.initSource);
1775
- if (collectScript) {
1776
- this.scripts = collectScript;
1777
- }
1778
- if (collectStyle) {
1779
- this.styles = collectStyle;
1780
- }
2369
+ };
2370
+ /**
2371
+ * 加载初始资源
2372
+ */
2373
+ async loadInitialSources(app) {
2374
+ if (!app.initSource?.length) return;
2375
+ const { collectScript, collectStyle } = await collectSource(app.initSource);
2376
+ if (collectScript) {
2377
+ this.scripts = collectScript;
2378
+ }
2379
+ if (collectStyle) {
2380
+ this.styles = collectStyle;
1781
2381
  }
1782
- if (app instanceof MicroAppModel) await this.importHtmlEntry(app);
1783
- else if (app instanceof MicroInstanceModel) await this.importInstanceEntry(app);
1784
2382
  }
1785
- async importHtmlEntry(app) {
2383
+ /**
2384
+ * 获取HTML content
2385
+ */
2386
+ async fetchHtmlContent(app) {
1786
2387
  let htmlStr = appCache.getCacheHtml(this.url);
1787
2388
  if (!htmlStr) {
1788
2389
  htmlStr = await fetchSource(addUrlProtocol(this.url), { cache: "no-cache" }, app);
1789
- if (!htmlStr) {
1790
- console.error("load app entry error, place check");
1791
- return Promise.reject();
1792
- }
1793
2390
  }
1794
- this.rawHtml = htmlStr;
2391
+ return htmlStr;
2392
+ }
2393
+ /**
2394
+ * 创建顶层 root 元素
2395
+ */
2396
+ createWrapElement(htmlStr) {
1795
2397
  const wrapElement = document.createElement("div");
1796
2398
  if (wrapElement.__BK_WEWEB_APP_KEY__) {
1797
2399
  wrapElement.__BK_WEWEB_APP_KEY__ = void 0;
1798
2400
  }
1799
- wrapElement.innerHTML = htmlStr.replace(/<\/?head>/gim, "").replace(/<\/?body>/i, "");
1800
- this.collectScriptAndStyle(wrapElement);
1801
- await executeAppStyles(app, wrapElement);
1802
- this.html = wrapElement;
2401
+ wrapElement.innerHTML = htmlStr.replace(HTML_FILTER_REGEX.HEAD, "").replace(HTML_FILTER_REGEX.BODY, "");
2402
+ return wrapElement;
1803
2403
  }
1804
- async importInstanceEntry(app) {
2404
+ /**
2405
+ * 获取JS content
2406
+ */
2407
+ async fetchJsContent(app) {
1805
2408
  let jsStr = appCache.getCacheScript(this.url)?.code;
1806
2409
  if (!jsStr) {
1807
2410
  jsStr = await fetchSource(this.url, { cache: "no-cache" }, app);
1808
2411
  }
1809
- if (!jsStr) {
1810
- console.error("load app entry error, place check");
1811
- return Promise.reject();
1812
- }
1813
- this.scripts.set(
1814
- this.url,
1815
- new Script({
1816
- async: false,
1817
- code: jsStr,
1818
- defer: false,
1819
- fromHtml: true,
1820
- isModule: !!this.url.match(/\.ts$/),
1821
- url: this.url
1822
- })
1823
- );
1824
- }
1825
- setScript(url, script) {
1826
- this.scripts.set(url, script instanceof Script ? script : new Script(script));
1827
- }
1828
- setStyle(url, style) {
1829
- this.styles.set(url, style);
2412
+ return jsStr;
1830
2413
  }
1831
2414
  };
1832
2415
 
1833
2416
  // src/cache/app-cache.ts
1834
2417
  var AppCache = class {
1835
- // todo 主应用共享资源包
2418
+ /** 基础资源源,用于主应用共享资源包 */
1836
2419
  baseSource;
2420
+ /** 应用实例缓存映射表 */
1837
2421
  cache;
2422
+ /**
2423
+ * 构造函数
2424
+ * @description 初始化应用缓存管理器
2425
+ */
1838
2426
  constructor() {
1839
2427
  this.cache = /* @__PURE__ */ new Map();
1840
2428
  this.baseSource = new EntrySource(location.href);
1841
2429
  }
1842
- // 删除缓存
1843
- deleteApp(url) {
1844
- this.cache.delete(url);
2430
+ /**
2431
+ * 设置应用实例到缓存
2432
+ * @description 将应用实例添加到缓存中,使用应用的缓存键作为标识
2433
+ * @param app - 要缓存的应用实例
2434
+ */
2435
+ setApp(app) {
2436
+ this.cache.set(app.appCacheKey, app);
1845
2437
  }
1846
- // 获取缓存app
2438
+ /**
2439
+ * 获取缓存的应用实例
2440
+ * @description 根据名称或ID获取已缓存的应用实例
2441
+ * @param name - 应用名称或ID,为空时返回 undefined
2442
+ * @returns BaseModel | undefined - 应用实例或 undefined
2443
+ */
1847
2444
  getApp(name) {
1848
2445
  if (!name) return void 0;
1849
2446
  const app = this.cache.get(name);
1850
2447
  if (app) return app;
1851
- return Array.from(this.cache.values()).find((item) => item.name === name);
2448
+ const item = Array.from(this.cache.values()).find((item2) => item2.name === name);
2449
+ if (item) return item;
2450
+ return window.__BK_WEWEB_APP_KEY__ ? window.__getAppOrInstance__()?.getApp(name) : void 0;
1852
2451
  }
1853
- // 获取缓存app
1854
- getBaseAppStyle(urlOrCode) {
1855
- return this.baseSource.getStyle(urlOrCode);
2452
+ /**
2453
+ * 删除缓存的应用实例
2454
+ * @description 从缓存中移除指定URL的应用实例
2455
+ * @param url - 要删除的应用URL标识
2456
+ */
2457
+ deleteApp(url) {
2458
+ this.cache.delete(url);
1856
2459
  }
2460
+ /**
2461
+ * 获取缓存的HTML内容
2462
+ * @description 根据URL获取已缓存的HTML内容
2463
+ * @param url - 应用的URL
2464
+ * @returns string - HTML内容,未找到时返回空字符串
2465
+ */
1857
2466
  getCacheHtml(url) {
1858
2467
  const list = Array.from(this.cache.values());
1859
2468
  const app = list.find((item) => item.url === url);
1860
2469
  if (app) return app.source?.rawHtml || "";
1861
2470
  return "";
1862
2471
  }
2472
+ /**
2473
+ * 设置基础应用脚本
2474
+ * @description 将脚本添加到基础资源源中,供多个应用共享
2475
+ * @param url - 脚本的URL
2476
+ * @param script - 脚本实例
2477
+ */
2478
+ setBaseAppScript(url, script) {
2479
+ this.baseSource.setScript(url, script);
2480
+ }
2481
+ /**
2482
+ * 获取缓存的脚本资源
2483
+ * @description 从基础资源源或应用缓存中获取脚本资源
2484
+ * @param url - 脚本的URL
2485
+ * @returns Script | undefined - 脚本实例或 undefined
2486
+ */
1863
2487
  getCacheScript(url) {
1864
2488
  let script = this.baseSource.getScript(url);
1865
- if (script) return;
2489
+ if (script) return script;
1866
2490
  const list = Array.from(this.cache.values());
1867
2491
  list.some((app) => {
1868
2492
  script = app.source?.getScript(url);
@@ -1870,9 +2494,33 @@ var AppCache = class {
1870
2494
  });
1871
2495
  return script;
1872
2496
  }
2497
+ /**
2498
+ * 设置基础应用样式
2499
+ * @description 将样式添加到基础资源源中,供多个应用共享
2500
+ * @param url - 样式的URL
2501
+ * @param style - 样式实例
2502
+ */
2503
+ setBaseAppStyle(url, style) {
2504
+ this.baseSource.setStyle(url, style);
2505
+ }
2506
+ /**
2507
+ * 获取基础应用样式
2508
+ * @description 从基础资源源中获取样式资源
2509
+ * @param urlOrCode - 样式的URL或代码
2510
+ * @returns Style | undefined - 样式实例或 undefined
2511
+ */
2512
+ getBaseAppStyle(urlOrCode) {
2513
+ return this.baseSource.getStyle(urlOrCode);
2514
+ }
2515
+ /**
2516
+ * 获取缓存的样式资源
2517
+ * @description 从基础资源源或应用缓存中获取样式资源
2518
+ * @param url - 样式的URL
2519
+ * @returns Style | undefined - 样式实例或 undefined
2520
+ */
1873
2521
  getCacheStyle(url) {
1874
2522
  let style = this.baseSource.getStyle(url);
1875
- if (style) return;
2523
+ if (style) return style;
1876
2524
  const list = Array.from(this.cache.values());
1877
2525
  list.some((app) => {
1878
2526
  style = app.source?.getStyle(url);
@@ -1880,17 +2528,13 @@ var AppCache = class {
1880
2528
  });
1881
2529
  return style;
1882
2530
  }
1883
- setApp(app) {
1884
- this.cache.set(app.appCacheKey, app);
1885
- }
1886
- setBaseAppScript(url, script) {
1887
- this.baseSource.setScript(url, script);
1888
- }
1889
- setBaseAppStyle(url, style) {
1890
- this.baseSource.setStyle(url, style);
1891
- }
2531
+ /**
2532
+ * 检查是否存在活跃的应用
2533
+ * @description 判断当前是否有处于非卸载状态的应用实例
2534
+ * @returns boolean - 存在活跃应用时返回 true
2535
+ */
1892
2536
  get hasActiveApp() {
1893
- return Array.from(this.cache.values()).some((app) => app.status !== "UNMOUNT" /* UNMOUNT */);
2537
+ return Array.from(this.cache.values()).some((app) => app.status !== AppState.UNMOUNT);
1894
2538
  }
1895
2539
  };
1896
2540
  var appCache = new AppCache();
@@ -1908,8 +2552,8 @@ function getStyleSource(url, style, originLink) {
1908
2552
  appCache.setBaseAppStyle(url, style);
1909
2553
  replaceStyle.textContent = data;
1910
2554
  dispatchLinkOrScriptLoad(originLink);
1911
- }).catch((err) => {
1912
- console.error(err);
2555
+ }).catch((error) => {
2556
+ console.error("Failed to load style resource:", error);
1913
2557
  dispatchLinkOrScriptError(originLink);
1914
2558
  });
1915
2559
  return replaceStyle;
@@ -1924,59 +2568,67 @@ function getScriptSource(url, script, originScript) {
1924
2568
  if (!url.startsWith("inline-")) {
1925
2569
  originScript.setAttribute("origin-src", url);
1926
2570
  }
1927
- } catch (e) {
1928
- console.error(e, url);
2571
+ } catch (error) {
2572
+ console.error("Failed to set script content:", error, url);
1929
2573
  }
1930
2574
  dispatchLinkOrScriptLoad(originScript);
1931
- }).catch((err) => {
1932
- console.error(err);
2575
+ }).catch((error) => {
2576
+ console.error("Failed to load script resource:", error);
1933
2577
  dispatchLinkOrScriptError(originScript);
1934
2578
  });
1935
2579
  return replaceScript;
1936
2580
  }
2581
+ function processLinkElement(linkElement) {
2582
+ const rel = linkElement.getAttribute("rel");
2583
+ let href = linkElement.getAttribute("href");
2584
+ if (rel === "stylesheet" && href) {
2585
+ href = fillUpPath(href, location.origin);
2586
+ const replaceStyle = document.createElement("style");
2587
+ const styleInstance = new Style({
2588
+ code: "",
2589
+ fromHtml: false,
2590
+ url: href
2591
+ });
2592
+ getStyleSource(href, styleInstance, linkElement);
2593
+ return replaceStyle;
2594
+ }
2595
+ return linkElement;
2596
+ }
2597
+ function processScriptElement(scriptElement) {
2598
+ let src = scriptElement.getAttribute("src");
2599
+ if (src && scriptElement.type !== "module") {
2600
+ src = fillUpPath(src, location.origin);
2601
+ const script = new Script({
2602
+ async: scriptElement.hasAttribute("async"),
2603
+ code: "",
2604
+ defer: scriptElement.defer || scriptElement.type === "module",
2605
+ fromHtml: false,
2606
+ isModule: false
2607
+ });
2608
+ appCache.setBaseAppScript(src, script);
2609
+ const replaceElement = getScriptSource(src, script, scriptElement);
2610
+ return replaceElement || scriptElement;
2611
+ }
2612
+ return scriptElement;
2613
+ }
1937
2614
  function createNewNode(child) {
1938
2615
  if (child instanceof HTMLLinkElement) {
1939
- const rel = child.getAttribute("rel");
1940
- let href = child.getAttribute("href");
1941
- if (rel === "stylesheet" && href) {
1942
- href = fillUpPath(href, location.origin);
1943
- const replaceStyle = document.createElement("style");
1944
- const styleInstance = new Style({
1945
- code: "",
1946
- fromHtml: false,
1947
- url: href
1948
- });
1949
- getStyleSource(href, styleInstance, child);
1950
- return replaceStyle;
1951
- }
2616
+ return processLinkElement(child);
1952
2617
  }
1953
2618
  if (child instanceof HTMLScriptElement) {
1954
- let src = child.getAttribute("src");
1955
- if (src && child.type !== "module") {
1956
- src = fillUpPath(src, location.origin);
1957
- const script = new Script({
1958
- async: child.hasAttribute("async"),
1959
- code: "",
1960
- defer: child.defer || child.type === "module",
1961
- fromHtml: false,
1962
- isModule: false
1963
- });
1964
- appCache.setBaseAppScript(src, script);
1965
- const replaceElement = getScriptSource(src, script, child);
1966
- return replaceElement || child;
1967
- }
2619
+ return processScriptElement(child);
1968
2620
  }
1969
2621
  return child;
1970
2622
  }
1971
2623
  function isLinkOrScript(node) {
1972
2624
  return node instanceof HTMLLinkElement || node instanceof HTMLScriptElement;
1973
2625
  }
1974
- function baseElementInertHandle(parent, newChild, passiveChild, rawMethod) {
2626
+ function baseElementInertHandle(parent, newChild, referenceChild, rawMethod) {
1975
2627
  if (isLinkOrScript(newChild)) {
1976
2628
  const targetChild = createNewNode(newChild);
1977
- return rawMethod.call(parent, targetChild, passiveChild);
2629
+ return rawMethod.call(parent, targetChild, referenceChild);
1978
2630
  }
1979
- return rawMethod.call(parent, newChild, passiveChild);
2631
+ return rawMethod.call(parent, newChild, referenceChild);
1980
2632
  }
1981
2633
  function baseElementAppendHandle(parent, newChild, rawMethod) {
1982
2634
  if (isLinkOrScript(newChild)) {
@@ -1987,10 +2639,15 @@ function baseElementAppendHandle(parent, newChild, rawMethod) {
1987
2639
  }
1988
2640
 
1989
2641
  // src/base-app/collect-source.ts
1990
- function collectBaseSource() {
1991
- const rawBodyAppendChild = HTMLBodyElement.prototype.appendChild;
1992
- const rawHeadAppendChild = HTMLHeadElement.prototype.appendChild;
1993
- const rawHeadInsertBefore = HTMLHeadElement.prototype.appendChild;
2642
+ function cacheOriginalDOMMethods() {
2643
+ return {
2644
+ rawBodyAppendChild: HTMLBodyElement.prototype.appendChild,
2645
+ rawHeadAppendChild: HTMLHeadElement.prototype.appendChild,
2646
+ rawHeadInsertBefore: HTMLHeadElement.prototype.insertBefore
2647
+ };
2648
+ }
2649
+ function overrideDOMMethods(originalMethods) {
2650
+ const { rawBodyAppendChild, rawHeadAppendChild, rawHeadInsertBefore } = originalMethods;
1994
2651
  HTMLBodyElement.prototype.appendChild = function(newChild) {
1995
2652
  return baseElementAppendHandle(this, newChild, rawBodyAppendChild);
1996
2653
  };
@@ -2000,22 +2657,39 @@ function collectBaseSource() {
2000
2657
  HTMLHeadElement.prototype.insertBefore = function(newChild, refChild) {
2001
2658
  return baseElementInertHandle(this, newChild, refChild, rawHeadInsertBefore);
2002
2659
  };
2003
- window.addEventListener("load", () => {
2004
- const nodeList = document.head.querySelectorAll("style");
2005
- for (const node of Array.from(nodeList)) {
2006
- node.textContent && appCache.setBaseAppStyle(
2007
- randomUrl(),
2008
- new Style({
2009
- code: node.textContent,
2660
+ }
2661
+ function collectExistingStyles() {
2662
+ const styleNodes = document.head.querySelectorAll("style");
2663
+ for (const styleNode of Array.from(styleNodes)) {
2664
+ const textContent = styleNode.textContent;
2665
+ if (textContent) {
2666
+ try {
2667
+ const style = new Style({
2668
+ code: textContent,
2010
2669
  fromHtml: false,
2011
2670
  url: ""
2012
- })
2013
- );
2671
+ });
2672
+ appCache.setBaseAppStyle(randomUrl(), style);
2673
+ } catch (error) {
2674
+ console.warn("Failed to collect style element:", error);
2675
+ }
2014
2676
  }
2015
- });
2677
+ }
2678
+ }
2679
+ function setupLoadEventListener() {
2680
+ window.addEventListener("load", collectExistingStyles);
2681
+ }
2682
+ function collectBaseSource() {
2683
+ const originalMethods = cacheOriginalDOMMethods();
2684
+ overrideDOMMethods(originalMethods);
2685
+ setupLoadEventListener();
2016
2686
  }
2017
2687
 
2018
2688
  // src/context/element.ts
2689
+ var RESOURCE_ATTRIBUTES = ["src", "srcset"];
2690
+ var LINK_ATTRIBUTES = ["href"];
2691
+ var RESOURCE_TAG_NAMES = ["IMG", "SCRIPT"];
2692
+ var LINK_TAG_NAMES = ["LINK"];
2019
2693
  var { setAttribute } = Element.prototype;
2020
2694
  var {
2021
2695
  append,
@@ -2030,47 +2704,99 @@ var {
2030
2704
  } = HTMLHeadElement.prototype;
2031
2705
  var rawHead = document.head;
2032
2706
  var hasRewrite = false;
2033
- function rewriteBodyAndHeaderMethods() {
2034
- if (hasRewrite) return;
2035
- hasRewrite = true;
2036
- Element.prototype.setAttribute = function(key, value) {
2037
- const tagName = this.tagName.toLocaleUpperCase();
2038
- if ((["src", "srcset"].includes(key) && ["IMG", "SCRIPT"].includes(tagName) || key === "href" && ["LINK"].includes(tagName)) && this.__BK_WEWEB_APP_KEY__ && appCache.getApp(this.__BK_WEWEB_APP_KEY__ || "")) {
2039
- setAttribute.call(this, key, fillUpPath(value, appCache.getApp(this.__BK_WEWEB_APP_KEY__).url));
2040
- } else {
2041
- setAttribute.call(this, key, value);
2707
+ function shouldProcessResourcePath(key, tagName) {
2708
+ const upperTagName = tagName.toUpperCase();
2709
+ return RESOURCE_ATTRIBUTES.includes(key) && RESOURCE_TAG_NAMES.includes(upperTagName) || LINK_ATTRIBUTES.includes(key) && LINK_TAG_NAMES.includes(upperTagName);
2710
+ }
2711
+ function getElementApp(element) {
2712
+ if (!element.__BK_WEWEB_APP_KEY__) {
2713
+ return null;
2714
+ }
2715
+ return appCache.getApp(element.__BK_WEWEB_APP_KEY__);
2716
+ }
2717
+ function createOverriddenSetAttribute() {
2718
+ return function(key, value) {
2719
+ const tagName = this.tagName.toUpperCase();
2720
+ if (shouldProcessResourcePath(key, tagName) && this.__BK_WEWEB_APP_KEY__) {
2721
+ const app = getElementApp(this);
2722
+ if (app) {
2723
+ setAttribute.call(this, key, fillUpPath(value, app.url));
2724
+ return;
2725
+ }
2042
2726
  }
2727
+ setAttribute.call(this, key, value);
2043
2728
  };
2044
- HTMLBodyElement.prototype.appendChild = function appendChildNew(newChild) {
2045
- if (newChild.__KEEP_ALIVE__ && isSpecialElement(newChild)) return headAppendChild.call(rawHead, newChild);
2046
- return elementAppendHandler(this, newChild, bodyAppendChild2);
2729
+ }
2730
+ function handleKeepAliveElement(newChild) {
2731
+ if (newChild.__KEEP_ALIVE__ && isSpecialElement(newChild)) {
2732
+ return headAppendChild.call(rawHead, newChild);
2733
+ }
2734
+ return null;
2735
+ }
2736
+ function createOverriddenAppendChild() {
2737
+ return function(newChild) {
2738
+ const keepAliveResult = handleKeepAliveElement(newChild);
2739
+ if (keepAliveResult) {
2740
+ return keepAliveResult;
2741
+ }
2742
+ const node = elementAppendHandler(this, newChild, bodyAppendChild2);
2743
+ if (node?.tagName === "STYLE") {
2744
+ node.insertAdjacentElement = createOverriddenInsertAdjacentElement();
2745
+ }
2746
+ return node;
2047
2747
  };
2048
- HTMLBodyElement.prototype.append = function(...nodes) {
2748
+ }
2749
+ function createOverriddenAppend() {
2750
+ return function(...nodes) {
2049
2751
  nodes.forEach((node) => {
2050
- if (node.__KEEP_ALIVE__ && isSpecialElement(node)) {
2051
- return headAppendChild.call(rawHead, node);
2752
+ const keepAliveResult = handleKeepAliveElement(node);
2753
+ if (keepAliveResult) {
2754
+ return;
2052
2755
  }
2053
2756
  elementAppendHandler(this, node, bodyAppendChild2);
2054
2757
  });
2055
2758
  };
2056
- HTMLHeadElement.prototype.appendChild = HTMLBodyElement.prototype.appendChild;
2057
- HTMLHeadElement.prototype.insertBefore = function(newChild, refChild) {
2058
- return elementInsertHandler(this, newChild, refChild, headInsertBefore);
2059
- };
2060
- HTMLBodyElement.prototype.insertBefore = function(newChild, refChild) {
2759
+ }
2760
+ function createOverriddenInsertBefore() {
2761
+ return function(newChild, refChild) {
2061
2762
  return elementInsertHandler(this, newChild, refChild, headInsertBefore);
2062
2763
  };
2063
- HTMLBodyElement.prototype.removeChild = function removeChildNew(oldChild) {
2064
- const app = appCache.getApp(oldChild.__BK_WEWEB_APP_KEY__);
2764
+ }
2765
+ function createOverriddenRemoveChild() {
2766
+ return function(oldChild) {
2767
+ const app = oldChild.__BK_WEWEB_APP_KEY__ ? appCache.getApp(oldChild.__BK_WEWEB_APP_KEY__) : null;
2065
2768
  if (app?.container?.contains(oldChild)) {
2066
- const node = bodyRemoveChild.call(app.container, oldChild);
2067
- return node;
2769
+ return bodyRemoveChild.call(app.container, oldChild);
2068
2770
  }
2069
2771
  if (this.contains(oldChild)) {
2070
2772
  return bodyRemoveChild.call(this, oldChild);
2071
2773
  }
2072
2774
  return oldChild;
2073
2775
  };
2776
+ }
2777
+ var insertAdjacentElement = createOverriddenInsertAdjacentElement();
2778
+ function createOverriddenInsertAdjacentElement() {
2779
+ return function(_where, element) {
2780
+ const node = elementAppendHandler(this, element, headAppendChild);
2781
+ if (node?.tagName === "STYLE") {
2782
+ node.insertAdjacentElement = insertAdjacentElement;
2783
+ }
2784
+ return node;
2785
+ };
2786
+ }
2787
+ function rewriteBodyAndHeaderMethods() {
2788
+ if (hasRewrite || window.__BK_WEWEB_HAS_REWRITE__) {
2789
+ return;
2790
+ }
2791
+ hasRewrite = true;
2792
+ window.__BK_WEWEB_HAS_REWRITE__ = true;
2793
+ Element.prototype.setAttribute = createOverriddenSetAttribute();
2794
+ HTMLBodyElement.prototype.appendChild = createOverriddenAppendChild();
2795
+ HTMLBodyElement.prototype.append = createOverriddenAppend();
2796
+ HTMLBodyElement.prototype.insertBefore = createOverriddenInsertBefore();
2797
+ HTMLBodyElement.prototype.removeChild = createOverriddenRemoveChild();
2798
+ HTMLHeadElement.prototype.appendChild = HTMLBodyElement.prototype.appendChild;
2799
+ HTMLHeadElement.prototype.insertBefore = createOverriddenInsertBefore();
2074
2800
  HTMLHeadElement.prototype.removeChild = HTMLBodyElement.prototype.removeChild;
2075
2801
  }
2076
2802
  function resetBodyAndHeaderMethods() {
@@ -2086,31 +2812,31 @@ function resetBodyAndHeaderMethods() {
2086
2812
  hasRewrite = false;
2087
2813
  }
2088
2814
 
2089
- // src/lifecircle/before-load.ts
2815
+ // src/lifecycle/before-load.ts
2090
2816
  function beforeLoad() {
2091
2817
  rewriteBodyAndHeaderMethods();
2092
2818
  }
2093
2819
 
2094
- // src/lifecircle/activated.ts
2820
+ // src/lifecycle/activated.ts
2095
2821
  function activated(appKey, container, callback) {
2096
2822
  const app = appCache.getApp(appKey);
2097
- if (app?.status === "DEACTIVATED" /* DEACTIVATED */ && app.keepAlive) {
2823
+ if (app?.status === AppState.DEACTIVATED && app.keepAlive) {
2098
2824
  nextTask(() => {
2099
2825
  beforeLoad();
2100
2826
  app.activated(container, callback);
2101
2827
  });
2102
- } else {
2103
- app && nextTask(() => {
2828
+ } else if (app) {
2829
+ nextTask(() => {
2104
2830
  beforeLoad();
2105
2831
  app.mount(container, callback);
2106
2832
  });
2107
2833
  }
2108
2834
  }
2109
2835
 
2110
- // src/lifecircle/deactivated.ts
2836
+ // src/lifecycle/deactivated.ts
2111
2837
  function deactivated(appKey) {
2112
2838
  const app = appCache.getApp(appKey);
2113
- if (app && ["ACTIVATED" /* ACTIVATED */, "MOUNTED" /* MOUNTED */].includes(app.status)) {
2839
+ if (app && [AppState.ACTIVATED, AppState.MOUNTED].some((status) => status === app.status)) {
2114
2840
  app.keepAlive ? app.deactivated() : app.unmount();
2115
2841
  }
2116
2842
  if (!appCache.hasActiveApp) {
@@ -2118,10 +2844,13 @@ function deactivated(appKey) {
2118
2844
  }
2119
2845
  }
2120
2846
 
2121
- // src/lifecircle/load.ts
2847
+ // src/lifecycle/load.ts
2848
+ var STATUS_CHECK_INTERVAL = 300;
2122
2849
  async function load(props) {
2123
2850
  beforeLoad();
2124
- if (props.mode === "js" /* INSTANCE */) return await loadInstance(props);
2851
+ if (props.mode === "js" /* INSTANCE */) {
2852
+ return await loadInstance(props);
2853
+ }
2125
2854
  return await loadApp(props);
2126
2855
  }
2127
2856
  async function loadApp(props) {
@@ -2130,6 +2859,8 @@ async function loadApp(props) {
2130
2859
  if (!instance) {
2131
2860
  instance = new MicroAppModel(props);
2132
2861
  appCache.setApp(instance);
2862
+ } else {
2863
+ instance.data = props.data || instance.data || {};
2133
2864
  }
2134
2865
  await instance.start();
2135
2866
  return instance;
@@ -2142,23 +2873,26 @@ function loadInstance(props) {
2142
2873
  instance = new MicroInstanceModel(props);
2143
2874
  appCache.setApp(instance);
2144
2875
  instance.start().then(() => resolve(instance));
2145
- } else if (["MOUNTING" /* MOUNTING */, "UNSET" /* UNSET */].includes(instance.status)) {
2876
+ return;
2877
+ }
2878
+ if (instance.status in [AppState.MOUNTING, AppState.UNSET]) {
2146
2879
  const timer = setInterval(() => {
2147
- if (["ERROR" /* ERROR */, "MOUNTED" /* MOUNTED */].includes(instance.status)) {
2880
+ if (instance.status in [AppState.ERROR, AppState.MOUNTED]) {
2148
2881
  resolve(instance);
2149
2882
  clearInterval(timer);
2150
2883
  }
2151
- }, 300);
2152
- } else {
2153
- resolve(instance);
2884
+ }, STATUS_CHECK_INTERVAL);
2885
+ return;
2154
2886
  }
2887
+ instance.data = props.data || instance.data || {};
2888
+ resolve(instance);
2155
2889
  });
2156
2890
  }
2157
2891
 
2158
- // src/lifecircle/unmount.ts
2892
+ // src/lifecycle/unmount.ts
2159
2893
  function unmount(appKey) {
2160
2894
  const app = appCache.getApp(appKey);
2161
- if (app && app.status !== "UNMOUNT" /* UNMOUNT */) {
2895
+ if (app && app.status !== AppState.UNMOUNT) {
2162
2896
  app.unmount();
2163
2897
  }
2164
2898
  if (!appCache.hasActiveApp) {
@@ -2166,48 +2900,102 @@ function unmount(appKey) {
2166
2900
  }
2167
2901
  }
2168
2902
 
2169
- // src/component/web-compnent.ts
2903
+ // src/component/web-component.ts
2170
2904
  var BkWewebElement = class extends HTMLElement {
2905
+ /** 应用 URL 缓存 */
2171
2906
  appUrl = "";
2907
+ /** 组件连接状态标识 */
2172
2908
  connected = false;
2909
+ /**
2910
+ * 观察的属性列表
2911
+ * @description 定义需要监听变化的属性名称列表
2912
+ * @returns string[] - 属性名称数组
2913
+ */
2173
2914
  static get observedAttributes() {
2174
2915
  return ["url" /* url */];
2175
2916
  }
2917
+ /**
2918
+ * 获取布尔类型属性值
2919
+ * @description 解析布尔类型的自定义属性,支持驼峰和短横线命名
2920
+ * @param name - 属性名称
2921
+ * @returns boolean | undefined - 属性值或 undefined
2922
+ * @private
2923
+ */
2176
2924
  getBooleanAttr(name) {
2177
- return this.hasAttribute(name) || this.hasAttribute(name.replace(/([A-Z])/g, "-$1").toLocaleLowerCase()) ? this.getAttribute(name) !== "false" : void 0;
2925
+ const hasAttr = this.hasAttribute(name) || this.hasAttribute(name.replace(/([A-Z])/g, "-$1").toLocaleLowerCase());
2926
+ return hasAttr ? this.getAttribute(name) !== "false" : void 0;
2178
2927
  }
2928
+ /**
2929
+ * 处理属性变化的内部逻辑
2930
+ * @description 当属性发生变化时执行的处理逻辑
2931
+ * @returns Promise<void>
2932
+ * @private
2933
+ */
2179
2934
  async handleAttributeChanged() {
2180
2935
  if (!this.appKey) return;
2181
- if (this.getBooleanAttr("setShodowDom" /* setShodowDom */)) {
2936
+ if (this.setShadowDomAttr) {
2182
2937
  this.attachShadow({ mode: "open" });
2183
2938
  }
2184
2939
  const app = appCache.getApp(this.appKey);
2185
- if (app && app.url === this.appUrl && (app.isPreLoad || app.status === "UNMOUNT" /* UNMOUNT */)) {
2940
+ if (app && app.url === this.appUrl && (app.isPreLoad || app.status === AppState.UNMOUNT)) {
2186
2941
  activated(this.appKey, this.shadowRoot ?? this);
2187
2942
  return;
2188
2943
  }
2189
2944
  await load(this.appProps);
2190
2945
  }
2946
+ /**
2947
+ * 属性变化回调
2948
+ * @description 当观察的属性发生变化时触发
2949
+ * @param attr - 变化的属性名
2950
+ * @param _oldVal - 旧值(未使用)
2951
+ * @param newVal - 新值
2952
+ */
2191
2953
  attributeChangedCallback(attr, _oldVal, newVal) {
2192
2954
  if (attr !== "url" /* url */ || this[attr] === newVal || !this.connected) return;
2193
2955
  this.appUrl = newVal;
2194
2956
  const cacheApp = appCache.getApp(this.appKey);
2195
- (this.connected || cacheApp) && this.handleAttributeChanged();
2957
+ if (this.connected || cacheApp) {
2958
+ this.handleAttributeChanged();
2959
+ }
2960
+ }
2961
+ /**
2962
+ * 获取是否启用 Shadow DOM 属性
2963
+ * @description 获取是否启用 Shadow DOM 属性 兼容旧版使用
2964
+ * @returns boolean | undefined - 是否启用 Shadow DOM 属性
2965
+ */
2966
+ get setShadowDomAttr() {
2967
+ return this.getBooleanAttr("setShadowDom" /* setShadowDom */) ?? this.getBooleanAttr("setShodowDom" /* setShodowDom */);
2196
2968
  }
2969
+ /**
2970
+ * 组件连接到 DOM 时的回调
2971
+ * @description 当自定义元素被插入到 DOM 时触发
2972
+ * @returns Promise<void>
2973
+ */
2197
2974
  async connectedCallback() {
2198
- if (this.getBooleanAttr("setShodowDom" /* setShodowDom */) && !this.shadowRoot) {
2975
+ if (this.setShadowDomAttr && !this.shadowRoot) {
2199
2976
  this.attachShadow({ delegatesFocus: false, mode: "open" });
2200
2977
  }
2201
2978
  await load(this.appProps);
2202
2979
  activated(this.appKey, this.shadowRoot ?? this);
2203
2980
  this.connected = true;
2204
2981
  }
2982
+ /**
2983
+ * 组件从 DOM 断开时的回调
2984
+ * @description 当自定义元素从 DOM 中移除时触发
2985
+ */
2205
2986
  disconnectedCallback() {
2206
2987
  this.connected = false;
2207
2988
  if (this.appProps.keepAlive) {
2208
2989
  deactivated(this.appKey);
2209
- } else unmount(this.appKey);
2990
+ } else {
2991
+ unmount(this.appKey);
2992
+ }
2210
2993
  }
2994
+ /**
2995
+ * 获取应用数据
2996
+ * @description 解析 data 属性中的 JSON 数据
2997
+ * @returns Record<string, unknown> - 应用数据对象
2998
+ */
2211
2999
  get appData() {
2212
3000
  if (this.hasAttribute("data" /* data */)) {
2213
3001
  try {
@@ -2217,49 +3005,60 @@ var BkWewebElement = class extends HTMLElement {
2217
3005
  }
2218
3006
  return {};
2219
3007
  }
2220
- // 考虑到js模式下 需要js bundle的复用性 需用户设置id属性 如果单实例下则可以不用配置
3008
+ /**
3009
+ * 获取应用标识符
3010
+ * @description 优先使用 id 属性,其次使用 url 属性作为应用标识
3011
+ * 考虑到 JS 模式下需要 JS bundle 的复用性,需用户设置 id 属性
3012
+ * 如果是单实例应用则可以不用配置 id
3013
+ * @returns string | null - 应用标识符或 null
3014
+ */
2221
3015
  get appKey() {
2222
3016
  return this.getAttribute("id" /* id */) || this.getAttribute("url" /* url */);
2223
3017
  }
3018
+ /**
3019
+ * 获取应用配置属性
3020
+ * @description 根据模式返回相应的应用配置对象
3021
+ * @returns IAppModelProps | IJsModelProps - 应用配置对象
3022
+ */
2224
3023
  get appProps() {
3024
+ const commonProps = {
3025
+ container: this.shadowRoot ?? this,
3026
+ data: this.appData,
3027
+ id: this.appKey,
3028
+ keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
3029
+ showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
3030
+ url: this.getAttribute("url" /* url */)
3031
+ };
2225
3032
  if (this.getAttribute("mode") === "js" /* INSTANCE */) {
2226
3033
  return {
2227
- container: this.shadowRoot ?? this,
2228
- data: this.appData,
2229
- id: this.appKey,
2230
- keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
3034
+ ...commonProps,
2231
3035
  mode: "js" /* INSTANCE */,
2232
- scopeCss: this.getBooleanAttr("scopeCss" /* scopeCss */) && !this.getBooleanAttr("setShodowDom" /* setShodowDom */),
2233
- scopeJs: this.getBooleanAttr("scopeJs" /* scopeJs */),
2234
- showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
2235
- url: this.getAttribute("url" /* url */)
3036
+ scopeCss: this.getBooleanAttr("scopeCss" /* scopeCss */) && !this.setShadowDomAttr,
3037
+ scopeJs: this.getBooleanAttr("scopeJs" /* scopeJs */)
2236
3038
  };
2237
3039
  }
2238
3040
  return {
2239
- container: this.shadowRoot ?? this,
2240
- data: this.appData,
2241
- id: this.appKey,
2242
- keepAlive: this.getBooleanAttr("keepAlive" /* keepAlive */),
3041
+ ...commonProps,
2243
3042
  mode: "app" /* APP */,
2244
- scopeCss: !this.getBooleanAttr("setShodowDom" /* setShodowDom */),
3043
+ scopeCss: !this.setShadowDomAttr,
2245
3044
  scopeJs: !this.getBooleanAttr("scopeJs" /* scopeJs */),
2246
- scopeLocation: this.getBooleanAttr("scopeLocation" /* scopeLocation */),
2247
- showSourceCode: this.getBooleanAttr("showSourceCode" /* showSourceCode */),
2248
- url: this.getAttribute("url" /* url */)
3045
+ scopeLocation: this.getBooleanAttr("scopeLocation" /* scopeLocation */)
2249
3046
  };
2250
3047
  }
2251
3048
  };
2252
3049
 
2253
- // src/lifecircle/mount.ts
3050
+ // src/lifecycle/mount.ts
2254
3051
  function mount(appKey, container, callback) {
2255
3052
  const app = appCache.getApp(appKey);
2256
- app && nextTask(() => {
2257
- beforeLoad();
2258
- app.mount(container, callback);
2259
- });
3053
+ if (app) {
3054
+ nextTask(() => {
3055
+ beforeLoad();
3056
+ app.mount(container, callback);
3057
+ });
3058
+ }
2260
3059
  }
2261
3060
 
2262
- // src/lifecircle/unload.ts
3061
+ // src/lifecycle/unload.ts
2263
3062
  function unload(url) {
2264
3063
  appCache.deleteApp(url);
2265
3064
  }
@@ -2291,19 +3090,19 @@ function preLoadSource(sourceList) {
2291
3090
  var CUSTOM_ELEMENT_TAG = "bk-weweb";
2292
3091
  var WeWeb = class {
2293
3092
  fetchSource;
2294
- webcomponentTag = CUSTOM_ELEMENT_TAG;
3093
+ webComponentTag = CUSTOM_ELEMENT_TAG;
2295
3094
  constructor() {
2296
3095
  if (!window.customElements.get(CUSTOM_ELEMENT_TAG)) {
2297
3096
  window.customElements.define(CUSTOM_ELEMENT_TAG, BkWewebElement);
2298
3097
  }
2299
3098
  }
2300
- // 设置自定义dom标签名
3099
+ /** 设置自定义DOM标签名 */
2301
3100
  setWebComponentTag() {
2302
- if (!window.customElements.get(this.webcomponentTag)) {
2303
- window.customElements.define(this.webcomponentTag, BkWewebElement);
3101
+ if (!window.customElements.get(this.webComponentTag)) {
3102
+ window.customElements.define(this.webComponentTag, BkWewebElement);
2304
3103
  }
2305
3104
  }
2306
- // todo set some global start props
3105
+ /** 启动WeWeb */
2307
3106
  start(option) {
2308
3107
  if (option?.collectBaseSource) {
2309
3108
  collectBaseSource();
@@ -2311,7 +3110,7 @@ var WeWeb = class {
2311
3110
  if (typeof option?.fetchSource === "function") {
2312
3111
  this.fetchSource = option.fetchSource;
2313
3112
  }
2314
- this.webcomponentTag = option?.webcomponentTag || CUSTOM_ELEMENT_TAG;
3113
+ this.webComponentTag = option?.webComponentTag || CUSTOM_ELEMENT_TAG;
2315
3114
  this.setWebComponentTag();
2316
3115
  }
2317
3116
  };