patch-browser.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. Stencil Client Patch Browser v2.18.1 | MIT Licensed | https://stenciljs.com
  3. */
  4. import { BUILD, NAMESPACE } from '@stencil/core/internal/app-data';
  5. import { consoleDevInfo, plt, win, doc, promiseResolve, H } from '@stencil/core';
  6. const getDynamicImportFunction = (namespace) => `__sc_import_${namespace.replace(/\s|-/g, '_')}`;
  7. const patchBrowser = () => {
  8. // NOTE!! This fn cannot use async/await!
  9. if (BUILD.isDev && !BUILD.isTesting) {
  10. consoleDevInfo('Running in development mode.');
  11. }
  12. if (BUILD.cssVarShim) {
  13. // shim css vars
  14. plt.$cssShim$ = win.__cssshim;
  15. }
  16. if (BUILD.cloneNodeFix) {
  17. // opted-in to polyfill cloneNode() for slot polyfilled components
  18. patchCloneNodeFix(H.prototype);
  19. }
  20. if (BUILD.profile && !performance.mark) {
  21. // not all browsers support performance.mark/measure (Safari 10)
  22. // because the mark/measure APIs are designed to write entries to a buffer in the browser that does not exist,
  23. // simply stub the implementations out.
  24. // TODO(STENCIL-323): Remove this patch when support for older browsers is removed (breaking)
  25. // @ts-ignore
  26. performance.mark = performance.measure = () => {
  27. /*noop*/
  28. };
  29. performance.getEntriesByName = () => [];
  30. }
  31. // @ts-ignore
  32. const scriptElm = BUILD.scriptDataOpts || BUILD.safari10 || BUILD.dynamicImportShim
  33. ? Array.from(doc.querySelectorAll('script')).find((s) => new RegExp(`\/${NAMESPACE}(\\.esm)?\\.js($|\\?|#)`).test(s.src) ||
  34. s.getAttribute('data-stencil-namespace') === NAMESPACE)
  35. : null;
  36. const importMeta = import.meta.url;
  37. const opts = BUILD.scriptDataOpts ? scriptElm['data-opts'] || {} : {};
  38. if (BUILD.safari10 && 'onbeforeload' in scriptElm && !history.scrollRestoration /* IS_ESM_BUILD */) {
  39. // Safari < v11 support: This IF is true if it's Safari below v11.
  40. // This fn cannot use async/await since Safari didn't support it until v11,
  41. // however, Safari 10 did support modules. Safari 10 also didn't support "nomodule",
  42. // so both the ESM file and nomodule file would get downloaded. Only Safari
  43. // has 'onbeforeload' in the script, and "history.scrollRestoration" was added
  44. // to Safari in v11. Return a noop then() so the async/await ESM code doesn't continue.
  45. // IS_ESM_BUILD is replaced at build time so this check doesn't happen in systemjs builds.
  46. return {
  47. then() {
  48. /* promise noop */
  49. },
  50. };
  51. }
  52. if (!BUILD.safari10 && importMeta !== '') {
  53. opts.resourcesUrl = new URL('.', importMeta).href;
  54. }
  55. else if (BUILD.dynamicImportShim || BUILD.safari10) {
  56. opts.resourcesUrl = new URL('.', new URL(scriptElm.getAttribute('data-resources-url') || scriptElm.src, win.location.href)).href;
  57. if (BUILD.dynamicImportShim) {
  58. patchDynamicImport(opts.resourcesUrl, scriptElm);
  59. }
  60. if (BUILD.dynamicImportShim && !win.customElements) {
  61. // module support, but no custom elements support (Old Edge)
  62. // @ts-ignore
  63. return import(/* webpackChunkName: "polyfills-dom" */ './dom.js').then(() => opts);
  64. }
  65. }
  66. return promiseResolve(opts);
  67. };
  68. const patchDynamicImport = (base, orgScriptElm) => {
  69. const importFunctionName = getDynamicImportFunction(NAMESPACE);
  70. try {
  71. // test if this browser supports dynamic imports
  72. // There is a caching issue in V8, that breaks using import() in Function
  73. // By generating a random string, we can workaround it
  74. // Check https://bugs.chromium.org/p/chromium/issues/detail?id=990810 for more info
  75. win[importFunctionName] = new Function('w', `return import(w);//${Math.random()}`);
  76. }
  77. catch (e) {
  78. // this shim is specifically for browsers that do support "esm" imports
  79. // however, they do NOT support "dynamic" imports
  80. // basically this code is for old Edge, v18 and below
  81. const moduleMap = new Map();
  82. win[importFunctionName] = (src) => {
  83. const url = new URL(src, base).href;
  84. let mod = moduleMap.get(url);
  85. if (!mod) {
  86. const script = doc.createElement('script');
  87. script.type = 'module';
  88. script.crossOrigin = orgScriptElm.crossOrigin;
  89. script.src = URL.createObjectURL(new Blob([`import * as m from '${url}'; window.${importFunctionName}.m = m;`], {
  90. type: 'application/javascript',
  91. }));
  92. mod = new Promise((resolve) => {
  93. script.onload = () => {
  94. resolve(win[importFunctionName].m);
  95. script.remove();
  96. };
  97. });
  98. moduleMap.set(url, mod);
  99. doc.head.appendChild(script);
  100. }
  101. return mod;
  102. };
  103. }
  104. };
  105. const patchCloneNodeFix = (HTMLElementPrototype) => {
  106. const nativeCloneNodeFn = HTMLElementPrototype.cloneNode;
  107. HTMLElementPrototype.cloneNode = function (deep) {
  108. if (this.nodeName === 'TEMPLATE') {
  109. return nativeCloneNodeFn.call(this, deep);
  110. }
  111. const clonedNode = nativeCloneNodeFn.call(this, false);
  112. const srcChildNodes = this.childNodes;
  113. if (deep) {
  114. for (let i = 0; i < srcChildNodes.length; i++) {
  115. // Node.ATTRIBUTE_NODE === 2, and checking because IE11
  116. if (srcChildNodes[i].nodeType !== 2) {
  117. clonedNode.appendChild(srcChildNodes[i].cloneNode(true));
  118. }
  119. }
  120. }
  121. return clonedNode;
  122. };
  123. };
  124. export { patchBrowser };