1. /* global chrome */
    
  2. 
    
  3. import {__DEBUG__} from 'react-devtools-shared/src/constants';
    
  4. 
    
  5. let debugIDCounter = 0;
    
  6. 
    
  7. const debugLog = (...args) => {
    
  8.   if (__DEBUG__) {
    
  9.     console.log(...args);
    
  10.   }
    
  11. };
    
  12. 
    
  13. const fetchFromNetworkCache = (url, resolve, reject) => {
    
  14.   // Debug ID allows us to avoid re-logging (potentially long) URL strings below,
    
  15.   // while also still associating (potentially) interleaved logs with the original request.
    
  16.   let debugID = null;
    
  17. 
    
  18.   if (__DEBUG__) {
    
  19.     debugID = debugIDCounter++;
    
  20.     debugLog(`[main] fetchFromNetworkCache(${debugID})`, url);
    
  21.   }
    
  22. 
    
  23.   chrome.devtools.network.getHAR(harLog => {
    
  24.     for (let i = 0; i < harLog.entries.length; i++) {
    
  25.       const entry = harLog.entries[i];
    
  26.       if (url !== entry.request.url) {
    
  27.         continue;
    
  28.       }
    
  29. 
    
  30.       debugLog(
    
  31.         `[main] fetchFromNetworkCache(${debugID}) Found matching URL in HAR`,
    
  32.         url,
    
  33.       );
    
  34. 
    
  35.       if (entry.getContent != null) {
    
  36.         entry.getContent(content => {
    
  37.           if (content) {
    
  38.             debugLog(
    
  39.               `[main] fetchFromNetworkCache(${debugID}) Content retrieved`,
    
  40.             );
    
  41. 
    
  42.             resolve(content);
    
  43.           } else {
    
  44.             debugLog(
    
  45.               `[main] fetchFromNetworkCache(${debugID}) Invalid content returned by getContent()`,
    
  46.               content,
    
  47.             );
    
  48. 
    
  49.             // Edge case where getContent() returned null; fall back to fetch.
    
  50.             fetchFromPage(url, resolve, reject);
    
  51.           }
    
  52.         });
    
  53.       } else {
    
  54.         const content = entry.response.content.text;
    
  55. 
    
  56.         if (content != null) {
    
  57.           debugLog(
    
  58.             `[main] fetchFromNetworkCache(${debugID}) Content retrieved`,
    
  59.           );
    
  60.           resolve(content);
    
  61.         } else {
    
  62.           debugLog(
    
  63.             `[main] fetchFromNetworkCache(${debugID}) Invalid content returned from entry.response.content`,
    
  64.             content,
    
  65.           );
    
  66.           fetchFromPage(url, resolve, reject);
    
  67.         }
    
  68.       }
    
  69.     }
    
  70. 
    
  71.     debugLog(
    
  72.       `[main] fetchFromNetworkCache(${debugID}) No cached request found in getHAR()`,
    
  73.     );
    
  74. 
    
  75.     // No matching URL found; fall back to fetch.
    
  76.     fetchFromPage(url, resolve, reject);
    
  77.   });
    
  78. };
    
  79. 
    
  80. const fetchFromPage = async (url, resolve, reject) => {
    
  81.   debugLog('[main] fetchFromPage()', url);
    
  82. 
    
  83.   function onPortMessage({payload, source}) {
    
  84.     if (source === 'react-devtools-background') {
    
  85.       switch (payload?.type) {
    
  86.         case 'fetch-file-with-cache-complete':
    
  87.           chrome.runtime.onMessage.removeListener(onPortMessage);
    
  88.           resolve(payload.value);
    
  89.           break;
    
  90.         case 'fetch-file-with-cache-error':
    
  91.           chrome.runtime.onMessage.removeListener(onPortMessage);
    
  92.           reject(payload.value);
    
  93.           break;
    
  94.       }
    
  95.     }
    
  96.   }
    
  97. 
    
  98.   chrome.runtime.onMessage.addListener(onPortMessage);
    
  99. 
    
  100.   chrome.runtime.sendMessage({
    
  101.     source: 'devtools-page',
    
  102.     payload: {
    
  103.       type: 'fetch-file-with-cache',
    
  104.       tabId: chrome.devtools.inspectedWindow.tabId,
    
  105.       url,
    
  106.     },
    
  107.   });
    
  108. };
    
  109. 
    
  110. // Fetching files from the extension won't make use of the network cache
    
  111. // for resources that have already been loaded by the page.
    
  112. // This helper function allows the extension to request files to be fetched
    
  113. // by the content script (running in the page) to increase the likelihood of a cache hit.
    
  114. const fetchFileWithCaching = url => {
    
  115.   return new Promise((resolve, reject) => {
    
  116.     // Try fetching from the Network cache first.
    
  117.     // If DevTools was opened after the page started loading, we may have missed some requests.
    
  118.     // So fall back to a fetch() from the page and hope we get a cached response that way.
    
  119.     fetchFromNetworkCache(url, resolve, reject);
    
  120.   });
    
  121. };
    
  122. 
    
  123. export default fetchFileWithCaching;