@blueking/bk-weweb 0.0.35-beta.9 → 0.0.36-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +6 -1
- package/dist/index.esm.js +1455 -1379
- package/dist/index.esm.js.map +1 -1
- package/dist/vite/helper.d.mts +11 -0
- package/dist/vite/helper.esm.js +50 -0
- package/dist/vite/helper.esm.js.map +1 -0
- package/package.json +3 -2
- package/readme.md +13 -13
package/dist/index.esm.js
CHANGED
|
@@ -209,1538 +209,1592 @@ var isJsonpUrl = (url) => {
|
|
|
209
209
|
}
|
|
210
210
|
};
|
|
211
211
|
|
|
212
|
-
// src/
|
|
213
|
-
var
|
|
214
|
-
var
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
shadow.host.parentNode?.insertBefore(item, shadow.host);
|
|
225
|
-
}
|
|
226
|
-
break;
|
|
227
|
-
case "afterbegin":
|
|
228
|
-
for (const item of elements.reverse()) {
|
|
229
|
-
shadow.insertBefore(item, shadow.firstChild);
|
|
230
|
-
}
|
|
231
|
-
break;
|
|
232
|
-
case "beforeend":
|
|
233
|
-
for (const item of elements) {
|
|
234
|
-
shadow.appendChild(item);
|
|
235
|
-
}
|
|
236
|
-
break;
|
|
237
|
-
case "afterend":
|
|
238
|
-
for (const item of elements) {
|
|
239
|
-
shadow.host.parentNode?.insertBefore(item, shadow.host.nextSibling);
|
|
240
|
-
}
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
function createProxyBody(rawDocument, app) {
|
|
246
|
-
return new Proxy(
|
|
247
|
-
{},
|
|
248
|
-
{
|
|
249
|
-
get(_, key) {
|
|
250
|
-
if (app.container instanceof ShadowRoot) {
|
|
251
|
-
if (key === "insertAdjacentHTML") {
|
|
252
|
-
return createShadowRootInsertAdjacentHTML(app);
|
|
253
|
-
}
|
|
254
|
-
const value2 = Reflect.get(app.container, key);
|
|
255
|
-
if (typeof value2 === "function") {
|
|
256
|
-
return value2.bind(app.container);
|
|
257
|
-
}
|
|
258
|
-
if (value2 !== void 0) {
|
|
259
|
-
return value2;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
const value = Reflect.get(rawDocument.body, key);
|
|
263
|
-
return typeof value === "function" ? value.bind(rawDocument.body) : value;
|
|
264
|
-
},
|
|
265
|
-
set(_, key, value) {
|
|
266
|
-
if (app.container instanceof ShadowRoot) {
|
|
267
|
-
Reflect.set(app.container, key, value);
|
|
268
|
-
return true;
|
|
269
|
-
}
|
|
270
|
-
Reflect.set(rawDocument.body, key, value);
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
function createElementWithAppKey(rawDocument, app) {
|
|
277
|
-
return function createElement(tagName, options) {
|
|
278
|
-
const element = rawDocument.createElement(tagName, options);
|
|
279
|
-
element[APP_KEY_PROPERTY] = app.appCacheKey;
|
|
280
|
-
return element;
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
function isSpecialElementTag(selector) {
|
|
284
|
-
return SPECIAL_ELEMENT_TAGS.includes(selector);
|
|
285
|
-
}
|
|
286
|
-
function safeQuerySelector(container, selector) {
|
|
287
|
-
try {
|
|
288
|
-
return container?.querySelector(selector) ?? null;
|
|
289
|
-
} catch {
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
function safeQuerySelectorAll(container, selector) {
|
|
294
|
-
try {
|
|
295
|
-
return container?.querySelectorAll(selector) ?? [];
|
|
296
|
-
} catch {
|
|
297
|
-
return [];
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
function createProxyQuerySelector(rawDocument, app, proxyBody) {
|
|
301
|
-
return function querySelectorNew(selectors) {
|
|
302
|
-
if (selectors === proxyBody) {
|
|
303
|
-
return app.container instanceof ShadowRoot ? app.container : rawDocument.body;
|
|
304
|
-
}
|
|
305
|
-
if (isSpecialElementTag(selectors)) {
|
|
306
|
-
if (app?.container instanceof ShadowRoot) {
|
|
307
|
-
return app?.container;
|
|
308
|
-
}
|
|
309
|
-
return rawDocument.querySelector.call(this, selectors);
|
|
310
|
-
}
|
|
311
|
-
return safeQuerySelector(app?.container, selectors);
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
function createProxyQuerySelectorAll(rawDocument, app) {
|
|
315
|
-
return function querySelectorAllNew(selectors) {
|
|
316
|
-
if (isSpecialElementTag(selectors)) {
|
|
317
|
-
if (app?.container instanceof ShadowRoot) {
|
|
318
|
-
return [app?.container];
|
|
319
|
-
}
|
|
320
|
-
const result = rawDocument.querySelector(selectors);
|
|
321
|
-
return result ? [result] : [];
|
|
322
|
-
}
|
|
323
|
-
return safeQuerySelectorAll(app?.container, selectors);
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
function createProxyGetElementById(rawDocument, querySelector) {
|
|
327
|
-
return function getElementByIdNew(id) {
|
|
328
|
-
return querySelector.call(rawDocument, `#${id}`);
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
function createProxyGetElementsByClassName(querySelectorAll) {
|
|
332
|
-
return function getElementsByClassName(className) {
|
|
333
|
-
return querySelectorAll(`.${className}`);
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
function createProxyGetElementsByTagName(rawDocument, app, querySelectorAll) {
|
|
337
|
-
return function getElementsByTagName(tagName) {
|
|
338
|
-
if (isSpecialElementTag(tagName) || !app?.showSourceCode && tagName.toLowerCase() === "script") {
|
|
339
|
-
return rawDocument.getElementsByTagName(tagName);
|
|
340
|
-
}
|
|
341
|
-
return querySelectorAll(tagName);
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
function createProxyGetElementsByName(querySelectorAll) {
|
|
345
|
-
return function getElementsByNameNew(name) {
|
|
346
|
-
return querySelectorAll(`[name="${name}"]`);
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
function createProxyMethodMap(rawDocument, app, proxyBody) {
|
|
350
|
-
const createElement = createElementWithAppKey(rawDocument, app);
|
|
351
|
-
const querySelector = createProxyQuerySelector(rawDocument, app, proxyBody);
|
|
352
|
-
const querySelectorAll = createProxyQuerySelectorAll(rawDocument, app);
|
|
353
|
-
const getElementById = createProxyGetElementById(rawDocument, querySelector);
|
|
354
|
-
const getElementsByClassName = createProxyGetElementsByClassName(querySelectorAll);
|
|
355
|
-
const getElementsByTagName = createProxyGetElementsByTagName(rawDocument, app, querySelectorAll);
|
|
356
|
-
const getElementsByName = createProxyGetElementsByName(querySelectorAll);
|
|
357
|
-
return {
|
|
358
|
-
createElement: createElement.bind(rawDocument),
|
|
359
|
-
querySelector: querySelector.bind(rawDocument),
|
|
360
|
-
querySelectorAll: querySelectorAll.bind(rawDocument),
|
|
361
|
-
getElementById: getElementById.bind(rawDocument),
|
|
362
|
-
getElementsByClassName: getElementsByClassName.bind(rawDocument),
|
|
363
|
-
getElementsByTagName: getElementsByTagName.bind(rawDocument),
|
|
364
|
-
getElementsByName: getElementsByName.bind(rawDocument)
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
var createProxyDocument = (rawDocument, app) => {
|
|
368
|
-
const fakeDocument = {};
|
|
369
|
-
const proxyBody = createProxyBody(rawDocument, app);
|
|
370
|
-
const methodMap = createProxyMethodMap(rawDocument, app, proxyBody);
|
|
371
|
-
return new Proxy(fakeDocument, {
|
|
372
|
-
get(_, key) {
|
|
373
|
-
if (key === "body") {
|
|
374
|
-
return proxyBody;
|
|
375
|
-
}
|
|
376
|
-
if (typeof key === "string" && key in methodMap) {
|
|
377
|
-
return methodMap[key];
|
|
378
|
-
}
|
|
379
|
-
const result = Reflect.get(rawDocument, key);
|
|
380
|
-
return typeof result === "function" ? result.bind(rawDocument) : result;
|
|
381
|
-
}
|
|
382
|
-
});
|
|
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);
|
|
383
224
|
};
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const documentListenerMap = /* @__PURE__ */ new Map();
|
|
390
|
-
document.addEventListener = function(type, listener, options) {
|
|
391
|
-
const app = getCurrentRunningApp();
|
|
392
|
-
if (app?.keepAlive) {
|
|
393
|
-
const listeners = documentListenerMap.get(type) || [];
|
|
394
|
-
documentListenerMap.set(type, [...listeners, listener]);
|
|
395
|
-
}
|
|
396
|
-
addEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
|
|
397
|
-
};
|
|
398
|
-
document.body.addEventListener = document.addEventListener;
|
|
399
|
-
document.removeEventListener = function(type, listener, options) {
|
|
400
|
-
const app = getCurrentRunningApp();
|
|
401
|
-
if (app?.keepAlive) {
|
|
402
|
-
const listeners = documentListenerMap.get(type) || [];
|
|
403
|
-
if (listeners.length && listeners.some((l) => l === listener)) {
|
|
404
|
-
listeners.splice(listeners.indexOf(listener), 1);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
removeEventListener.call(app?.container instanceof ShadowRoot ? app.container : this, type, listener, options);
|
|
408
|
-
};
|
|
409
|
-
document.body.removeEventListener = document.removeEventListener;
|
|
410
|
-
function resetDocumentAndBodyEvent() {
|
|
411
|
-
const app = getCurrentRunningApp();
|
|
412
|
-
if (app?.keepAlive && documentListenerMap.values()) {
|
|
413
|
-
for (const [type, listeners] of documentListenerMap.entries()) {
|
|
414
|
-
for (const listener of listeners || []) {
|
|
415
|
-
document.removeEventListener.call(document, type, listener);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
document.addEventListener = addEventListener;
|
|
420
|
-
document.body.addEventListener = bodyAddEventListener;
|
|
421
|
-
document.removeEventListener = removeEventListener;
|
|
422
|
-
document.body.removeEventListener = bodyRemoveEventListener;
|
|
423
|
-
documentListenerMap.clear();
|
|
424
|
-
}
|
|
425
|
-
return {
|
|
426
|
-
resetDocumentAndBodyEvent
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// src/context/function.ts
|
|
431
|
-
var CLASS_REGEX = /^class\b/;
|
|
432
|
-
var COMMON_CONSTRUCT_FU_REGEX = /^function\b\s[A-Z].*/;
|
|
433
|
-
var ConstructFunCacheMap = /* @__PURE__ */ new WeakMap();
|
|
434
|
-
function isConstructFun(fn) {
|
|
435
|
-
if (fn.prototype?.constructor === fn && Object.getOwnPropertyNames(fn.prototype).length > 1) {
|
|
436
|
-
return true;
|
|
437
|
-
}
|
|
438
|
-
if (ConstructFunCacheMap.has(fn)) {
|
|
439
|
-
return ConstructFunCacheMap.get(fn);
|
|
440
|
-
}
|
|
441
|
-
const constructable = COMMON_CONSTRUCT_FU_REGEX.test(fn.toString()) || CLASS_REGEX.test(fn.toString());
|
|
442
|
-
ConstructFunCacheMap.set(fn, constructable);
|
|
443
|
-
return constructable;
|
|
444
|
-
}
|
|
445
|
-
var functionBoundedValueMap = /* @__PURE__ */ new WeakMap();
|
|
446
|
-
function bindFunctionToRawWindow(rawWindow, value) {
|
|
447
|
-
if (functionBoundedValueMap.has(value)) {
|
|
448
|
-
return functionBoundedValueMap.get(value);
|
|
225
|
+
var dispatchLinkOrScriptLoad = (element) => {
|
|
226
|
+
const loadEvent = defineEventSourceElement(element, "load");
|
|
227
|
+
if (typeof element.onload === "function") {
|
|
228
|
+
element.onload.call(element, loadEvent);
|
|
229
|
+
return;
|
|
449
230
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
enumerable: false,
|
|
458
|
-
value: value.prototype,
|
|
459
|
-
writable: true
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
if (typeof value.toString === "function") {
|
|
463
|
-
const valueHasInstanceToString = Object.hasOwn(value, "toString") && !Object.hasOwn(boundValue, "toString");
|
|
464
|
-
const boundValueHasPrototypeToString = boundValue.toString === Function.prototype.toString;
|
|
465
|
-
if (valueHasInstanceToString || boundValueHasPrototypeToString) {
|
|
466
|
-
const originToStringDescriptor = Object.getOwnPropertyDescriptor(
|
|
467
|
-
valueHasInstanceToString ? value : Function.prototype,
|
|
468
|
-
"toString"
|
|
469
|
-
);
|
|
470
|
-
Object.defineProperty(boundValue, "toString", {
|
|
471
|
-
...originToStringDescriptor,
|
|
472
|
-
...originToStringDescriptor?.get ? null : { value: () => value.toString() }
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
functionBoundedValueMap.set(value, boundValue);
|
|
477
|
-
return boundValue;
|
|
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;
|
|
478
238
|
}
|
|
479
|
-
|
|
480
|
-
}
|
|
239
|
+
element.dispatchEvent(errorEvent);
|
|
240
|
+
};
|
|
481
241
|
|
|
482
|
-
// src/
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
windowEventListenerMap.set(type, [...windowEventListenerMap.get(type) || [], listener]);
|
|
490
|
-
addEventListener.call(rawWindow, type, listener, options);
|
|
491
|
-
};
|
|
492
|
-
fakeWindow.removeEventListener = (type, listener, options) => {
|
|
493
|
-
const listenerList = windowEventListenerMap.get(type);
|
|
494
|
-
if (listenerList?.length) {
|
|
495
|
-
const index = listenerList.indexOf(listener);
|
|
496
|
-
index > -1 && listenerList.splice(index, 1);
|
|
497
|
-
}
|
|
498
|
-
removeEventListener.call(rawWindow, type, listener, options);
|
|
499
|
-
};
|
|
500
|
-
fakeWindow.setInterval = (handler, timeout, ...args) => {
|
|
501
|
-
const timer = setInterval2(handler, timeout, ...args);
|
|
502
|
-
intervalTimerList.push(timer);
|
|
503
|
-
return timer;
|
|
504
|
-
};
|
|
505
|
-
fakeWindow.clearInterval = (timer) => {
|
|
506
|
-
const index = intervalTimerList.indexOf(timer);
|
|
507
|
-
index > -1 && intervalTimerList.splice(index, 1);
|
|
508
|
-
clearInterval2.call(rawWindow, timer);
|
|
509
|
-
};
|
|
510
|
-
function resetWindowFunction() {
|
|
511
|
-
if (windowEventListenerMap.size) {
|
|
512
|
-
windowEventListenerMap.forEach((listenerList, type) => {
|
|
513
|
-
for (const listener of listenerList) {
|
|
514
|
-
removeEventListener.call(rawWindow, type, listener);
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
windowEventListenerMap.clear();
|
|
518
|
-
}
|
|
519
|
-
if (intervalTimerList.length) {
|
|
520
|
-
for (const timer of intervalTimerList) {
|
|
521
|
-
clearInterval2.call(rawWindow, timer);
|
|
522
|
-
}
|
|
242
|
+
// src/utils/fetch.ts
|
|
243
|
+
var fetchSource = async (url, options = {}, app) => {
|
|
244
|
+
if (typeof app?.fetchSource === "function") {
|
|
245
|
+
try {
|
|
246
|
+
return await app.fetchSource(url, options);
|
|
247
|
+
} catch {
|
|
248
|
+
return "";
|
|
523
249
|
}
|
|
524
250
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// src/context/sandbox.ts
|
|
531
|
-
var SandBox = class {
|
|
532
|
-
/** 初始化沙箱环境 */
|
|
533
|
-
constructor(app) {
|
|
534
|
-
this.app = app;
|
|
535
|
-
const windowDescriptorSet = /* @__PURE__ */ new Set();
|
|
536
|
-
const rawWindow = window;
|
|
537
|
-
this.rawWindow = rawWindow;
|
|
538
|
-
this.rawDocument = createProxyDocument(document, app);
|
|
539
|
-
const fakeWindow = /* @__PURE__ */ Object.create({});
|
|
540
|
-
fakeWindow.__BK_WEWEB_APP_KEY__ = app.appCacheKey;
|
|
541
|
-
fakeWindow.__POWERED_BY_BK_WEWEB__ = true;
|
|
542
|
-
fakeWindow.rawDocument = document;
|
|
543
|
-
fakeWindow.rawWindow = rawWindow;
|
|
544
|
-
fakeWindow.__proto__ = Window;
|
|
545
|
-
this.fakeWindow = fakeWindow;
|
|
546
|
-
const { resetWindowFunction } = rewriteWindowFunction(this.fakeWindow);
|
|
547
|
-
this.resetWindowFunction = resetWindowFunction;
|
|
548
|
-
const appIdentifier = (app.name || app.appCacheKey).replace(/[-,:~'"]/g, "_");
|
|
549
|
-
this.windowSymbolKey = `__${appIdentifier}_${random(10)}__`;
|
|
550
|
-
this.proxyWindow = new Proxy(this.fakeWindow, {
|
|
551
|
-
defineProperty: (target, key, value) => {
|
|
552
|
-
if (windowDescriptorSet.has(key)) {
|
|
553
|
-
return Reflect.defineProperty(rawWindow, key, value);
|
|
554
|
-
}
|
|
555
|
-
return Reflect.defineProperty(target, key, value);
|
|
556
|
-
},
|
|
557
|
-
deleteProperty: (target, key) => {
|
|
558
|
-
if (Object.hasOwn(target, key)) {
|
|
559
|
-
if (this.sameRawWindowKeySet.has(key)) {
|
|
560
|
-
this.sameRawWindowKeySet.delete(key);
|
|
561
|
-
}
|
|
562
|
-
if (this.inRawWindowKeySet.has(key)) {
|
|
563
|
-
Reflect.deleteProperty(rawWindow, key);
|
|
564
|
-
}
|
|
565
|
-
return Reflect.deleteProperty(target, key);
|
|
566
|
-
}
|
|
567
|
-
return true;
|
|
568
|
-
},
|
|
569
|
-
get: (target, key) => {
|
|
570
|
-
return this.handleProxyGet(target, key, rawWindow);
|
|
571
|
-
},
|
|
572
|
-
getOwnPropertyDescriptor: (target, key) => {
|
|
573
|
-
if (Object.hasOwn(target, key)) {
|
|
574
|
-
return Object.getOwnPropertyDescriptor(target, key);
|
|
575
|
-
}
|
|
576
|
-
if (Object.hasOwn(rawWindow, key)) {
|
|
577
|
-
windowDescriptorSet.add(key);
|
|
578
|
-
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
579
|
-
if (descriptor && !descriptor.configurable) {
|
|
580
|
-
descriptor.configurable = true;
|
|
581
|
-
}
|
|
582
|
-
return descriptor;
|
|
583
|
-
}
|
|
584
|
-
return void 0;
|
|
585
|
-
},
|
|
586
|
-
has: (target, key) => windowNativeFuncMap.has(key) || key in target || key in rawWindow,
|
|
587
|
-
ownKeys: (target) => Array.from(new Set(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)))),
|
|
588
|
-
set: (target, key, value) => {
|
|
589
|
-
return this.handleProxySet(target, key, value, rawWindow);
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
rawWindow[this.windowSymbolKey] = this.proxyWindow;
|
|
251
|
+
if (src_default.fetchSource) {
|
|
252
|
+
return src_default.fetchSource(url, options);
|
|
593
253
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
254
|
+
try {
|
|
255
|
+
const response = await window.fetch(url, options);
|
|
256
|
+
return await response.text();
|
|
257
|
+
} catch {
|
|
258
|
+
return "";
|
|
259
|
+
}
|
|
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;
|
|
300
|
+
}
|
|
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);
|
|
640
311
|
}
|
|
641
|
-
|
|
642
|
-
|
|
312
|
+
this.scoped = true;
|
|
313
|
+
}
|
|
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;
|
|
643
321
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
322
|
+
return styleElement;
|
|
323
|
+
}
|
|
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);
|
|
647
337
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
338
|
+
styleElement = this.scopedStyleCSS(app, styleElement);
|
|
339
|
+
this.scoped = true;
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.error("scoped style error", error);
|
|
652
342
|
}
|
|
653
|
-
|
|
654
|
-
|
|
343
|
+
return styleElement;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* 获取样式代码
|
|
347
|
+
*/
|
|
348
|
+
async getCode(app) {
|
|
349
|
+
if (this.code.length || !this.url) {
|
|
350
|
+
return this.code;
|
|
655
351
|
}
|
|
656
|
-
const
|
|
657
|
-
|
|
352
|
+
const code = this.getCodeFromAppSource(app) || this.getCodeFromCache() || await this.fetchCodeFromRemote(app);
|
|
353
|
+
this.code = code;
|
|
354
|
+
return code;
|
|
658
355
|
}
|
|
659
356
|
/**
|
|
660
|
-
*
|
|
661
|
-
* @
|
|
662
|
-
* @param
|
|
663
|
-
* @
|
|
664
|
-
* @param value - 属性值
|
|
665
|
-
* @param rawWindow - 原始 window 对象
|
|
666
|
-
* @returns boolean - 设置是否成功
|
|
667
|
-
* @private
|
|
357
|
+
* 检查并链接基础应用样式
|
|
358
|
+
* @param styleElement 样式元素
|
|
359
|
+
* @param app 应用实例
|
|
360
|
+
* @returns 是否已链接基础样式
|
|
668
361
|
*/
|
|
669
|
-
|
|
670
|
-
if (!
|
|
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");
|
|
671
366
|
return true;
|
|
672
367
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
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;
|
|
385
|
+
}
|
|
386
|
+
if (CSS_SELECTORS.RELATIVE_PATH.test(matchedUrl) && linkPath) {
|
|
387
|
+
baseURI = this.buildBaseURI(linkPath);
|
|
388
|
+
}
|
|
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;
|
|
411
|
+
}
|
|
684
412
|
}
|
|
685
|
-
|
|
686
|
-
return true;
|
|
413
|
+
return result.replace(/^\s+/, "");
|
|
687
414
|
}
|
|
688
415
|
/**
|
|
689
|
-
*
|
|
690
|
-
* @description 检查是否在 iframe 模式下访问 location 相关属性
|
|
691
|
-
* @param key - 属性键
|
|
692
|
-
* @returns boolean - 是否使用 iframe location
|
|
693
|
-
* @private
|
|
416
|
+
* style rule 处理
|
|
694
417
|
*/
|
|
695
|
-
|
|
696
|
-
|
|
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);
|
|
422
|
+
}
|
|
423
|
+
if (selectorText === "*") {
|
|
424
|
+
return cssText.replace("*", `${prefix} *`);
|
|
425
|
+
}
|
|
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
|
+
);
|
|
697
435
|
}
|
|
698
436
|
/**
|
|
699
|
-
*
|
|
700
|
-
* @description 为 getComputedStyle 方法创建安全的代理实现
|
|
701
|
-
* @param rawWindow - 原始 window 对象
|
|
702
|
-
* @returns Function - 代理后的 getComputedStyle 方法
|
|
703
|
-
* @private
|
|
437
|
+
* link style 处理
|
|
704
438
|
*/
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
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);
|
|
709
452
|
}
|
|
710
|
-
|
|
711
|
-
|
|
453
|
+
} catch {
|
|
454
|
+
linkElement && dispatchLinkOrScriptError(linkElement);
|
|
455
|
+
}
|
|
456
|
+
return styleElement;
|
|
712
457
|
}
|
|
713
458
|
/**
|
|
714
|
-
*
|
|
715
|
-
* @description 检查属性设置的逻辑条件
|
|
716
|
-
* @param target - 目标对象
|
|
717
|
-
* @param key - 属性键
|
|
718
|
-
* @param rawWindow - 原始 window 对象
|
|
719
|
-
* @returns boolean - 是否在目标对象上设置
|
|
720
|
-
* @private
|
|
459
|
+
* 隔离 style
|
|
721
460
|
*/
|
|
722
|
-
|
|
723
|
-
|
|
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);
|
|
468
|
+
}
|
|
469
|
+
if (this.url) {
|
|
470
|
+
styleElement.setAttribute(STYLE_ATTRIBUTES.ORIGIN_SRC, this.url);
|
|
471
|
+
}
|
|
472
|
+
return styleElement;
|
|
724
473
|
}
|
|
725
474
|
/**
|
|
726
|
-
*
|
|
727
|
-
* @description 安全地在目标对象上设置属性,保持描述符特性
|
|
728
|
-
* @param target - 目标对象
|
|
729
|
-
* @param key - 属性键
|
|
730
|
-
* @param value - 属性值
|
|
731
|
-
* @param rawWindow - 原始 window 对象
|
|
732
|
-
* @private
|
|
475
|
+
* 应用隔离 style
|
|
733
476
|
*/
|
|
734
|
-
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
}
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
this.
|
|
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);
|
|
748
491
|
}
|
|
492
|
+
styleElement.textContent = cssText.replace(CSS_SELECTORS.ROOT_HOST_PATTERN, ":host");
|
|
749
493
|
}
|
|
750
494
|
/**
|
|
751
|
-
*
|
|
752
|
-
* @description 处理需要在原始 window 上设置的白名单属性
|
|
753
|
-
* @param key - 属性键
|
|
754
|
-
* @param value - 属性值
|
|
755
|
-
* @param rawWindow - 原始 window 对象
|
|
756
|
-
* @private
|
|
495
|
+
* 处理ShadowRoot中的字体
|
|
757
496
|
*/
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
+
`;
|
|
503
|
+
}
|
|
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);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
getCodeFromAppSource(app) {
|
|
514
|
+
if (this.url && app?.source?.styles?.has(this.url)) {
|
|
515
|
+
return app.source.styles.get(this.url)?.code || "";
|
|
516
|
+
}
|
|
517
|
+
return "";
|
|
518
|
+
}
|
|
519
|
+
getCodeFromCache() {
|
|
520
|
+
if (this.url && appCache.getCacheStyle(this.url)) {
|
|
521
|
+
const style = appCache.getCacheStyle(this.url);
|
|
522
|
+
return style?.code || "";
|
|
762
523
|
}
|
|
524
|
+
return "";
|
|
525
|
+
}
|
|
526
|
+
async fetchCodeFromRemote(app) {
|
|
527
|
+
return await fetchSource(this.url, {}, app).catch(() => "");
|
|
528
|
+
}
|
|
529
|
+
clearStyleElement(styleElement) {
|
|
530
|
+
styleElement.textContent = "";
|
|
531
|
+
styleElement.innerHTML = "";
|
|
532
|
+
}
|
|
533
|
+
buildBaseURI(linkPath) {
|
|
534
|
+
const pathArr = linkPath.split("/");
|
|
535
|
+
pathArr.pop();
|
|
536
|
+
return addUrlProtocol(`${pathArr.join("/")}/`);
|
|
537
|
+
}
|
|
538
|
+
handleExistingCode(styleElement, app, container, linkElement) {
|
|
539
|
+
this.commonScoped(styleElement, app);
|
|
540
|
+
container?.prepend(styleElement);
|
|
541
|
+
linkElement && dispatchLinkOrScriptLoad(linkElement);
|
|
763
542
|
}
|
|
764
543
|
/**
|
|
765
|
-
*
|
|
766
|
-
* @description 启动沙箱环境,初始化代理对象和事件处理
|
|
767
|
-
* @param data - 传递给沙箱的数据(可选)
|
|
544
|
+
* 处理href属性
|
|
768
545
|
*/
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
this.
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
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
|
+
});
|
|
777
555
|
}
|
|
778
556
|
/**
|
|
779
|
-
*
|
|
780
|
-
* @description 关闭沙箱环境,清理所有副作用和修改
|
|
557
|
+
* 处理缺失的href
|
|
781
558
|
*/
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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
|
+
});
|
|
572
|
+
});
|
|
573
|
+
const observerConfig = {
|
|
574
|
+
attributeFilter: ["href"],
|
|
575
|
+
childList: false,
|
|
576
|
+
subtree: false
|
|
577
|
+
};
|
|
578
|
+
observer.observe(linkElement, observerConfig);
|
|
579
|
+
}
|
|
580
|
+
processExistingContent(styleElement, app) {
|
|
581
|
+
if (styleElement.textContent) {
|
|
582
|
+
this.clearStyleElement(styleElement);
|
|
583
|
+
}
|
|
584
|
+
if (!this.linkedBaseStyle(styleElement, app)) {
|
|
585
|
+
this.commonScoped(styleElement, app);
|
|
788
586
|
}
|
|
789
|
-
this.inRawWindowKeySet.clear();
|
|
790
|
-
this.resetDocumentAndBodyEvent?.();
|
|
791
587
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
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)) {
|
|
593
|
+
this.commonScoped(styleElement, app);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
const observerConfig = {
|
|
597
|
+
attributes: false,
|
|
598
|
+
characterData: true,
|
|
599
|
+
childList: true,
|
|
600
|
+
subtree: true
|
|
802
601
|
};
|
|
803
|
-
|
|
804
|
-
}, {});
|
|
805
|
-
return Object.defineProperties(new CustomEvent(eventName), targetProperties);
|
|
806
|
-
};
|
|
807
|
-
var dispatchLinkOrScriptLoad = (element) => {
|
|
808
|
-
const loadEvent = defineEventSourceElement(element, "load");
|
|
809
|
-
if (typeof element.onload === "function") {
|
|
810
|
-
element.onload.call(element, loadEvent);
|
|
811
|
-
return;
|
|
602
|
+
observer.observe(styleElement, observerConfig);
|
|
812
603
|
}
|
|
813
|
-
element.dispatchEvent(loadEvent);
|
|
814
604
|
};
|
|
815
|
-
|
|
816
|
-
const
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
605
|
+
async function executeAppStyles(app, container) {
|
|
606
|
+
const styleList = Array.from(app.source?.styles?.values() || []);
|
|
607
|
+
const promiseList = [];
|
|
608
|
+
for (const style of styleList) {
|
|
609
|
+
promiseList.push(style.executeCode(app));
|
|
820
610
|
}
|
|
821
|
-
|
|
822
|
-
|
|
611
|
+
await Promise.all(promiseList).then((styleElementList) => {
|
|
612
|
+
const parentElement = container || app.container;
|
|
613
|
+
if (app.keepAlive && !(parentElement instanceof ShadowRoot)) {
|
|
614
|
+
document.head.append(...styleElementList);
|
|
615
|
+
} else {
|
|
616
|
+
parentElement?.append(...styleElementList);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
}
|
|
823
620
|
|
|
824
|
-
// src/
|
|
825
|
-
var
|
|
826
|
-
var
|
|
827
|
-
|
|
828
|
-
|
|
621
|
+
// src/mode/instance.ts
|
|
622
|
+
var DEFAULT_RANDOM_LENGTH = 5;
|
|
623
|
+
var WRAPPER_SUFFIX = "-wrapper";
|
|
624
|
+
var MicroInstanceModel = class {
|
|
625
|
+
state = AppState.UNSET;
|
|
626
|
+
appCacheKey;
|
|
627
|
+
container;
|
|
628
|
+
data;
|
|
629
|
+
fetchSource;
|
|
630
|
+
initSource;
|
|
631
|
+
isPreLoad = false;
|
|
632
|
+
keepAlive;
|
|
633
|
+
name;
|
|
634
|
+
sandBox;
|
|
635
|
+
scopeCss = true;
|
|
636
|
+
scopeJs = false;
|
|
637
|
+
showSourceCode = true;
|
|
638
|
+
source;
|
|
639
|
+
url;
|
|
640
|
+
constructor(props) {
|
|
641
|
+
this.name = props.id !== props.url ? props.id : random(DEFAULT_RANDOM_LENGTH);
|
|
642
|
+
this.appCacheKey = props.id || this.name;
|
|
643
|
+
this.url = props.url;
|
|
644
|
+
this.container = props.container ?? void 0;
|
|
645
|
+
this.scopeJs = props.scopeJs ?? true;
|
|
646
|
+
this.showSourceCode = props.showSourceCode ?? true;
|
|
647
|
+
this.scopeCss = props.scopeCss ?? true;
|
|
648
|
+
this.keepAlive = props.keepAlive ?? false;
|
|
649
|
+
this.data = props.data ?? {};
|
|
650
|
+
this.initSource = props.initSource ?? [];
|
|
651
|
+
this.fetchSource = props.fetchSource;
|
|
652
|
+
this.initializeSandBox();
|
|
829
653
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
654
|
+
/** 激活微模块 */
|
|
655
|
+
activated(container, callback) {
|
|
656
|
+
this.isPreLoad = false;
|
|
657
|
+
this.state = AppState.ACTIVATED;
|
|
658
|
+
if (this.container && container) {
|
|
659
|
+
this.setContainerAttribute(container);
|
|
660
|
+
this.transferNodes(container);
|
|
661
|
+
this.container = container;
|
|
662
|
+
this.initShadowRootContainer();
|
|
663
|
+
this.sandBox?.activated();
|
|
664
|
+
const scriptInfo = this.getScriptInfo();
|
|
665
|
+
callback?.(this, scriptInfo?.exportInstance);
|
|
833
666
|
}
|
|
834
667
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
url: ""
|
|
840
|
-
});
|
|
841
|
-
app.source?.setStyle(randomUrl(), styleInstance);
|
|
842
|
-
styleInstance.scopedStyleCSS(app, child);
|
|
668
|
+
/** 停用微模块 */
|
|
669
|
+
deactivated() {
|
|
670
|
+
this.state = AppState.DEACTIVATED;
|
|
671
|
+
this.sandBox?.deactivated();
|
|
843
672
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
673
|
+
/** 挂载微模块 */
|
|
674
|
+
mount(container, callback) {
|
|
675
|
+
this.isPreLoad = false;
|
|
676
|
+
this.container = container ?? this.container;
|
|
677
|
+
this.initShadowRootContainer();
|
|
678
|
+
this.state = AppState.MOUNTING;
|
|
679
|
+
this.setContainerAttribute(this.container);
|
|
680
|
+
this.setupContainer();
|
|
681
|
+
this.executeStyles();
|
|
682
|
+
this.sandBox?.activated();
|
|
683
|
+
execAppScripts(this).finally(() => {
|
|
684
|
+
this.state = AppState.MOUNTED;
|
|
685
|
+
this.renderInstance();
|
|
686
|
+
const scriptInfo = this.getScriptInfo();
|
|
687
|
+
callback?.(this, scriptInfo?.exportInstance);
|
|
688
|
+
});
|
|
851
689
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
const observer = new MutationObserver(() => {
|
|
856
|
-
if (child.getAttribute("src")) {
|
|
857
|
-
observer.disconnect();
|
|
858
|
-
const scriptInfo = app.source.collectScript(child, parent, true);
|
|
859
|
-
if (scriptInfo?.replace) {
|
|
860
|
-
bodyAppendChild.call(app.container, scriptInfo.replace);
|
|
861
|
-
}
|
|
862
|
-
if (isJsonpUrl(child.getAttribute("src"))) {
|
|
863
|
-
app.container?.append(child);
|
|
864
|
-
return;
|
|
865
|
-
}
|
|
866
|
-
if (scriptInfo?.script) {
|
|
867
|
-
scriptInfo.script.executeCode(app);
|
|
868
|
-
}
|
|
869
|
-
child.remove();
|
|
870
|
-
} else if (child.textContent) {
|
|
871
|
-
observer.disconnect();
|
|
872
|
-
const scriptInstance = new Script({
|
|
873
|
-
async: false,
|
|
874
|
-
code: child.textContent,
|
|
875
|
-
defer: child.type === "module",
|
|
876
|
-
fromHtml: false,
|
|
877
|
-
isModule: child.type === "module"
|
|
878
|
-
});
|
|
879
|
-
app.source.scripts.set(randomUrl(), scriptInstance);
|
|
880
|
-
try {
|
|
881
|
-
scriptInstance.executeCode(app);
|
|
882
|
-
} catch (error) {
|
|
883
|
-
console.error(error);
|
|
884
|
-
} finally {
|
|
885
|
-
if (!scriptInstance.isModule) {
|
|
886
|
-
dispatchLinkOrScriptLoad(child);
|
|
887
|
-
}
|
|
888
|
-
child.remove();
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
});
|
|
892
|
-
return observer;
|
|
893
|
-
};
|
|
894
|
-
var handleScriptElement = (child, parent, app) => {
|
|
895
|
-
const replaceInfo = app.source.collectScript(child, parent, true);
|
|
896
|
-
if (!replaceInfo) {
|
|
897
|
-
return child;
|
|
690
|
+
/** 错误处理 */
|
|
691
|
+
onError() {
|
|
692
|
+
this.state = AppState.ERROR;
|
|
898
693
|
}
|
|
899
|
-
|
|
900
|
-
|
|
694
|
+
/** 挂载处理 */
|
|
695
|
+
onMount() {
|
|
696
|
+
if (this.isPreLoad) return;
|
|
697
|
+
this.state = AppState.LOADED;
|
|
698
|
+
this.mount();
|
|
901
699
|
}
|
|
902
|
-
|
|
903
|
-
|
|
700
|
+
/** 注册运行中的应用 */
|
|
701
|
+
registerRunningApp() {
|
|
702
|
+
setCurrentRunningApp(this);
|
|
703
|
+
Promise.resolve().then(() => setCurrentRunningApp(null));
|
|
904
704
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
705
|
+
/** 启动微模块 */
|
|
706
|
+
async start() {
|
|
707
|
+
if (!this.source || this.needsReload()) {
|
|
708
|
+
this.source = new EntrySource(this.url);
|
|
709
|
+
await this.source.importEntry(this);
|
|
710
|
+
}
|
|
909
711
|
}
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
712
|
+
/** 卸载微模块 */
|
|
713
|
+
unmount(needDestroy) {
|
|
714
|
+
this.state = AppState.UNMOUNT;
|
|
715
|
+
this.sandBox?.deactivated();
|
|
716
|
+
if (needDestroy) {
|
|
717
|
+
appCache.deleteApp(this.url);
|
|
718
|
+
}
|
|
719
|
+
if (this.container) {
|
|
720
|
+
this.container.innerHTML = "";
|
|
721
|
+
this.container = void 0;
|
|
722
|
+
}
|
|
915
723
|
}
|
|
916
|
-
|
|
917
|
-
|
|
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
|
+
}
|
|
918
735
|
}
|
|
919
|
-
|
|
920
|
-
|
|
736
|
+
set status(value) {
|
|
737
|
+
this.state = value;
|
|
921
738
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
var isSpecialElement = (node) => {
|
|
925
|
-
return node instanceof HTMLScriptElement || node instanceof HTMLStyleElement || node instanceof HTMLLinkElement;
|
|
926
|
-
};
|
|
927
|
-
var getTargetContainer = (app, isSpecial) => {
|
|
928
|
-
const needKeepAlive = isSpecial && !!app.keepAlive && !(app.container instanceof ShadowRoot);
|
|
929
|
-
return needKeepAlive ? document.head : app.container;
|
|
930
|
-
};
|
|
931
|
-
var elementAppendHandler = (parent, newChild, rawMethod) => {
|
|
932
|
-
if (!newChild.__BK_WEWEB_APP_KEY__) {
|
|
933
|
-
return rawMethod.call(parent, newChild);
|
|
739
|
+
get status() {
|
|
740
|
+
return this.state;
|
|
934
741
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
742
|
+
/** 初始化沙盒 */
|
|
743
|
+
initializeSandBox() {
|
|
744
|
+
if (this.scopeJs) {
|
|
745
|
+
this.sandBox = new SandBox(this);
|
|
746
|
+
}
|
|
938
747
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
return rawMethod.call(container, targetChild);
|
|
945
|
-
};
|
|
946
|
-
var elementInsertHandler = (parent, newChild, passiveChild, rawMethod) => {
|
|
947
|
-
if (!newChild.__BK_WEWEB_APP_KEY__) {
|
|
948
|
-
return rawMethod.call(parent, newChild, passiveChild);
|
|
748
|
+
/** 设置容器属性 */
|
|
749
|
+
setContainerAttribute(container) {
|
|
750
|
+
if (container instanceof HTMLElement) {
|
|
751
|
+
container.setAttribute(CSS_ATTRIBUTE_KEY, this.name);
|
|
752
|
+
}
|
|
949
753
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
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);
|
|
953
763
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
764
|
+
/** 设置容器 */
|
|
765
|
+
setupContainer() {
|
|
766
|
+
if (this.container) {
|
|
767
|
+
this.container.innerHTML = "";
|
|
768
|
+
const instanceWrapper = this.createInstanceWrapper();
|
|
769
|
+
this.container.appendChild(instanceWrapper);
|
|
770
|
+
}
|
|
960
771
|
}
|
|
961
|
-
|
|
962
|
-
|
|
772
|
+
/** 执行样式 */
|
|
773
|
+
executeStyles() {
|
|
774
|
+
if (this.source?.styles.size && this.container) {
|
|
775
|
+
executeAppStyles(this, this.container);
|
|
776
|
+
}
|
|
963
777
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
element.setAttribute("data-from", app.name);
|
|
970
|
-
element.setAttribute("data-keep-alive", "true");
|
|
778
|
+
/** 创建实例包装器 */
|
|
779
|
+
createInstanceWrapper() {
|
|
780
|
+
const wrapper = document.createElement("div");
|
|
781
|
+
wrapper.id = `${this.name}${WRAPPER_SUFFIX}`;
|
|
782
|
+
return wrapper;
|
|
971
783
|
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
return await app.fetchSource(url, options);
|
|
981
|
-
} catch {
|
|
982
|
-
return "";
|
|
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
|
+
}
|
|
983
792
|
}
|
|
984
793
|
}
|
|
985
|
-
|
|
986
|
-
|
|
794
|
+
/** 获取脚本信息 */
|
|
795
|
+
getScriptInfo() {
|
|
796
|
+
const script = this.source?.getScript(this.url);
|
|
797
|
+
return script ? { exportInstance: script.exportInstance } : void 0;
|
|
987
798
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
return
|
|
991
|
-
} catch {
|
|
992
|
-
return "";
|
|
799
|
+
/** 检查是否需要重新加载 */
|
|
800
|
+
needsReload() {
|
|
801
|
+
return this.status === AppState.ERROR || this.status === AppState.UNSET;
|
|
993
802
|
}
|
|
994
803
|
};
|
|
995
804
|
|
|
996
|
-
// src/entry/
|
|
997
|
-
var
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
HTTP_PROTOCOL: /^(https?:)?\/\//,
|
|
1004
|
-
RELATIVE_PATH: /^((\.\.?\/)|[^/])/,
|
|
1005
|
-
ROOT_HOST_PATTERN: /(:?:root|html)/gm
|
|
1006
|
-
};
|
|
1007
|
-
var STYLE_ATTRIBUTES = {
|
|
1008
|
-
TYPE: "text/css",
|
|
1009
|
-
POWERED_BY: "bk-weweb",
|
|
1010
|
-
LINKED_FROM_BASE: "linked-from-base",
|
|
1011
|
-
ORIGIN_SRC: "origin-src"
|
|
1012
|
-
};
|
|
1013
|
-
var PACK_RULE_NAMES = {
|
|
1014
|
-
MEDIA: "media",
|
|
1015
|
-
SUPPORTS: "supports"
|
|
1016
|
-
};
|
|
1017
|
-
var Style = class {
|
|
805
|
+
// src/entry/script.ts
|
|
806
|
+
var firstGlobalProp;
|
|
807
|
+
var secondGlobalProp;
|
|
808
|
+
var lastGlobalProp;
|
|
809
|
+
var STRICT_MODE_REGEX = /^"use\sstrict";$/gim;
|
|
810
|
+
var Script = class {
|
|
811
|
+
async = false;
|
|
1018
812
|
code = "";
|
|
813
|
+
defer = false;
|
|
814
|
+
exportInstance;
|
|
1019
815
|
fromHtml;
|
|
816
|
+
blobUrl;
|
|
1020
817
|
initial;
|
|
1021
|
-
|
|
1022
|
-
preload = false;
|
|
818
|
+
isModule = false;
|
|
1023
819
|
scoped;
|
|
1024
|
-
scopedCode = "";
|
|
1025
820
|
url;
|
|
1026
|
-
constructor({ code, fromHtml, initial,
|
|
1027
|
-
this.
|
|
1028
|
-
this.
|
|
1029
|
-
this.
|
|
1030
|
-
this.
|
|
821
|
+
constructor({ async, code, defer, fromHtml, initial, isModule, url }) {
|
|
822
|
+
this.code = code?.replace(STRICT_MODE_REGEX, "");
|
|
823
|
+
this.async = async;
|
|
824
|
+
this.defer = defer;
|
|
825
|
+
this.isModule = isModule;
|
|
1031
826
|
this.url = url;
|
|
1032
|
-
this.
|
|
827
|
+
this.scoped = false;
|
|
828
|
+
this.fromHtml = fromHtml ?? false;
|
|
1033
829
|
this.initial = initial ?? false;
|
|
830
|
+
this.blobUrl = void 0;
|
|
1034
831
|
}
|
|
1035
|
-
/**
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
832
|
+
/** 执行脚本代码 */
|
|
833
|
+
async executeCode(app, needReplaceScriptElement = false) {
|
|
834
|
+
try {
|
|
835
|
+
if (!this.code) await this.getCode(app);
|
|
836
|
+
if (app instanceof MicroInstanceModel) {
|
|
837
|
+
const globalWindow = app.scopeJs ? app.sandBox?.proxyWindow || window : window;
|
|
838
|
+
noteGlobalProps(globalWindow);
|
|
839
|
+
}
|
|
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) {
|
|
863
|
+
const scriptElement = document.createElement("script");
|
|
864
|
+
if (scriptElement.__BK_WEWEB_APP_KEY__) {
|
|
865
|
+
scriptElement.__BK_WEWEB_APP_KEY__ = void 0;
|
|
866
|
+
}
|
|
867
|
+
app.registerRunningApp();
|
|
868
|
+
this.executeSourceScript(scriptElement, scopedCode);
|
|
869
|
+
if (needReplaceScriptElement) return scriptElement;
|
|
870
|
+
const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
|
|
871
|
+
const container = needKeepAlive ? document.head : app.container;
|
|
872
|
+
setMarkElement(scriptElement, app, needKeepAlive);
|
|
873
|
+
container.appendChild(scriptElement);
|
|
874
|
+
} else {
|
|
875
|
+
this.executeMemoryScript(app, scopedCode);
|
|
876
|
+
if (needReplaceScriptElement) return document.createComment("\u3010bk-weweb\u3011dynamic script");
|
|
877
|
+
}
|
|
878
|
+
if (app instanceof MicroInstanceModel) {
|
|
879
|
+
const globalWindow = app.scopeJs ? app.sandBox?.proxyWindow || window : window;
|
|
880
|
+
const isIifeVar = !!this.code.replace(/\/\*[\s\S]*?\*\//g, "").match(/^\s*var\s/);
|
|
881
|
+
const exportProp = getGlobalProp(globalWindow, isIifeVar);
|
|
882
|
+
if (exportProp) {
|
|
883
|
+
this.exportInstance = globalWindow[exportProp];
|
|
884
|
+
if (!app.scopeJs) {
|
|
885
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalWindow, exportProp);
|
|
886
|
+
if (descriptor?.configurable) {
|
|
887
|
+
delete globalWindow[exportProp];
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
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");
|
|
1043
916
|
} else {
|
|
1044
|
-
|
|
917
|
+
scriptElement.textContent = scopedCode;
|
|
1045
918
|
}
|
|
1046
|
-
this.
|
|
919
|
+
this.url && scriptElement.setAttribute("origin-src", this.url);
|
|
1047
920
|
}
|
|
1048
|
-
/**
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
const styleElement = document.createElement("style");
|
|
1053
|
-
if (styleElement.__BK_WEWEB_APP_KEY__) {
|
|
1054
|
-
styleElement.__BK_WEWEB_APP_KEY__ = void 0;
|
|
921
|
+
/** 获取脚本内容 */
|
|
922
|
+
async getCode(app) {
|
|
923
|
+
if (this.code.length || !this.url || this.isModule) {
|
|
924
|
+
return this.code;
|
|
1055
925
|
}
|
|
1056
|
-
|
|
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;
|
|
1057
942
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
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));
|
|
1071
1048
|
}
|
|
1072
|
-
styleElement = this.scopedStyleCSS(app, styleElement);
|
|
1073
|
-
this.scoped = true;
|
|
1074
|
-
} catch (error) {
|
|
1075
|
-
console.error("scoped style error", error);
|
|
1076
1049
|
}
|
|
1077
|
-
return styleElement;
|
|
1078
1050
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
return
|
|
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");
|
|
1089
1061
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
* @param app 应用实例
|
|
1094
|
-
* @returns 是否已链接基础样式
|
|
1095
|
-
*/
|
|
1096
|
-
linkedBaseStyle(styleElement, app) {
|
|
1097
|
-
if (!(app.container instanceof ShadowRoot) && styleElement.textContent && appCache.getBaseAppStyle(styleElement.textContent)) {
|
|
1098
|
-
this.clearStyleElement(styleElement);
|
|
1099
|
-
styleElement.setAttribute(STYLE_ATTRIBUTES.LINKED_FROM_BASE, "true");
|
|
1100
|
-
return true;
|
|
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");
|
|
1101
1065
|
}
|
|
1102
|
-
return false;
|
|
1103
1066
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
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);
|
|
1110
1075
|
}
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
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);
|
|
1119
1093
|
}
|
|
1120
|
-
if (
|
|
1121
|
-
|
|
1094
|
+
if (isJsonpUrl(child.getAttribute("src"))) {
|
|
1095
|
+
app.container?.append(child);
|
|
1096
|
+
return;
|
|
1122
1097
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
}
|
|
1126
|
-
/**
|
|
1127
|
-
* css rule 处理
|
|
1128
|
-
*/
|
|
1129
|
-
scopeRule(rules, cssPrefix) {
|
|
1130
|
-
let result = "";
|
|
1131
|
-
for (const rule of rules) {
|
|
1132
|
-
switch (rule.type) {
|
|
1133
|
-
case 1 /* STYLE_RULE */:
|
|
1134
|
-
result += this.scopeStyleRule(rule, cssPrefix);
|
|
1135
|
-
break;
|
|
1136
|
-
case 4 /* MEDIA_RULE */:
|
|
1137
|
-
result += this.resetPackRule(rule, cssPrefix, PACK_RULE_NAMES.MEDIA);
|
|
1138
|
-
break;
|
|
1139
|
-
case 12 /* SUPPORTS_RULE */:
|
|
1140
|
-
result += this.resetPackRule(rule, cssPrefix, PACK_RULE_NAMES.SUPPORTS);
|
|
1141
|
-
break;
|
|
1142
|
-
default:
|
|
1143
|
-
result += rule.cssText;
|
|
1144
|
-
break;
|
|
1098
|
+
if (scriptInfo?.script) {
|
|
1099
|
+
scriptInfo.script.executeCode(app);
|
|
1145
1100
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
return all.replace(CSS_SELECTORS.BUILT_IN_ROOT_SELECTOR, prefix);
|
|
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);
|
|
1165
1119
|
}
|
|
1166
|
-
|
|
1167
|
-
})
|
|
1168
|
-
);
|
|
1169
|
-
}
|
|
1170
|
-
/**
|
|
1171
|
-
* link style 处理
|
|
1172
|
-
*/
|
|
1173
|
-
scopedLinkCSS(app, linkElement) {
|
|
1174
|
-
const styleElement = this.createStyleElement();
|
|
1175
|
-
styleElement.setAttribute("type", STYLE_ATTRIBUTES.TYPE);
|
|
1176
|
-
const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
|
|
1177
|
-
setMarkElement(styleElement, app, needKeepAlive);
|
|
1178
|
-
const container = needKeepAlive ? document.head : app.container;
|
|
1179
|
-
try {
|
|
1180
|
-
if (this.code) {
|
|
1181
|
-
this.handleExistingCode(styleElement, app, container, linkElement);
|
|
1182
|
-
} else if (linkElement.getAttribute("href")) {
|
|
1183
|
-
this.handleHrefAttribute(styleElement, app, container, linkElement);
|
|
1184
|
-
} else {
|
|
1185
|
-
this.handleMissingHref(styleElement, app, container, linkElement);
|
|
1120
|
+
child.remove();
|
|
1186
1121
|
}
|
|
1187
|
-
} catch {
|
|
1188
|
-
linkElement && dispatchLinkOrScriptError(linkElement);
|
|
1189
1122
|
}
|
|
1190
|
-
|
|
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;
|
|
1191
1130
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
*/
|
|
1195
|
-
scopedStyleCSS(app, styleElement) {
|
|
1196
|
-
const needKeepAlive = !!app.keepAlive && !(app.container instanceof ShadowRoot);
|
|
1197
|
-
setMarkElement(styleElement, app, needKeepAlive);
|
|
1198
|
-
if (this.code || styleElement.textContent) {
|
|
1199
|
-
this.processExistingContent(styleElement, app);
|
|
1200
|
-
} else {
|
|
1201
|
-
this.observeContentChanges(styleElement, app);
|
|
1202
|
-
}
|
|
1203
|
-
if (this.url) {
|
|
1204
|
-
styleElement.setAttribute(STYLE_ATTRIBUTES.ORIGIN_SRC, this.url);
|
|
1205
|
-
}
|
|
1206
|
-
return styleElement;
|
|
1131
|
+
if (replaceInfo.script) {
|
|
1132
|
+
replaceInfo.script.executeCode(app);
|
|
1207
1133
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
*/
|
|
1211
|
-
applyScopedCSS(styleElement, app) {
|
|
1212
|
-
const cssStyleSheet = new CSSStyleSheet({ disabled: true });
|
|
1213
|
-
cssStyleSheet.replaceSync(styleElement.textContent || this.code);
|
|
1214
|
-
const rules = Array.from(cssStyleSheet?.cssRules ?? []);
|
|
1215
|
-
const cssPrefix = `#${app.name}`;
|
|
1216
|
-
const scopedCss = this.scopeRule(rules, cssPrefix);
|
|
1217
|
-
const cssText = this.resetUrlHost(scopedCss, app.url, this.url);
|
|
1218
|
-
styleElement.textContent = cssText;
|
|
1219
|
-
this.scopedCode = cssText;
|
|
1134
|
+
if (replaceInfo.replace !== child) {
|
|
1135
|
+
return replaceInfo.replace;
|
|
1220
1136
|
}
|
|
1221
|
-
|
|
1222
|
-
const
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
}
|
|
1226
|
-
styleElement.textContent = cssText.replace(CSS_SELECTORS.ROOT_HOST_PATTERN, ":host");
|
|
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");
|
|
1227
1141
|
}
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
const fontFaces = cssText.match(CSS_SELECTORS.FONT_FACE) || [];
|
|
1234
|
-
for (const fontFace of fontFaces) {
|
|
1235
|
-
fontContent += `${fontFace}
|
|
1236
|
-
`;
|
|
1237
|
-
}
|
|
1238
|
-
const rawDocument = app.sandBox?.rawDocument;
|
|
1239
|
-
if (rawDocument && fontContent) {
|
|
1240
|
-
const fontStyle = rawDocument.createElement("style");
|
|
1241
|
-
fontStyle.setAttribute("type", STYLE_ATTRIBUTES.TYPE);
|
|
1242
|
-
fontStyle.setAttribute("powered-by", STYLE_ATTRIBUTES.POWERED_BY);
|
|
1243
|
-
fontStyle.textContent = fontContent;
|
|
1244
|
-
rawDocument?.head?.append(fontStyle);
|
|
1245
|
-
}
|
|
1142
|
+
return child;
|
|
1143
|
+
};
|
|
1144
|
+
var resetNewElement = (parent, child, app) => {
|
|
1145
|
+
if (child instanceof HTMLStyleElement) {
|
|
1146
|
+
return handleStyleElement(child, app);
|
|
1246
1147
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
return app.source.styles.get(this.url)?.code || "";
|
|
1250
|
-
}
|
|
1251
|
-
return "";
|
|
1148
|
+
if (child instanceof HTMLLinkElement) {
|
|
1149
|
+
return handleLinkElement(child, parent, app);
|
|
1252
1150
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const style = appCache.getCacheStyle(this.url);
|
|
1256
|
-
return style?.code || "";
|
|
1257
|
-
}
|
|
1258
|
-
return "";
|
|
1151
|
+
if (child instanceof HTMLScriptElement) {
|
|
1152
|
+
return handleScriptElement(child, parent, app);
|
|
1259
1153
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
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);
|
|
1262
1166
|
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1167
|
+
const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
|
|
1168
|
+
if (!app?.container) {
|
|
1169
|
+
return rawMethod.call(parent, newChild);
|
|
1266
1170
|
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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);
|
|
1271
1181
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
linkElement && dispatchLinkOrScriptLoad(linkElement);
|
|
1182
|
+
const app = appCache.getApp(newChild.__BK_WEWEB_APP_KEY__);
|
|
1183
|
+
if (!app?.container) {
|
|
1184
|
+
return rawMethod.call(parent, newChild, passiveChild);
|
|
1276
1185
|
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
this.scopedStyleCSS(app, styleElement);
|
|
1284
|
-
linkElement.remove();
|
|
1285
|
-
container?.prepend(styleElement);
|
|
1286
|
-
linkElement && dispatchLinkOrScriptLoad(linkElement);
|
|
1287
|
-
this.scoped = true;
|
|
1288
|
-
});
|
|
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);
|
|
1289
1192
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
*/
|
|
1293
|
-
handleMissingHref(styleElement, app, container, linkElement) {
|
|
1294
|
-
const observer = new MutationObserver(() => {
|
|
1295
|
-
const href = linkElement.getAttribute("href");
|
|
1296
|
-
if (!href) return;
|
|
1297
|
-
observer.disconnect();
|
|
1298
|
-
this.url = fillUpPath(href, app.url);
|
|
1299
|
-
this.getCode(app).then(() => {
|
|
1300
|
-
this.scopedStyleCSS(app, styleElement);
|
|
1301
|
-
linkElement.remove();
|
|
1302
|
-
container?.prepend(styleElement);
|
|
1303
|
-
linkElement && dispatchLinkOrScriptLoad(linkElement);
|
|
1304
|
-
this.scoped = true;
|
|
1305
|
-
});
|
|
1306
|
-
});
|
|
1307
|
-
const observerConfig = {
|
|
1308
|
-
attributeFilter: ["href"],
|
|
1309
|
-
childList: false,
|
|
1310
|
-
subtree: false
|
|
1311
|
-
};
|
|
1312
|
-
observer.observe(linkElement, observerConfig);
|
|
1193
|
+
if (passiveChild && !container.contains(passiveChild)) {
|
|
1194
|
+
return bodyAppendChild.call(container, targetChild);
|
|
1313
1195
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
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;
|
|
1317
1238
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
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
|
+
});
|
|
1320
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;
|
|
1321
1297
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
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;
|
|
1328
1381
|
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
subtree: true
|
|
1335
|
-
};
|
|
1336
|
-
observer.observe(styleElement, observerConfig);
|
|
1337
|
-
}
|
|
1338
|
-
};
|
|
1339
|
-
async function executeAppStyles(app, container) {
|
|
1340
|
-
const styleList = Array.from(app.source?.styles?.values() || []);
|
|
1341
|
-
const promiseList = [];
|
|
1342
|
-
for (const style of styleList) {
|
|
1343
|
-
promiseList.push(style.executeCode(app));
|
|
1344
|
-
}
|
|
1345
|
-
await Promise.all(promiseList).then((styleElementList) => {
|
|
1346
|
-
const parentElement = container || app.container;
|
|
1347
|
-
if (app.keepAlive && !(parentElement instanceof ShadowRoot)) {
|
|
1348
|
-
document.head.append(...styleElementList);
|
|
1349
|
-
} else {
|
|
1350
|
-
parentElement?.append(...styleElementList);
|
|
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;
|
|
1351
1387
|
}
|
|
1352
1388
|
});
|
|
1353
|
-
}
|
|
1389
|
+
};
|
|
1354
1390
|
|
|
1355
|
-
// src/
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
isPreLoad = false;
|
|
1366
|
-
keepAlive;
|
|
1367
|
-
name;
|
|
1368
|
-
sandBox;
|
|
1369
|
-
scopeCss = true;
|
|
1370
|
-
scopeJs = false;
|
|
1371
|
-
showSourceCode = true;
|
|
1372
|
-
source;
|
|
1373
|
-
url;
|
|
1374
|
-
constructor(props) {
|
|
1375
|
-
this.name = props.id !== props.url ? props.id : random(DEFAULT_RANDOM_LENGTH);
|
|
1376
|
-
this.appCacheKey = props.id || this.name;
|
|
1377
|
-
this.url = props.url;
|
|
1378
|
-
this.container = props.container ?? void 0;
|
|
1379
|
-
this.scopeJs = props.scopeJs ?? true;
|
|
1380
|
-
this.showSourceCode = props.showSourceCode ?? true;
|
|
1381
|
-
this.scopeCss = props.scopeCss ?? true;
|
|
1382
|
-
this.keepAlive = props.keepAlive ?? false;
|
|
1383
|
-
this.data = props.data ?? {};
|
|
1384
|
-
this.initSource = props.initSource ?? [];
|
|
1385
|
-
this.fetchSource = props.fetchSource;
|
|
1386
|
-
this.initializeSandBox();
|
|
1387
|
-
}
|
|
1388
|
-
/** 激活微模块 */
|
|
1389
|
-
activated(container, callback) {
|
|
1390
|
-
this.isPreLoad = false;
|
|
1391
|
-
this.state = AppState.ACTIVATED;
|
|
1392
|
-
if (this.container && container) {
|
|
1393
|
-
this.setContainerAttribute(container);
|
|
1394
|
-
this.transferNodes(container);
|
|
1395
|
-
this.container = container;
|
|
1396
|
-
this.sandBox?.activated();
|
|
1397
|
-
const scriptInfo = this.getScriptInfo();
|
|
1398
|
-
callback?.(this, scriptInfo?.exportInstance);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
/** 停用微模块 */
|
|
1402
|
-
deactivated() {
|
|
1403
|
-
this.state = AppState.DEACTIVATED;
|
|
1404
|
-
this.sandBox?.deactivated();
|
|
1405
|
-
}
|
|
1406
|
-
/** 挂载微模块 */
|
|
1407
|
-
mount(container, callback) {
|
|
1408
|
-
this.isPreLoad = false;
|
|
1409
|
-
this.container = container ?? this.container;
|
|
1410
|
-
this.state = AppState.MOUNTING;
|
|
1411
|
-
this.setContainerAttribute(this.container);
|
|
1412
|
-
this.setupContainer();
|
|
1413
|
-
this.executeStyles();
|
|
1414
|
-
this.sandBox?.activated();
|
|
1415
|
-
execAppScripts(this).finally(() => {
|
|
1416
|
-
this.state = AppState.MOUNTED;
|
|
1417
|
-
this.renderInstance();
|
|
1418
|
-
const scriptInfo = this.getScriptInfo();
|
|
1419
|
-
callback?.(this, scriptInfo?.exportInstance);
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
1422
|
-
/** 错误处理 */
|
|
1423
|
-
onError() {
|
|
1424
|
-
this.state = AppState.ERROR;
|
|
1425
|
-
}
|
|
1426
|
-
/** 挂载处理 */
|
|
1427
|
-
onMount() {
|
|
1428
|
-
if (this.isPreLoad) return;
|
|
1429
|
-
this.state = AppState.LOADED;
|
|
1430
|
-
this.mount();
|
|
1431
|
-
}
|
|
1432
|
-
/** 注册运行中的应用 */
|
|
1433
|
-
registerRunningApp() {
|
|
1434
|
-
setCurrentRunningApp(this);
|
|
1435
|
-
Promise.resolve().then(() => setCurrentRunningApp(null));
|
|
1436
|
-
}
|
|
1437
|
-
/** 启动微模块 */
|
|
1438
|
-
async start() {
|
|
1439
|
-
if (!this.source || this.needsReload()) {
|
|
1440
|
-
this.source = new EntrySource(this.url);
|
|
1441
|
-
await this.source.importEntry(this);
|
|
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]);
|
|
1442
1401
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
if (
|
|
1449
|
-
|
|
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
|
+
}
|
|
1450
1412
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
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
|
+
}
|
|
1454
1424
|
}
|
|
1425
|
+
document.addEventListener = addEventListener;
|
|
1426
|
+
document.body.addEventListener = bodyAddEventListener;
|
|
1427
|
+
document.removeEventListener = removeEventListener;
|
|
1428
|
+
document.body.removeEventListener = bodyRemoveEventListener;
|
|
1429
|
+
documentListenerMap.clear();
|
|
1455
1430
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
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;
|
|
1458
1443
|
}
|
|
1459
|
-
|
|
1460
|
-
return
|
|
1444
|
+
if (ConstructFunCacheMap.has(fn)) {
|
|
1445
|
+
return ConstructFunCacheMap.get(fn);
|
|
1461
1446
|
}
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
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);
|
|
1467
1455
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
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];
|
|
1472
1460
|
}
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
for (const node of nodeList) {
|
|
1480
|
-
fragment.appendChild(node);
|
|
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
|
+
});
|
|
1481
1467
|
}
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
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
|
+
}
|
|
1490
1481
|
}
|
|
1482
|
+
functionBoundedValueMap.set(value, boundValue);
|
|
1483
|
+
return boundValue;
|
|
1491
1484
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
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);
|
|
1496
1503
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
const
|
|
1501
|
-
|
|
1502
|
-
return
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
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);
|
|
1511
1528
|
}
|
|
1512
1529
|
}
|
|
1513
1530
|
}
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
}
|
|
1519
|
-
/** 检查是否需要重新加载 */
|
|
1520
|
-
needsReload() {
|
|
1521
|
-
return this.status === AppState.ERROR || this.status === AppState.UNSET;
|
|
1522
|
-
}
|
|
1523
|
-
};
|
|
1531
|
+
return {
|
|
1532
|
+
resetWindowFunction
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1524
1535
|
|
|
1525
|
-
// src/
|
|
1526
|
-
var
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
this.
|
|
1543
|
-
this.
|
|
1544
|
-
this.
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
this.initial = initial ?? false;
|
|
1549
|
-
}
|
|
1550
|
-
/** 执行脚本代码 */
|
|
1551
|
-
async executeCode(app, needReplaceScriptElement = false) {
|
|
1552
|
-
try {
|
|
1553
|
-
if (!this.code) await this.getCode(app);
|
|
1554
|
-
if (app instanceof MicroInstanceModel) {
|
|
1555
|
-
const globalWindow = app.scopeJs ? app.sandBox?.proxyWindow || window : window;
|
|
1556
|
-
noteGlobalProps(globalWindow);
|
|
1557
|
-
}
|
|
1558
|
-
const scopedCode = this.transformCode(app);
|
|
1559
|
-
if (app.showSourceCode || this.isModule) {
|
|
1560
|
-
const scriptElement = document.createElement("script");
|
|
1561
|
-
if (scriptElement.__BK_WEWEB_APP_KEY__) {
|
|
1562
|
-
scriptElement.__BK_WEWEB_APP_KEY__ = void 0;
|
|
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);
|
|
1563
1559
|
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
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
1586
|
}
|
|
1587
|
+
return descriptor;
|
|
1587
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);
|
|
1588
1595
|
}
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
}
|
|
1592
|
-
return;
|
|
1596
|
+
});
|
|
1597
|
+
rawWindow[this.windowSymbolKey] = this.proxyWindow;
|
|
1593
1598
|
}
|
|
1594
|
-
/**
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
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;
|
|
1606
1645
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
executeSourceScript(scriptElement, scopedCode) {
|
|
1610
|
-
if (this.isModule) {
|
|
1611
|
-
scriptElement.src = `${this.url}?key=${Date.now()}`;
|
|
1612
|
-
scriptElement.setAttribute("type", "module");
|
|
1613
|
-
} else {
|
|
1614
|
-
scriptElement.textContent = scopedCode;
|
|
1646
|
+
if (key === "hasOwnProperty") {
|
|
1647
|
+
return (checkKey) => Object.hasOwn(this.fakeWindow, checkKey) || Object.hasOwn(rawWindow, checkKey);
|
|
1615
1648
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
return this.code;
|
|
1649
|
+
if (key === "top" || key === "parent") {
|
|
1650
|
+
if (rawWindow === rawWindow.parent) {
|
|
1651
|
+
return this.proxyWindow;
|
|
1652
|
+
}
|
|
1653
|
+
return Reflect.get(rawWindow, key);
|
|
1622
1654
|
}
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
code = app.source.getScript(this.url)?.code || "";
|
|
1655
|
+
if (key === "getComputedStyle") {
|
|
1656
|
+
return this.createGetComputedStyleProxy(rawWindow);
|
|
1626
1657
|
}
|
|
1627
|
-
if (
|
|
1628
|
-
|
|
1658
|
+
if (Reflect.has(target, key) || BK_WEWEB_INJECT_KEY_LIST.includes(key)) {
|
|
1659
|
+
return Reflect.get(target, key);
|
|
1629
1660
|
}
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
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;
|
|
1635
1677
|
}
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
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;
|
|
1681
|
+
}
|
|
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;
|
|
1639
1692
|
}
|
|
1640
|
-
|
|
1641
|
-
|
|
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);
|
|
1642
1702
|
}
|
|
1643
|
-
/**
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
if (app.showSourceCode) {
|
|
1655
|
-
return `;(function(window, self, globalThis){
|
|
1656
|
-
with(window){
|
|
1657
|
-
${getGlobalContextCode()}
|
|
1658
|
-
|
|
1659
|
-
${this.code}
|
|
1660
|
-
|
|
1661
|
-
${sourceMapUrl}
|
|
1662
|
-
}
|
|
1663
|
-
}).call(window.${app.sandBox.windowSymbolKey},
|
|
1664
|
-
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);
|
|
1665
1714
|
}
|
|
1666
|
-
return
|
|
1667
|
-
|
|
1668
|
-
try {
|
|
1669
|
-
${getGlobalContextCode()}
|
|
1670
|
-
|
|
1671
|
-
${this.code}
|
|
1672
|
-
|
|
1673
|
-
${sourceMapUrl}
|
|
1674
|
-
}
|
|
1675
|
-
catch(e) {
|
|
1676
|
-
console.error(e)
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
`;
|
|
1680
|
-
}
|
|
1681
|
-
return this.code;
|
|
1715
|
+
return rawWindow.getComputedStyle(document.body, pseudoElt);
|
|
1716
|
+
};
|
|
1682
1717
|
}
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
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;
|
|
1699
1743
|
}
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
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);
|
|
1705
1753
|
}
|
|
1706
|
-
cnt += 1;
|
|
1707
1754
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
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);
|
|
1719
1767
|
}
|
|
1720
|
-
lastGlobalProp = property;
|
|
1721
1768
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
deferScriptList.push(script.executeCode(app));
|
|
1735
|
-
} else {
|
|
1736
|
-
asyncScriptList.push(script.executeCode(app));
|
|
1737
|
-
}
|
|
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;
|
|
1738
1781
|
}
|
|
1739
1782
|
}
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
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);
|
|
1793
|
+
}
|
|
1794
|
+
this.inRawWindowKeySet.clear();
|
|
1795
|
+
this.resetDocumentAndBodyEvent?.();
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1744
1798
|
|
|
1745
1799
|
// src/mode/app.ts
|
|
1746
1800
|
var IFRAME_CONSTANTS = {
|
|
@@ -2683,7 +2737,11 @@ function createOverriddenAppendChild() {
|
|
|
2683
2737
|
if (keepAliveResult) {
|
|
2684
2738
|
return keepAliveResult;
|
|
2685
2739
|
}
|
|
2686
|
-
|
|
2740
|
+
const node = elementAppendHandler(this, newChild, bodyAppendChild2);
|
|
2741
|
+
if (node?.tagName === "STYLE") {
|
|
2742
|
+
node.insertAdjacentElement = createOverriddenInsertAdjacentElement();
|
|
2743
|
+
}
|
|
2744
|
+
return node;
|
|
2687
2745
|
};
|
|
2688
2746
|
}
|
|
2689
2747
|
function createOverriddenAppend() {
|
|
@@ -2714,6 +2772,16 @@ function createOverriddenRemoveChild() {
|
|
|
2714
2772
|
return oldChild;
|
|
2715
2773
|
};
|
|
2716
2774
|
}
|
|
2775
|
+
var insertAdjacentElement = createOverriddenInsertAdjacentElement();
|
|
2776
|
+
function createOverriddenInsertAdjacentElement() {
|
|
2777
|
+
return function(where, element) {
|
|
2778
|
+
const node = elementAppendHandler(this, element, headAppendChild);
|
|
2779
|
+
if (node?.tagName === "STYLE") {
|
|
2780
|
+
node.insertAdjacentElement = insertAdjacentElement;
|
|
2781
|
+
}
|
|
2782
|
+
return node;
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2717
2785
|
function rewriteBodyAndHeaderMethods() {
|
|
2718
2786
|
if (hasRewrite) {
|
|
2719
2787
|
return;
|
|
@@ -2862,7 +2930,7 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2862
2930
|
*/
|
|
2863
2931
|
async handleAttributeChanged() {
|
|
2864
2932
|
if (!this.appKey) return;
|
|
2865
|
-
if (this.
|
|
2933
|
+
if (this.setShadowDomAttr) {
|
|
2866
2934
|
this.attachShadow({ mode: "open" });
|
|
2867
2935
|
}
|
|
2868
2936
|
const app = appCache.getApp(this.appKey);
|
|
@@ -2887,13 +2955,21 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2887
2955
|
this.handleAttributeChanged();
|
|
2888
2956
|
}
|
|
2889
2957
|
}
|
|
2958
|
+
/**
|
|
2959
|
+
* 获取是否启用 Shadow DOM 属性
|
|
2960
|
+
* @description 获取是否启用 Shadow DOM 属性 兼容旧版使用
|
|
2961
|
+
* @returns boolean | undefined - 是否启用 Shadow DOM 属性
|
|
2962
|
+
*/
|
|
2963
|
+
get setShadowDomAttr() {
|
|
2964
|
+
return this.getBooleanAttr("setShadowDom" /* setShadowDom */) ?? this.getBooleanAttr("setShodowDom" /* setShodowDom */);
|
|
2965
|
+
}
|
|
2890
2966
|
/**
|
|
2891
2967
|
* 组件连接到 DOM 时的回调
|
|
2892
2968
|
* @description 当自定义元素被插入到 DOM 时触发
|
|
2893
2969
|
* @returns Promise<void>
|
|
2894
2970
|
*/
|
|
2895
2971
|
async connectedCallback() {
|
|
2896
|
-
if (this.
|
|
2972
|
+
if (this.setShadowDomAttr && !this.shadowRoot) {
|
|
2897
2973
|
this.attachShadow({ delegatesFocus: false, mode: "open" });
|
|
2898
2974
|
}
|
|
2899
2975
|
await load(this.appProps);
|
|
@@ -2954,14 +3030,14 @@ var BkWewebElement = class extends HTMLElement {
|
|
|
2954
3030
|
return {
|
|
2955
3031
|
...commonProps,
|
|
2956
3032
|
mode: "js" /* INSTANCE */,
|
|
2957
|
-
scopeCss: this.getBooleanAttr("scopeCss" /* scopeCss */) && !this.
|
|
3033
|
+
scopeCss: this.getBooleanAttr("scopeCss" /* scopeCss */) && !this.setShadowDomAttr,
|
|
2958
3034
|
scopeJs: this.getBooleanAttr("scopeJs" /* scopeJs */)
|
|
2959
3035
|
};
|
|
2960
3036
|
}
|
|
2961
3037
|
return {
|
|
2962
3038
|
...commonProps,
|
|
2963
3039
|
mode: "app" /* APP */,
|
|
2964
|
-
scopeCss: !this.
|
|
3040
|
+
scopeCss: !this.setShadowDomAttr,
|
|
2965
3041
|
scopeJs: !this.getBooleanAttr("scopeJs" /* scopeJs */),
|
|
2966
3042
|
scopeLocation: this.getBooleanAttr("scopeLocation" /* scopeLocation */)
|
|
2967
3043
|
};
|