@micro-zoe/micro-app 1.0.0-rc.8 → 1.0.0-rc.9

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/lib/index.d.ts CHANGED
@@ -143,6 +143,10 @@ declare module '@micro-zoe/micro-app/libs/utils' {
143
143
  export function isURL(target: unknown): target is URL;
144
144
  export function isElement(target: unknown): target is Element;
145
145
  export function isNode(target: unknown): target is Node;
146
+ export function isCanvasElement(target: unknown): target is HTMLAnchorElement;
147
+ export function isAnchorElement(target: unknown): target is HTMLAnchorElement;
148
+ export function isAudioElement(target: unknown): target is HTMLAnchorElement;
149
+ export function isVideoElement(target: unknown): target is HTMLAnchorElement;
146
150
  export function isLinkElement(target: unknown): target is HTMLLinkElement;
147
151
  export function isStyleElement(target: unknown): target is HTMLStyleElement;
148
152
  export function isScriptElement(target: unknown): target is HTMLScriptElement;
@@ -340,6 +344,12 @@ declare module '@micro-zoe/micro-app/libs/utils' {
340
344
  * target maybe number, string, array ...
341
345
  */
342
346
  export function isEmptyObject(target: unknown): boolean;
347
+ /**
348
+ *
349
+ * @param {string} url input url
350
+ * @returns {boolean} is relative path
351
+ */
352
+ export const isRelativePath: (url: string) => boolean;
343
353
  }
344
354
 
345
355
  declare module '@micro-zoe/micro-app/interact' {
package/lib/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- const version = '1.0.0-rc.8';
1
+ const version = '1.0.0-rc.9';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -89,6 +89,15 @@ function isNode(target) {
89
89
  var _a;
90
90
  return target instanceof Node || isNumber((_a = target) === null || _a === void 0 ? void 0 : _a.nodeType);
91
91
  }
92
+ function isAnchorElement(target) {
93
+ return toTypeString(target) === '[object HTMLAnchorElement]';
94
+ }
95
+ function isAudioElement(target) {
96
+ return toTypeString(target) === '[object HTMLAudioElement]';
97
+ }
98
+ function isVideoElement(target) {
99
+ return toTypeString(target) === '[object HTMLVideoElement]';
100
+ }
92
101
  function isLinkElement(target) {
93
102
  return toTypeString(target) === '[object HTMLLinkElement]';
94
103
  }
@@ -643,6 +652,12 @@ function formatEventType(type, appName) {
643
652
  function isEmptyObject(target) {
644
653
  return isPlainObject(target) ? !Object.keys(target).length : true;
645
654
  }
655
+ /**
656
+ *
657
+ * @param {string} url input url
658
+ * @returns {boolean} is relative path
659
+ */
660
+ const isRelativePath = (url) => !/^https?:\/\//i.test(url) && !/^\/\//i.test(url);
646
661
 
647
662
  function formatEventInfo(event, element) {
648
663
  Object.defineProperties(event, {
@@ -865,7 +880,7 @@ class CSSParser {
865
880
  // reset scopecssDisableNextLine
866
881
  this.scopecssDisableNextLine = false;
867
882
  if (!selectors)
868
- return parseError('selector missing', this.linkPath);
883
+ return this.printError('selector missing', this.linkPath);
869
884
  this.recordResult(selectors);
870
885
  this.matchComments();
871
886
  this.styleDeclarations();
@@ -910,10 +925,10 @@ class CSSParser {
910
925
  // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration
911
926
  styleDeclarations() {
912
927
  if (!this.matchOpenBrace())
913
- return parseError("Declaration missing '{'", this.linkPath);
928
+ return this.printError("Declaration missing '{'", this.linkPath);
914
929
  this.matchAllDeclarations();
915
930
  if (!this.matchCloseBrace())
916
- return parseError("Declaration missing '}'", this.linkPath);
931
+ return this.printError("Declaration missing '}'", this.linkPath);
917
932
  return true;
918
933
  }
919
934
  matchAllDeclarations(nesting = 0) {
@@ -936,7 +951,7 @@ class CSSParser {
936
951
  }
937
952
  // reset scopecssDisableNextLine
938
953
  this.scopecssDisableNextLine = false;
939
- if (!this.cssText)
954
+ if (!this.cssText.length)
940
955
  return;
941
956
  // extract comments in declarations
942
957
  if (this.cssText.charAt(0) === '/') {
@@ -990,16 +1005,16 @@ class CSSParser {
990
1005
  if (!this.commonMatch(/^@([-\w]+)?keyframes\s*/))
991
1006
  return false;
992
1007
  if (!this.commonMatch(/^[^{]+/))
993
- return parseError('@keyframes missing name', this.linkPath);
1008
+ return this.printError('@keyframes missing name', this.linkPath);
994
1009
  this.matchComments();
995
1010
  if (!this.matchOpenBrace())
996
- return parseError("@keyframes missing '{'", this.linkPath);
1011
+ return this.printError("@keyframes missing '{'", this.linkPath);
997
1012
  this.matchComments();
998
1013
  while (this.keyframeRule()) {
999
1014
  this.matchComments();
1000
1015
  }
1001
1016
  if (!this.matchCloseBrace())
1002
- return parseError("@keyframes missing '}'", this.linkPath);
1017
+ return this.printError("@keyframes missing '}'", this.linkPath);
1003
1018
  this.matchLeadingSpaces();
1004
1019
  return true;
1005
1020
  }
@@ -1047,7 +1062,7 @@ class CSSParser {
1047
1062
  this.matchComments();
1048
1063
  this.matchRules();
1049
1064
  if (!this.matchCloseBrace())
1050
- return parseError('@layer missing \'}\'', this.linkPath);
1065
+ return this.printError('@layer missing \'}\'', this.linkPath);
1051
1066
  this.matchLeadingSpaces();
1052
1067
  return true;
1053
1068
  }
@@ -1057,11 +1072,11 @@ class CSSParser {
1057
1072
  if (!this.commonMatch(reg))
1058
1073
  return false;
1059
1074
  if (!this.matchOpenBrace())
1060
- return parseError(`${name} missing '{'`, this.linkPath);
1075
+ return this.printError(`${name} missing '{'`, this.linkPath);
1061
1076
  this.matchComments();
1062
1077
  this.matchRules();
1063
1078
  if (!this.matchCloseBrace())
1064
- return parseError(`${name} missing '}'`, this.linkPath);
1079
+ return this.printError(`${name} missing '}'`, this.linkPath);
1065
1080
  this.matchLeadingSpaces();
1066
1081
  return true;
1067
1082
  };
@@ -1079,10 +1094,10 @@ class CSSParser {
1079
1094
  // common handler for @font-face, @page
1080
1095
  commonHandlerForAtRuleWithSelfRule(name) {
1081
1096
  if (!this.matchOpenBrace())
1082
- return parseError(`@${name} missing '{'`, this.linkPath);
1097
+ return this.printError(`@${name} missing '{'`, this.linkPath);
1083
1098
  this.matchAllDeclarations();
1084
1099
  if (!this.matchCloseBrace())
1085
- return parseError(`@${name} missing '}'`, this.linkPath);
1100
+ return this.printError(`@${name} missing '}'`, this.linkPath);
1086
1101
  this.matchLeadingSpaces();
1087
1102
  return true;
1088
1103
  }
@@ -1102,7 +1117,7 @@ class CSSParser {
1102
1117
  ++i;
1103
1118
  i += 2;
1104
1119
  if (this.cssText.charAt(i - 1) === '') {
1105
- return parseError('End of comment missing', this.linkPath);
1120
+ return this.printError('End of comment missing', this.linkPath);
1106
1121
  }
1107
1122
  // get comment content
1108
1123
  let commentText = this.cssText.slice(2, i - 2);
@@ -1162,6 +1177,11 @@ class CSSParser {
1162
1177
  this.result += strFragment;
1163
1178
  }
1164
1179
  }
1180
+ printError(msg, linkPath) {
1181
+ if (this.cssText.length) {
1182
+ parseError(msg, linkPath);
1183
+ }
1184
+ }
1165
1185
  }
1166
1186
  /**
1167
1187
  * common method of bind CSS
@@ -2968,14 +2988,37 @@ function updateElementInfo(node, appName) {
2968
2988
  * 1. 测试baseURI和ownerDocument在with沙箱中是否正确
2969
2989
  * 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
2970
2990
  */
2971
- rawDefineProperties(node, {
2991
+ const props = {
2972
2992
  __MICRO_APP_NAME__: {
2973
2993
  configurable: true,
2974
2994
  enumerable: true,
2975
2995
  writable: true,
2976
2996
  value: appName,
2977
2997
  },
2978
- });
2998
+ };
2999
+ if (isAnchorElement(node)) {
3000
+ // a 标签
3001
+ const microApp = AppManager.getInstance().get(appName);
3002
+ if (microApp) {
3003
+ let originalHref = node.href;
3004
+ props.href = {
3005
+ get() {
3006
+ if (isRelativePath(originalHref)) {
3007
+ return `${microApp.url}${originalHref}`;
3008
+ }
3009
+ return originalHref;
3010
+ },
3011
+ set(value) {
3012
+ originalHref = value;
3013
+ }
3014
+ };
3015
+ }
3016
+ }
3017
+ if (isImageElement(node) || isVideoElement(node) || isAudioElement(node)) {
3018
+ // @ts-ignore
3019
+ node.crossOrigin = 'anonymous';
3020
+ }
3021
+ rawDefineProperties(node, props);
2979
3022
  /**
2980
3023
  * In FireFox, iframe Node.prototype will point to native Node.prototype after insert to document
2981
3024
  *
@@ -5535,7 +5578,7 @@ const proxy2RawDocumentMethods = [
5535
5578
  * @returns EffectHook
5536
5579
  */
5537
5580
  function patchWindow$1(appName, microAppWindow, sandbox) {
5538
- patchWindowProperty$1(appName, microAppWindow);
5581
+ patchWindowProperty$1(appName, microAppWindow, sandbox);
5539
5582
  createProxyWindow$1(microAppWindow, sandbox);
5540
5583
  return patchWindowEffect$1(microAppWindow);
5541
5584
  }
@@ -5544,7 +5587,7 @@ function patchWindow$1(appName, microAppWindow, sandbox) {
5544
5587
  * @param appName app name
5545
5588
  * @param microAppWindow child app microWindow
5546
5589
  */
5547
- function patchWindowProperty$1(appName, microAppWindow) {
5590
+ function patchWindowProperty$1(appName, microAppWindow, sandbox) {
5548
5591
  const rawWindow = globalEnv.rawWindow;
5549
5592
  escape2RawWindowKeys.forEach((key) => {
5550
5593
  microAppWindow[key] = bindFunctionToRawTarget(rawWindow[key], rawWindow);
@@ -5589,25 +5632,10 @@ function patchWindowProperty$1(appName, microAppWindow) {
5589
5632
  configurable: true,
5590
5633
  enumerable: false,
5591
5634
  value(target) {
5592
- return target instanceof rawWindow[key] || instanceOf(target, microAppWindow[key]);
5635
+ return instanceOf(target, rawWindow[key]) || instanceOf(target, microAppWindow[key]);
5593
5636
  },
5594
5637
  });
5595
5638
  }
5596
- // hijackInstanceOfWindowRegExpKeys.some((reg: RegExp) => {
5597
- // if (reg.test(key) && key in rawWindow) {
5598
- // rawDefineProperty(microAppWindow[key], Symbol.hasInstance, {
5599
- // configurable: true,
5600
- // enumerable: false,
5601
- // value: (target: unknown) => {
5602
- // return target instanceof rawWindow[key]
5603
- // ? true
5604
- // : instanceOf(target, microAppWindow[key])
5605
- // },
5606
- // })
5607
- // return true
5608
- // }
5609
- // return false
5610
- // })
5611
5639
  return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_IFRAME.includes(key);
5612
5640
  })
5613
5641
  .forEach((eventName) => {
@@ -5628,6 +5656,23 @@ function patchWindowProperty$1(appName, microAppWindow) {
5628
5656
  logWarn(e, appName);
5629
5657
  }
5630
5658
  });
5659
+ /**
5660
+ * In esmodule(vite) proxyWindow will not take effect,
5661
+ * escapeProperties should define to microAppWindow
5662
+ */
5663
+ sandbox.escapeProperties.forEach((key) => {
5664
+ let rawValue = microAppWindow[key];
5665
+ rawDefineProperty(microAppWindow, key, {
5666
+ enumerable: true,
5667
+ configurable: true,
5668
+ get() {
5669
+ return rawValue !== null && rawValue !== void 0 ? rawValue : bindFunctionToRawTarget(rawWindow[key], rawWindow);
5670
+ },
5671
+ set(value) {
5672
+ rawValue = value;
5673
+ }
5674
+ });
5675
+ });
5631
5676
  }
5632
5677
  /**
5633
5678
  * create proxyWindow with Proxy(microAppWindow)
@@ -5662,7 +5707,7 @@ function createProxyWindow$1(microAppWindow, sandbox) {
5662
5707
  * 2. window.key in module app(vite), fall into microAppWindow(iframeWindow), escapeProperties will not take effect
5663
5708
  * 3. if (key)... --> fall into microAppWindow(iframeWindow), escapeProperties will not take effect
5664
5709
  */
5665
- if (includes(sandbox.escapeProperties, key) && !Reflect.has(target, key)) {
5710
+ if (includes(sandbox.escapeProperties, key) && !Reflect.get(target, key)) {
5666
5711
  return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
5667
5712
  }
5668
5713
  return bindFunctionToRawTarget(Reflect.get(target, key), target);
@@ -5674,17 +5719,13 @@ function createProxyWindow$1(microAppWindow, sandbox) {
5674
5719
  if (!Reflect.has(target, key)) {
5675
5720
  customProperties.add(key);
5676
5721
  }
5722
+ // sandbox.escapeProperties will not set to rawWindow from rc.9
5677
5723
  Reflect.set(target, key, value);
5678
- if (includes(sandbox.escapeProperties, key)) {
5679
- !Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
5680
- Reflect.set(rawWindow, key, value);
5681
- }
5682
5724
  return true;
5683
5725
  },
5684
5726
  has: (target, key) => key in target,
5685
5727
  deleteProperty: (target, key) => {
5686
5728
  if (Reflect.has(target, key)) {
5687
- sandbox.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
5688
5729
  return Reflect.deleteProperty(target, key);
5689
5730
  }
5690
5731
  return true;
@@ -6378,8 +6419,6 @@ class IframeSandbox {
6378
6419
  this.active = false;
6379
6420
  // Properties that can be escape to rawWindow
6380
6421
  this.escapeProperties = [];
6381
- // Properties escape to rawWindow, cleared when unmount
6382
- this.escapeKeys = new Set();
6383
6422
  // Update the base.href when initial and each redirect
6384
6423
  this.updateIframeBase = () => {
6385
6424
  var _a;
@@ -6495,10 +6534,6 @@ class IframeSandbox {
6495
6534
  /* --- memory router part --- end */
6496
6535
  if (!umdMode || destroy) {
6497
6536
  this.deleteIframeElement();
6498
- this.escapeKeys.forEach((key) => {
6499
- Reflect.deleteProperty(globalEnv.rawWindow, key);
6500
- });
6501
- this.escapeKeys.clear();
6502
6537
  this.clearHijackUmdHooks();
6503
6538
  }
6504
6539
  if (--globalEnv.activeSandbox === 0) {
@@ -7852,7 +7887,7 @@ function patchElementAndDocument() {
7852
7887
  },
7853
7888
  set(code) {
7854
7889
  globalEnv.rawInnerHTMLDesc.set.call(this, code);
7855
- const currentAppName = this.__MICRO_APP_NAME__ || getCurrentAppName();
7890
+ const currentAppName = this.__MICRO_APP_NAME__ || getIframeCurrentAppName() || getCurrentAppName();
7856
7891
  Array.from(this.children).forEach((child) => {
7857
7892
  if (isElement(child) && currentAppName) {
7858
7893
  updateElementInfo(child, currentAppName);
@@ -8027,6 +8062,68 @@ function rejectMicroAppStyle() {
8027
8062
  }
8028
8063
  }
8029
8064
 
8065
+ // 重写 Worker 构造函数的类型
8066
+ const originalWorker = window.Worker;
8067
+ function isSameOrigin(url) {
8068
+ if (url instanceof URL && url.protocol === 'blob:') {
8069
+ // 如果 url 是 Blob URL,直接返回 true
8070
+ return true;
8071
+ }
8072
+ // 检查 URL 是否与当前页面在同一个源
8073
+ try {
8074
+ const parsedUrl = new URL(url);
8075
+ return (parsedUrl.protocol === window.location.protocol &&
8076
+ parsedUrl.hostname === window.location.hostname &&
8077
+ parsedUrl.port === window.location.port);
8078
+ }
8079
+ catch (error) {
8080
+ return false;
8081
+ }
8082
+ }
8083
+ function urlFromScript(script) {
8084
+ let blob;
8085
+ try {
8086
+ blob = new Blob([script], {
8087
+ type: 'application/javascript'
8088
+ });
8089
+ }
8090
+ catch (e) {
8091
+ const BlobBuilder =
8092
+ // @ts-ignore
8093
+ window.BlobBuilder ||
8094
+ // @ts-ignore
8095
+ window.WebKitBlobBuilder ||
8096
+ // @ts-ignore
8097
+ window.MozBlobBuilder ||
8098
+ // @ts-ignore
8099
+ window.MSBlobBuilder;
8100
+ const blobBuilder = new BlobBuilder();
8101
+ blobBuilder.append(script);
8102
+ blob = blobBuilder.getBlob('application/javascript');
8103
+ }
8104
+ const URL = window.URL || window.webkitURL;
8105
+ return URL.createObjectURL(blob);
8106
+ }
8107
+ // @ts-ignore
8108
+ const WorkerProxy = new Proxy(originalWorker, {
8109
+ construct(Target, args) {
8110
+ const [scriptURL, options] = args;
8111
+ if (!isSameOrigin(scriptURL)) {
8112
+ // 如果 scriptURL 是跨域的,使用 Blob URL 加载并执行 worker
8113
+ const script = `import "${scriptURL}";`;
8114
+ const workerPath = urlFromScript(script);
8115
+ options.type = 'module';
8116
+ return new Target(workerPath, options);
8117
+ }
8118
+ else {
8119
+ // 如果 scriptURL 是同源的,直接使用原生的 Worker 构造函数
8120
+ return new Target(scriptURL, options);
8121
+ }
8122
+ },
8123
+ });
8124
+ // @ts-ignore
8125
+ window.Worker = WorkerProxy;
8126
+
8030
8127
  const globalEnv = {
8031
8128
  // active sandbox count
8032
8129
  activeSandbox: 0,