@@ -19,33 +19,13 @@ import {
19
19
localStorageSetItem ,
20
20
} from 'react-devtools-shared/src/storage' ;
21
21
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools' ;
22
+ import { __DEBUG__ } from 'react-devtools-shared/src/constants' ;
22
23
23
24
const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
24
25
'React::DevTools::supportsProfiling' ;
25
26
26
27
const isChrome = getBrowserName ( ) === 'Chrome' ;
27
28
28
- const cachedNetworkEvents = new Map ( ) ;
29
-
30
- // Cache JavaScript resources as the page loads them.
31
- // This helps avoid unnecessary duplicate requests when hook names are parsed.
32
- // Responses with a Vary: 'Origin' might not match future requests.
33
- // This lets us avoid a possible (expensive) cache miss.
34
- // For more info see: github.com/facebook/react/pull/22198
35
- chrome . devtools . network . onRequestFinished . addListener (
36
- function onRequestFinished ( event ) {
37
- if ( event . request . method === 'GET' ) {
38
- switch ( event . response . content . mimeType ) {
39
- case 'application/javascript' :
40
- case 'application/x-javascript' :
41
- case 'text/javascript' :
42
- cachedNetworkEvents . set ( event . request . url , event ) ;
43
- break ;
44
- }
45
- }
46
- } ,
47
- ) ;
48
-
49
29
let panelCreated = false ;
50
30
51
31
// The renderer interface can't read saved component filters directly,
@@ -233,56 +213,113 @@ function createPanelIfReactLoaded() {
233
213
}
234
214
} ;
235
215
216
+ let debugIDCounter = 0 ;
217
+
236
218
// For some reason in Firefox, chrome.runtime.sendMessage() from a content script
237
219
// never reaches the chrome.runtime.onMessage event listener.
238
220
let fetchFileWithCaching = null ;
239
221
if ( isChrome ) {
240
- // Fetching files from the extension won't make use of the network cache
241
- // for resources that have already been loaded by the page.
242
- // This helper function allows the extension to request files to be fetched
243
- // by the content script (running in the page) to increase the likelihood of a cache hit.
244
- fetchFileWithCaching = url => {
245
- const event = cachedNetworkEvents . get ( url ) ;
246
- if ( event != null ) {
247
- // If this resource has already been cached locally,
248
- // skip the network queue (which might not be a cache hit anyway)
249
- // and just use the cached response.
250
- return new Promise ( resolve => {
251
- event . getContent ( content => resolve ( content ) ) ;
252
- } ) ;
222
+ const fetchFromNetworkCache = ( url , resolve , reject ) => {
223
+ // Debug ID allows us to avoid re-logging (potentially long) URL strings below,
224
+ // while also still associating (potentially) interleaved logs with the original request.
225
+ let debugID = null ;
226
+
227
+ if ( __DEBUG__ ) {
228
+ debugID = debugIDCounter ++ ;
229
+ console . log ( `[main] fetchFromNetworkCache(${ debugID } )` , url ) ;
253
230
}
254
231
255
- // If DevTools was opened after the page started loading,
256
- // we may have missed some requests.
257
- // So fall back to a fetch() and hope we get a cached response.
258
-
259
- return new Promise ( ( resolve , reject ) => {
260
- function onPortMessage ( { payload, source} ) {
261
- if ( source === 'react-devtools-content-script' ) {
262
- switch ( payload ?. type ) {
263
- case 'fetch-file-with-cache-complete' :
264
- chrome . runtime . onMessage . removeListener ( onPortMessage ) ;
265
- resolve ( payload . value ) ;
266
- break ;
267
- case 'fetch-file-with-cache-error' :
268
- chrome . runtime . onMessage . removeListener ( onPortMessage ) ;
269
- reject ( payload . value ) ;
270
- break ;
232
+ chrome . devtools . network . getHAR ( harLog => {
233
+ for ( let i = 0 ; i < harLog . entries . length ; i ++ ) {
234
+ const entry = harLog . entries [ i ] ;
235
+ if ( url === entry . request . url ) {
236
+ if ( __DEBUG__ ) {
237
+ console . log (
238
+ `[main] fetchFromNetworkCache(${ debugID } ) Found matching URL in HAR` ,
239
+ url ,
240
+ ) ;
271
241
}
242
+
243
+ entry . getContent ( content => {
244
+ if ( content ) {
245
+ if ( __DEBUG__ ) {
246
+ console . log (
247
+ `[main] fetchFromNetworkCache(${ debugID } ) Content retrieved` ,
248
+ ) ;
249
+ }
250
+
251
+ resolve ( content ) ;
252
+ } else {
253
+ if ( __DEBUG__ ) {
254
+ console . log (
255
+ `[main] fetchFromNetworkCache(${ debugID } ) Invalid content returned by getContent()` ,
256
+ content ,
257
+ ) ;
258
+ }
259
+
260
+ // Edge case where getContent() returned null; fall back to fetch.
261
+ fetchFromPage ( url , resolve ) ;
262
+ }
263
+ } ) ;
264
+
265
+ return ;
272
266
}
273
267
}
274
268
275
- chrome . runtime . onMessage . addListener ( onPortMessage ) ;
269
+ if ( __DEBUG__ ) {
270
+ console . log (
271
+ `[main] fetchFromNetworkCache(${ debugID } ) No cached request found in getHAR()` ,
272
+ ) ;
273
+ }
276
274
277
- chrome . devtools . inspectedWindow . eval ( `
278
- window.postMessage({
279
- source: 'react-devtools-extension',
280
- payload: {
281
- type: 'fetch-file-with-cache',
282
- url: "${ url } ",
283
- },
284
- });
285
- ` ) ;
275
+ // No matching URL found; fall back to fetch.
276
+ fetchFromPage ( url , resolve ) ;
277
+ } ) ;
278
+ } ;
279
+
280
+ const fetchFromPage = ( url , resolve , reject ) => {
281
+ if ( __DEBUG__ ) {
282
+ console . log ( '[main] fetchFromPage()' , url ) ;
283
+ }
284
+
285
+ function onPortMessage ( { payload, source} ) {
286
+ if ( source === 'react-devtools-content-script' ) {
287
+ switch ( payload ?. type ) {
288
+ case 'fetch-file-with-cache-complete' :
289
+ chrome . runtime . onMessage . removeListener ( onPortMessage ) ;
290
+ resolve ( payload . value ) ;
291
+ break ;
292
+ case 'fetch-file-with-cache-error' :
293
+ chrome . runtime . onMessage . removeListener ( onPortMessage ) ;
294
+ reject ( payload . value ) ;
295
+ break ;
296
+ }
297
+ }
298
+ }
299
+
300
+ chrome . runtime . onMessage . addListener ( onPortMessage ) ;
301
+
302
+ chrome . devtools . inspectedWindow . eval ( `
303
+ window.postMessage({
304
+ source: 'react-devtools-extension',
305
+ payload: {
306
+ type: 'fetch-file-with-cache',
307
+ url: "${ url } ",
308
+ },
309
+ });
310
+ ` ) ;
311
+ } ;
312
+
313
+ // Fetching files from the extension won't make use of the network cache
314
+ // for resources that have already been loaded by the page.
315
+ // This helper function allows the extension to request files to be fetched
316
+ // by the content script (running in the page) to increase the likelihood of a cache hit.
317
+ fetchFileWithCaching = url => {
318
+ return new Promise ( ( resolve , reject ) => {
319
+ // Try fetching from the Network cache first.
320
+ // If DevTools was opened after the page started loading, we may have missed some requests.
321
+ // So fall back to a fetch() from the page and hope we get a cached response that way.
322
+ fetchFromNetworkCache ( url , resolve , reject ) ;
286
323
} ) ;
287
324
} ;
288
325
}
@@ -441,9 +478,6 @@ function createPanelIfReactLoaded() {
441
478
442
479
// Re-initialize DevTools panel when a new page is loaded.
443
480
chrome . devtools . network . onNavigated . addListener ( function onNavigated ( ) {
444
- // Clear cached requests when a new page is opened.
445
- cachedNetworkEvents . clear ( ) ;
446
-
447
481
// Re-initialize saved filters on navigation,
448
482
// since global values stored on window get reset in this case.
449
483
syncSavedPreferences ( ) ;
@@ -460,8 +494,7 @@ function createPanelIfReactLoaded() {
460
494
461
495
// Load (or reload) the DevTools extension when the user navigates to a new page.
462
496
function checkPageForReact ( ) {
463
- // Clear cached requests when a new page is opened.
464
- cachedNetworkEvents . clear ( ) ;
497
+ cachedNetworkRequests . clear ( ) ;
465
498
466
499
syncSavedPreferences ( ) ;
467
500
createPanelIfReactLoaded ( ) ;
@@ -472,7 +505,25 @@ chrome.devtools.network.onNavigated.addListener(checkPageForReact);
472
505
// Check to see if React has loaded once per second in case React is added
473
506
// after page load
474
507
const loadCheckInterval = setInterval ( function ( ) {
508
+ cachedNetworkRequests . clear ( ) ;
509
+
475
510
createPanelIfReactLoaded ( ) ;
476
511
} , 1000 ) ;
477
512
478
513
createPanelIfReactLoaded ( ) ;
514
+
515
+ const cachedNetworkRequests = new Map ( ) ;
516
+
517
+ chrome . devtools . network . onRequestFinished . addListener (
518
+ function onRequestFinished ( request ) {
519
+ if ( request . request . method === 'GET' ) {
520
+ switch ( request . response . content . mimeType ) {
521
+ case 'application/javascript' :
522
+ case 'application/x-javascript' :
523
+ case 'text/javascript' :
524
+ cachedNetworkRequests . set ( request . request . url , request ) ;
525
+ break ;
526
+ }
527
+ }
528
+ } ,
529
+ ) ;
0 commit comments