1. /** @flow */
    
  2. 
    
  3. import {createElement} from 'react';
    
  4. import {createRoot} from 'react-dom/client';
    
  5. import {
    
  6.   activate as activateBackend,
    
  7.   initialize as initializeBackend,
    
  8. } from 'react-devtools-inline/backend';
    
  9. import {initialize as initializeFrontend} from 'react-devtools-inline/frontend';
    
  10. import {initDevTools} from 'react-devtools-shared/src/devtools';
    
  11. 
    
  12. // This is a pretty gross hack to make the runtime loaded named-hooks-code work.
    
  13. // TODO (Webpack 5) Hoepfully we can remove this once we upgrade to Webpack 5.
    
  14. // $FlowFixMe[cannot-resolve-name]
    
  15. __webpack_public_path__ = '/dist/'; // eslint-disable-line no-undef
    
  16. 
    
  17. const iframe = ((document.getElementById('target'): any): HTMLIFrameElement);
    
  18. 
    
  19. const {contentDocument, contentWindow} = iframe;
    
  20. 
    
  21. // Helps with positioning Overlay UI.
    
  22. contentWindow.__REACT_DEVTOOLS_TARGET_WINDOW__ = window;
    
  23. 
    
  24. initializeBackend(contentWindow);
    
  25. 
    
  26. // Initialize the front end and activate the backend early so that we are able
    
  27. // to pass console settings in local storage to the backend before initial render
    
  28. const DevTools = initializeFrontend(contentWindow);
    
  29. 
    
  30. // Activate the backend only once the DevTools frontend Store has been initialized.
    
  31. // Otherwise the Store may miss important initial tree op codes.
    
  32. activateBackend(contentWindow);
    
  33. 
    
  34. const container = ((document.getElementById('devtools'): any): HTMLElement);
    
  35. 
    
  36. let isTestAppMounted = true;
    
  37. 
    
  38. const mountButton = ((document.getElementById(
    
  39.   'mountButton',
    
  40. ): any): HTMLButtonElement);
    
  41. mountButton.addEventListener('click', function () {
    
  42.   if (isTestAppMounted) {
    
  43.     if (typeof window.unmountTestApp === 'function') {
    
  44.       window.unmountTestApp();
    
  45.       mountButton.innerText = 'Mount test app';
    
  46.       isTestAppMounted = false;
    
  47.     }
    
  48.   } else {
    
  49.     if (typeof window.mountTestApp === 'function') {
    
  50.       window.mountTestApp();
    
  51.       mountButton.innerText = 'Unmount test app';
    
  52.       isTestAppMounted = true;
    
  53.     }
    
  54.   }
    
  55. });
    
  56. 
    
  57. // TODO (Webpack 5) Hopefully we can remove this prop after the Webpack 5 migration.
    
  58. function hookNamesModuleLoaderFunction() {
    
  59.   return import('react-devtools-inline/hookNames');
    
  60. }
    
  61. 
    
  62. inject('dist/app-index.js', () => {
    
  63.   initDevTools({
    
  64.     connect(cb) {
    
  65.       const root = createRoot(container);
    
  66.       root.render(
    
  67.         createElement(DevTools, {
    
  68.           browserTheme: 'light',
    
  69.           enabledInspectedElementContextMenu: true,
    
  70.           hookNamesModuleLoaderFunction,
    
  71.           showTabBar: true,
    
  72.           warnIfLegacyBackendDetected: true,
    
  73.           warnIfUnsupportedVersionDetected: true,
    
  74.         }),
    
  75.       );
    
  76.     },
    
  77. 
    
  78.     onReload(reloadFn) {
    
  79.       iframe.onload = reloadFn;
    
  80.     },
    
  81.   });
    
  82. });
    
  83. 
    
  84. function inject(sourcePath: string, callback: () => void) {
    
  85.   const script = contentDocument.createElement('script');
    
  86.   script.onload = callback;
    
  87.   script.src = sourcePath;
    
  88. 
    
  89.   ((contentDocument.body: any): HTMLBodyElement).appendChild(script);
    
  90. }