Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save OnurGvnc/31f03f0d5237b78224aa083493fda645 to your computer and use it in GitHub Desktop.
Save OnurGvnc/31f03f0d5237b78224aa083493fda645 to your computer and use it in GitHub Desktop.
removes injected HTML codes from browser extensions for react hydration
import { RemixBrowser } from '@remix-run/react'
import { startTransition, StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
function clearBrowserExtensionInjectionsBeforeHydration() {
document
.querySelectorAll(
[
'html > *:not(body, head)',
'script[src*="extension://"]',
'link[href*="extension://"]',
].join(', ')
)
.forEach((s) => {
s.parentNode?.removeChild(s)
})
const $targets = {
html: {
$elm: document.querySelector('html')!,
allowedAttributes: ['lang', 'dir', 'class'],
},
head: {
$elm: document.querySelector('head')!,
allowedAttributes: [''],
},
body: {
$elm: document.querySelector('body')!,
allowedAttributes: ['class'],
},
}
Object.entries($targets).forEach(([targetName, target]) => {
target.$elm.getAttributeNames().forEach((attr) => {
if (!target.allowedAttributes.includes(attr)) {
target.$elm.removeAttribute(attr)
}
})
})
}
function hydrate() {
clearBrowserExtensionInjectionsBeforeHydration()
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
)
})
}
if (window.requestIdleCallback) {
window.requestIdleCallback(hydrate)
} else {
// Safari doesn't support requestIdleCallback
// https://caniuse.com/requestidlecallback
window.setTimeout(hydrate, 1)
}
@OnurGvnc
Copy link
Author

OnurGvnc commented Mar 23, 2024

remix-run/remix#4822 (comment)

<script
  dangerouslySetInnerHTML={{
    __html: `
      const observerConfig = {
        childList: true,
        subtree: true,
        attributes: true,
        attributeOldValue: true,
        characterData: true,
        characterDataOldValue: true,
      };
      window.hydration_observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          switch (mutation.type) {
            case 'childList': {
              window.hydration_observer.disconnect();
              mutation.addedNodes.forEach((node) => {
                try {
                mutation.target.removeChild(node);
                } catch (e) {
                  console.error(e);
                }
              });
              window.hydration_observer.observe(document, observerConfig);
              break;
            }
            case 'attributes': {
              mutation.target.removeAttribute(mutation.attributeName);
              break;
            }
          }
        });
        
      });
      window.addEventListener('DOMContentLoaded', () => {
        window.hydration_observer.observe(document, observerConfig);
      });
    `,
  }}
/>
hydrateRoot(
  document,
  <Provider>
    </StrictMode>
  </Provider>,
);
window.hydration_observer.disconnect();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment