rsc-parser icon indicating copy to clipboard operation
rsc-parser copied to clipboard

Explore turning on recording mode as soon as dev tools panel is shown

Open alvarlagerlof opened this issue 2 years ago • 4 comments
trafficstars

Problem

#195 added some safety to reduce the risk that the extension blows up any page (by patching fetch potentially incorrectly), but does so by adding a recording mode. You have to press it after loading your page to start seeing RSC chunk data coming in. This makes it hard to see prefetching responses.

Proposed solution

The extension could start recording automatically as soon as it is shown to the user. See https://twitter.com/nickemccurdy/status/1690111061142155264

alvarlagerlof avatar Aug 13 '23 17:08 alvarlagerlof

I just came here to raise a similar issue; but I was wondering if it would make sense to have a similar mode as the Chrome DevTools 'Performance' tab, where it has a 'reload and start recording' button.

image

  • https://developer.chrome.com/docs/devtools/performance/reference#record-load

I haven't looked at the current method of patching fetch too deeply; but I also wonder if there are better 'higher level' extension API's that can be used, rather than monkeypatching fetch?

From memory, I believe it's not possible to get the response body with chrome.webRequest, but I think it might be possible via chrome.debugger.

I haven't deeply validated this, but here's what ChatGPT suggested for it:

chrome.debugger example

Capturing the response body directly with the chrome.webRequest API in a Chrome extension is not straightforward, as the API does not provide direct access to the body of HTTP responses. However, you can achieve this using the chrome.debugger API, which allows you to attach to the browser's debugging protocol and capture network traffic, including response bodies.

Here’s how you can set up a Chrome extension to capture the response body using the chrome.debugger API:

  1. Manifest file (manifest.json): Ensure your manifest file includes the necessary permissions and declares the background service worker:

    {
      "manifest_version": 3,
      "name": "Response Body Capturer",
      "version": "1.0",
      "permissions": [
        "debugger",
        "activeTab"
      ],
      "background": {
        "service_worker": "background.js"
      },
      "action": {
        "default_popup": "popup.html"
      }
    }
    
  2. Popup HTML (popup.html): Create a simple popup to start capturing:

    <!DOCTYPE html>
    <html>
    <head>
      <title>Start Capture</title>
    </head>
    <body>
      <button id="startCapture">Start Capture</button>
      <script src="popup.js"></script>
    </body>
    </html>
    
  3. Popup Script (popup.js): Add a script to handle the button click and start the debugger:

    document.getElementById('startCapture').addEventListener('click', function() {
      chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
        chrome.debugger.attach({ tabId: tabs[0].id }, '1.3', function() {
          chrome.debugger.sendCommand({ tabId: tabs[0].id }, 'Network.enable');
          chrome.debugger.onEvent.addListener(function(debuggeeId, message, params) {
            if (message === 'Network.responseReceived') {
              chrome.debugger.sendCommand(
                { tabId: tabs[0].id },
                'Network.getResponseBody',
                { requestId: params.requestId },
                function(response) {
                  console.log('Response body:', response.body);
                }
              );
            }
          });
        });
      });
    });
    
  4. Background Script (background.js): No changes needed in the background script for this example.

  5. Loading the extension:

    • Go to chrome://extensions/.
    • Enable "Developer mode".
    • Click "Load unpacked" and select the directory containing your manifest.json, popup.html, and popup.js files.

With this setup, the extension will attach to the browser's debugger protocol when you click the "Start Capture" button in the popup. It will then listen for network responses and capture the response bodies.

Important Notes:

  • Using the chrome.debugger API requires user interaction (e.g., clicking a button in the popup) to start the debugger.
  • The chrome.debugger API has powerful capabilities and should be used carefully, as it can interfere with normal browser operations.
  • Ensure you comply with Chrome Web Store policies and user privacy considerations when capturing network traffic.

There's also chrome.devtools.network, which might be useful?

  • onRequestFinished https://developer.chrome.com/docs/extensions/reference/api/devtools/network#event-onRequestFinished
    • Fired when a network request is finished and all request data are available.

  • Request: https://developer.chrome.com/docs/extensions/reference/api/devtools/network#type-Request
    • Represents a network request for a document resource (script, image and so on).

    • getContent: Returns content of the response body.

There might be other useful Chrome extension API's as well, it's been a while since I looked deeply through them.


As a workaround in the meantime, you could try setting a breakpoint in the 'Sources' tab -> Event listener breakpoints -> DOM mutation -> DOMContentLoaded:

  • https://stackoverflow.com/questions/6727370/using-chrome-javascript-debugger-how-to-break-on-page-loading-events/13372025#13372025

Then while the code is paused, click the 'record' button in RSC DevTools, and then unpause the code again.

0xdevalias avatar May 23 '24 05:05 0xdevalias

Copying the behaviour of the Chrome DevTools seems like a good idea UX wise. I like it.

Using chrome.webRequest does not let you get a streaming response. Only the full response, so it's not as featured. I wanted to use that originally, but hit a wall. I believe that the equivalent API does have support for streaming in Firefox. The chrome.devtools.network has the same problem.

The debugger example looks to have the same problem. While I don't understand what Network.getResponseBody' is referring to, it does not seem to be a stream either.

Really the main thing that needs to keep working is streaming support.

alvarlagerlof avatar May 23 '24 08:05 alvarlagerlof

While I don't understand what Network.getResponseBody' is referring to, it does not seem to be a stream either.

I believe it's referring to the chrome devtools protocol:

  • https://chromedevtools.github.io/devtools-protocol/

Specifically:

  • https://chromedevtools.github.io/devtools-protocol/1-3/Network/
    • Network Domain Network domain allows tracking network activities of the page. It exposes information about http, file, data and other requests and responses, their headers, bodies, timing, etc.

Not sure which part emits this; but the description on it certainly reads in a potentially stream friendly way:

  • https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-dataReceived
    • Network.dataReceived Fired when data chunk was received over the network.

  • https://chromedevtools.github.io/devtools-protocol/1-3/Network/#event-responseReceived
    • Network.responseReceived Fired when HTTP response is available.

It might just be part of this:

  • https://chromedevtools.github.io/devtools-protocol/1-3/Network/#method-enable
    • Network.enable Enables network tracking, network events will now be delivered to the client.

And even the description of response on this says 'bytes received so far':

  • https://chromedevtools.github.io/devtools-protocol/1-3/Network/#type-Response
    • encodedDataLength number Total number of bytes received for this request so far.

So sounds like there may be some bits worth PoC'ing with/exploring in there at the very least.

0xdevalias avatar May 23 '24 08:05 0xdevalias

Huh, yeah that seems like it might just work.

alvarlagerlof avatar May 23 '24 15:05 alvarlagerlof