Monkeypatch a React app using WebPack?



  • Is it possible? The modules are neatly organized in the Chrome debugger, but I can't figure out how to get at them from the window namespace so I could monkeypatch them.

    I'm executing JS injected onto the page from a Chrome extension, if it matters.

    Also if there's some alternative way to snoop AJAX calls (without using the debugger classes!) that could work too.



  • I guess you can try using the same global hook interface that react dev tools uses to get its data. Something like this:

        <script type="text/javascript">
          window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
            supportsFiber: true,
            inject: function(react) {
              console.log('inject', react);
            },
            onCommitFiberRoot: function (rendererID, root) {
              console.log('this is an initialized react app', root);
            },
            onCommitFiberUnmount: function (rendererID, fiber) {
              console.log('unmount', arguments);
            },
          };
        </script>
    

    Not sure what to do afterwards. You'll probably have to look into react-devtools source code to see how they are reading that component tree and extracting data.

    If you only need ajax sniffing, can't you just shim the global ajax methods directly, regardless of react? Eg. replace window.XMLHttpRequest with your own object and window.fetch with your own function.



  • @cartman82 said in Monkeypatch a React app using WebPack?:

    If you only need ajax sniffing, can't you just shim the global ajax methods directly, regardless of react? Eg. replace window.XMLHttpRequest with your own object and window.fetch with your own function.

    I might end up having to do that, it's kind of the nuclear option. I really just want only one bit of data, and I know exactly where the function that gets it is in the webpack, via the Chrome debugger which lays it all out-- I just don't know how to get to it from window.



  • I hooked XMLHttpRequest and... guess what? The function I need to grab the data from doesn't use it.

    How? You ask? Good question. I have no idea. Maybe it creates a FORM on the page and POSTs to it?



  • @blakeyrat Websockets?



  • @boomzilla Possibly? I noticed the SignalR library is on the page.

    But the requests I'm making show up in the network inspector like normal-- pretty sure WebSockets requests do not.

    Anybody know of a way to hook into SignalR?

    I'm trying to debug through this but React callstacks are literally 200+ levels deep and it's impossible to make heads or tails out of anything.





  • @blakeyrat OK so it's a native code API that returns a Promise...

    How the fuck do you monkeypatch this!?



  • @blakeyrat

    Something like this should do the trick:

    var nativeFetch = window.fetch;
    
    window.fetch = function(url, data) {
        console.log("about to fetch: " + url);
        return new Promise(function(resolve, reject) {
            nativeFetch(url, data).then(function(resp) {
                console.log("fetch successful!", resp);
                resolve(resp);
            });
        });
    }
    
    

    This is just code from the top of my head, I haven't tested itI just tested this in Chrome and it worked.



  • @alexmedia said in Monkeypatch a React app using WebPack?:

    var nativeFetch = window.fetch;

    window.fetch = function(url, data) {
    console.log("about to fetch: " + url);
    return new Promise(function(resolve, reject) {
    nativeFetch(url, data).then(function(resp) {
    console.log("fetch successful!", resp);
    resolve(resp);
    });
    });
    }

    If this works I will kiss you.



  • @blakeyrat Ok one question: the body's a "readableStream"-- if my monkeypatch reads it, can the page's code also read it?



  • @blakeyrat The answer: no.

    Paused on promise rejection
    TypeError: Already read

    (How the fuck is that a type error?)



  • @blakeyrat said in Monkeypatch a React app using WebPack?:

    @blakeyrat The answer: no.

    Paused on promise rejection
    TypeError: Already read

    If you clone the stream before reading from it, it should work:

    var nativeFetch = window.fetch;
    
    window.fetch = function(url, data) {
        console.log("about to fetch: " + url);
        return new Promise(function(resolve, reject) {
            nativeFetch(url, data).then(function(resp) {
                var clonedStream = resp.clone();
                clonedStream.text().then(function(txt) { console.log(txt); });
                
                resolve(resp);
            });
        });
    }
    

    (It took me some fiddling to get this working)

    (How the fuck is that a type error?)

    ¯\_(ツ)_/¯



  • @alexmedia said in Monkeypatch a React app using WebPack?:

    var clonedStream = resp.clone();

    You are my hero, that works. I owe you 1 (one) kiss.



  • @blakeyrat Happy to help! :)


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.