[HN Gopher] Debugging tricks in the browser
       ___________________________________________________________________
        
       Debugging tricks in the browser
        
       Author : bkudria
       Score  : 541 points
       Date   : 2023-11-11 01:35 UTC (21 hours ago)
        
 (HTM) web link (alan.norbauer.com)
 (TXT) w3m dump (alan.norbauer.com)
        
       | temporallobe wrote:
       | None of these are weird or something the browser is trying to
       | hide from you, just things that an experienced front-end
       | developer would probably know, although I was not aware of the
       | monitor() command.
       | 
       | That being said, I am pleasantly surprised at the debugging and
       | development tooling that is built right into most modern
       | browsers. It really does make the UI development experience very
       | powerful. I wish more back-end languages had this experience.
        
         | ethbr1 wrote:
         | It's a joke title.
        
         | chii wrote:
         | > I wish more back-end languages had this experience.
         | 
         | the jvm debugging experience is pretty good imho.
         | 
         | It's the compiled languages that have a poor experience with
         | debugging - try injecting code to execute in a c debugger! It's
         | hard as hell to do!
        
           | bpye wrote:
           | You know the tooling leaves something to be desired when
           | editing instruction bytes is the best option to NOP out an
           | assert - for example.
        
             | saagarjha wrote:
             | Generally a conditional breakpoint is good enough to do
             | this (though perhaps not very fast).
        
           | jeroenhd wrote:
           | > try injecting code to execute in a c debugger! It's hard as
           | hell to do!
           | 
           | I mean, theoretically, not really? Allocate a page RW, put in
           | some compiled code, remap as R+X, redirect execution there,
           | return code execution to where it was. Jumping through those
           | hoops will be more expensive when you use the debugger like
           | that (you'd need to hot patch some kind of jump statement to
           | circumvent that) but it's not exactly impossible.
           | 
           | Things become difficult when the compiler starts optimizing
           | out code, because the debugger would need to keep track of
           | everything, but I don't see why it'd be technically
           | impossible to do so.
           | 
           | Executing code in a C debugger is basically how modern
           | reverse engineering works, it's a lot harder than in other
           | languages but it's certainly possible.
        
             | saagarjha wrote:
             | Yeah, both GDB and LLDB know how to do this.
        
         | jeroenhd wrote:
         | > I wish more back-end languages had this experience.
         | 
         | I know what that feels like. I have that same feeling about a
         | whole bunch of languages that has been available in .NET for at
         | least 15 years now.
         | 
         | When I got into programming, I moved from VB6 to VB.NET to C#,
         | the latter two using a cracked version of MS Visual Studio I
         | downloaded at school. I only started seriously using the
         | debugger somewhere around the time I taught myself C#.
         | 
         | Because of this, I got used to the idea that in a normal
         | debugger, you could just click and drag back the point of
         | execution, modify the code, and hit resume. The VS time
         | traveling debugger will actually revert variable assignments,
         | recompile the modified code, insert it in its place, and
         | continue execution. This wouldn't work with P/Invoke calls, but
         | it worked great for what I was trying to do. Debugging and
         | fixing mistakes was absolutely trivial.
         | 
         | Imagine my betrayal when I found out that there was nothing
         | like this in C++, or Java, or Javascript. Java has gotten a
         | similar feature, but I've never worked with an IDE that
         | integrated it even close to how well VS 2008 integrated it.
         | 
         | Even today, this seemingly basic feature that I took for
         | granted just isn't available in many modern IDEs. I understand
         | natively compiled languages like C/C++/Rust/Go not supporting
         | the inline code replacement feature, but the hot reload in
         | languages like Kotlin, Java, and Javascript just don't work
         | like it did for me back in 2008.
         | 
         | As for all these tricks: I think most of them are available in
         | most IDEs. Anything involving conditional breakpoints will work
         | regardless of the language you use (although languages like
         | Rust can have some restrictions). Tracing callers should work
         | in any decent debugger. Timing individual functions may require
         | writing out long package names to get to the right methods, but
         | they should be available. The monitor() trick can be replaced
         | by a logging method breakpoint.
         | 
         | How well DOM-related debugging works, will depend on whether or
         | not your GUI framework uses a DOM and how it's constructed. If
         | you're composing a DOM from multiple individual functions (like
         | in React/Flutter/Kotlin Compose) then you can add breakpoints
         | to all the relevant state alterations. If your tooling uses a
         | more C-inspired windowing mechanism, you're probably going to
         | have to get creative.
         | 
         | When you get down into the weeds of it, I think you'll find
         | that more of these features are available for backend languages
         | than you might expect. I would recommend any developer to
         | occasionally read the changelogs of their IDEs (or to grab an
         | IDE if you normally don't use any) and take a few moments to
         | explore the possibilities of modern debuggers.
        
           | kccqzy wrote:
           | I love your description of undoing code execution, modifying
           | the code and continuing. I think too often these days because
           | of the UNIX philosophy of doing one thing well, the debugger
           | and the compiler and even the linker are different projects,
           | making it unnecessarily complicated to combine these tools
           | other than passing blobs of output into another tool's input.
           | We should aim higher.
        
           | seba_dos1 wrote:
           | > Imagine my betrayal when I found out that there was nothing
           | like this in C++, or Java, or Javascript.
           | 
           | For compiled languages (C, C++, Go, Rust etc.), check out
           | https://rr-project.org/
        
             | jeroenhd wrote:
             | This looks rather neat, and there seems to be ample IDE
             | support as well! It looks absolutely perfect, but makes me
             | wonder why this isn't included in VS Code and IntelliJ by
             | default when you install a (supported) language's debugger.
        
           | lenkite wrote:
           | What pre-historic Java IDE were you using ? Intellij has
           | supported time travel debugging in Java for nearly a decade.
           | 
           | https://www.jetbrains.com/help/idea/altering-the-program-
           | s-e...
        
             | jeroenhd wrote:
             | Back then, Eclipse was what every guide and book told me to
             | use, so that was where I started. These days I'm mostly on
             | Jetbrains products. Microsoft made VS a weirdly slow,
             | bloated piece of kit, but I still miss some of the features
             | they have had for ages.
             | 
             | I don't get automatically reloaded classes in IntelliJ,
             | though I think there's a button to manually reload code
             | manually? The whole ease of development came from not
             | having to manually pick what code to reload while
             | debugging. Java also seems to have a bunch of limitations
             | that C# doesn't have (and didn't have back when I tried it
             | on Windows). For example, you can't add a method, or alter
             | the return type of a method.
             | 
             | As for time travel debugging, I'm not sure how you do that
             | in IntelliJ? I can't even see any way to undo the previous
             | line of execution, let alone step through code in two
             | directions. It looks like there are plugins for a bunch of
             | languages, though, but those are all external tools built
             | by third parties.
             | 
             | Rolling back executed code seems to work in Rider, but I
             | don't seem to get any Edit and Continue functionality on
             | Linux, which is probably a Microsoft thing.
             | 
             | It looks like I was mistaken though, "IntelliTrace" was a
             | VS2010 feature, not 2008: https://learn.microsoft.com/en-
             | us/archive/msdn-magazine/2010...
        
         | jmkni wrote:
         | I think the author was just having a bit of fun with the title
        
       | adamnemecek wrote:
       | `queryObjects` is notably missing. It is a crazy API which
       | returns a list of all objects created by a particular
       | constructor. One can for example get a list of all functions on
       | the heap by doing `queryObjects(Function)`.
       | 
       | This will return even functions contained in some module that are
       | "private".
        
         | chrismorgan wrote:
         | To be honest, this might be one they'd be _justified_ in not
         | wanting you to know. Crazy indeed. Chromium-only, I presume.
        
           | adamnemecek wrote:
           | Haha, I agree.
           | 
           | They do seem to have some strange restrictions on this. E.g.
           | When you evaluate it the function returns undefined but it
           | also outputs the array underneath. You can right click and
           | save it to variable.
           | 
           | I think the point of this so that you cannot assign the
           | output programmatically, there has to be a person who saves
           | it to a variable by right clicking.
        
             | chrismorgan wrote:
             | I think it'll be because for architectural reasons it can't
             | return a value synchronously, combined with historical
             | ergonomic reasons. I don't know when it was introduced,
             | it's possible that originally it could be synchronous and
             | only subsequent V8 changes prevented that. Probably it
             | landed before you could use `await` in the console, and
             | they decided that made the ergonomics of Promising it too
             | bad for the typical use case (though _now_ you could write
             | `await queryObjects(Function)` if it worked that way). All
             | I _know_ is that the documentation at https://developer.chr
             | ome.com/docs/devtools/console/utilities... says it returns
             | an array of objects, which is patently false.
             | 
             | I can't see any reason for preventing assigning the output
             | programmatically.
        
       | Jerrrry wrote:
       | >>setTimeout(function() { debugger; }, 5000);
       | 
       | This is clever; after all, the only way to beat the recursive
       | turtle stack of chrome debuggers debugging themselves is with the
       | debugger statement.
       | 
       | sam.pl, of the infamous myspace Sammy worm, used debugging
       | gotcha's to prevent visitors from de-mystifying his obfuscated
       | html homepage.
        
         | zubairq wrote:
         | Nice, I never knew this trick existed
        
         | cookiengineer wrote:
         | This is what happens when websites prevent an open
         | Console/DevTools side panel. They basically have a main loop
         | running, inserting a debugger; statement in various places
         | where they're annoying, and they do that at 30FPS / 32ms so
         | that the DevTools become useless because there's no way to
         | "ignore" debugger statements.
        
           | lexicality wrote:
           | Why would this be a problem? I have a debugger. If you
           | conveniently invoke it for me I can simply delete the
           | offending code.
           | 
           | Also both Chrome and Firefox have a "disable breakpoints"
           | button that would instantly defeat this issue.
        
             | themoonisachees wrote:
             | This button was added to specifically combat that, and even
             | then it means you can't use breakpoints at all. IMO the
             | missing link is a way to specifically ignore a single
             | debugger call.
        
               | gear54rus wrote:
               | TFA has instructions on adding conditional breakpoint
               | with 'false' inside. Wouldn't this work?
        
         | 3abiton wrote:
         | Wait, that's it? This is too simple to be so good.
        
         | darekkay wrote:
         | That's one of my most used bookmarklets:
         | https://darekkay.com/blog/debugging-dynamic-content/
        
           | lelandfe wrote:
           | Woah, "Emulate a focused page" is a great tip, too.
        
           | awalGarg wrote:
           | You can just hit F8 and the debugger will pause at the next
           | instruction. Works in both Chrome/FF.
        
             | DustinBrett wrote:
             | Neither the bookmarklet or F8 is ideal if you want to
             | retain focus and any other state that you may effect by
             | going and clicking or pressing a key.
        
             | lelandfe wrote:
             | F8 first causes focus to be lost from the document body.
             | Just tested in Chrome.
        
         | johnfn wrote:
         | Another way to do this, if you don't want to wait 5 seconds, is
         | just to use the "pause script execution" shortcut, which is
         | cmd-\\. It'll freeze the page on whatever line of JS was
         | currently executing, and then you can inspect the problematic
         | element like normal.
        
       | Andrews54757 wrote:
       | I've noticed that a lot of websites will try to prevent you from
       | using the debugger. They use various techniques ranging from
       | calling `debugger` every second to entrapped sourcemaps to make
       | debugger features work against you!
       | 
       | Take a look at disable-devtool [1], it surprises me just how many
       | methods can be used to detect usage of an invaluable tool that
       | should be a user's right to use. These "exploits" should really
       | be patched browser-side, but I don't see any active efforts by
       | browsers to fix this.
       | 
       | I've created a simple anti-anti-debug extension [2] that monkey-
       | patches my way around these anti-debug scripts. It works fine for
       | now, but I can't imagine it working consistently in the long term
       | once the inevitable arms race begins.
       | 
       | How can we get Google, Mozilla, etc... to care about dev tool
       | accessibility?
       | 
       | [1]: https://github.com/theajack/disable-devtool
       | 
       | [2]: https://github.com/Andrews54757/Anti-Anti-Debug
        
         | supriyo-biswas wrote:
         | A simple way to solve this issue is to just deprecate the
         | debugger statement and have people rely on setting up
         | breakpoints manually, or request an explicit opt in into the
         | debugger statement so that random websites don't hijack it.
        
           | Andrews54757 wrote:
           | That would be helpful, but there are also other methods that
           | don't involve using the debugger. For example, one technique
           | involves periodically printing a custom object to the console
           | with a toString getter. This is programmatically called by
           | the browser only when the devtools are opened. This allows
           | the website to know when you've opened devtools and they will
           | redirect/block/crash your browser in response.
        
           | no_time wrote:
           | They don't need to deprecate it. I remember reading a
           | blogpost here that was about bypassing these kinds of checks.
           | They recompiled SpiderMonkey with the debugger() method
           | renamed to something else.
        
         | jeroenhd wrote:
         | I've pondered why websites who are that afraid of reverse
         | engineering don't simply feed the browser mock data or kill a
         | user's session (with a five minute IP block) when the browser
         | requests a source map. Almost all browsers request them by
         | default the moment you open the debugger and normal users very
         | rarely hit the debugger.
         | 
         | Sure, it'd be trivial to circumvent such a block, but it'd
         | easily inconvenience most of the low-hanging fruit enough that
         | things like community maintained ad blockers could become
         | ineffective. Surely simply never serving ads to people who open
         | the dev tools would prevent the 99.9% of normal users from
         | using effective ad blockers in their browsers.
        
           | Andrews54757 wrote:
           | I've seen some websites do this in the wild, it's why I
           | recommend turning the sourcemaps off in the troubleshooting
           | section of my anti-anti-debug tool.
           | 
           | It's pretty easy to circumvent this method, but honestly the
           | user shouldn't have to configure their browsers to be
           | resistant to anti-debugging. From the side of the website, it
           | should be impossible to know if the debug tools are just
           | open.
        
           | iudqnolq wrote:
           | I haven't seen any anti reverse engineering on sites with
           | significant technical expertise. For example Facebook just
           | prints a very reasonable warning. I've seen anti-debugger
           | stuff only on relatively shady and cheap websites. I suspect
           | the issue with your suggestion is it would require replacing
           | static file serving with a smarter backend.
        
         | cxr wrote:
         | Imagine if browser developer tools were reasonably architected
         | so e.g. opening the DOM inspector didn't provide a vector for
         | anti-tamper code targeting the JS debugger to DOS your attempts
         | to poke at the CSS or read network requests. Or get this: for
         | non-hostile content--like something you yourself have written--
         | maybe you could have the debugger and the inspector open in
         | separate windows, or even have multiple object inspectors open
         | on different objects at the same time. Gee. Fuckin' novel idea.
         | Maybe this is something we'll be able to look forward to once
         | the year 2000 rolls around.
        
         | quickthrower2 wrote:
         | The ultimate way is process everything on the server with a
         | sockets to webapi adaptor on the client. Then all you see is
         | commands coming from the server to pull various strings.
        
           | youngtaff wrote:
           | Even then some sites detect the DevTools connection and
           | prevent you from normal (on-site) actions
        
       | quotemstr wrote:
       | Don't any browsers support re-style reverse debugging yet?
        
       | amluto wrote:
       | I'd like to see a way to access local variables of an IIFE,
       | without breaking into code in the IIFE's scope. Is there some way
       | to convince the debugger to do this?
        
         | jeroenhd wrote:
         | If you're entering a breakpoint from a function called by the
         | IIFE, you can just walk up the stack. If you're outside the
         | IIFE entirely, I don't think it's possible The variables you're
         | looking for may not even exist in memory, either before or
         | after execution. Javascript doesn't have static variables like
         | other languages do, so each time the IIFE is called, the
         | variables inside it are thrown out. Javascript is also very
         | much single-threaded (unless you use web workers and such,
         | which come with limited interactivity with their parent pages)
         | so unless you're trying to race-condition yourself with an
         | async/await call, I don't think there's even a way to
         | conceptually have these variables around in memory outside the
         | IIFE scope.
         | 
         | You could (ab)use `var` to initialize the variable outside the
         | IIFE scope so you can see the values produced by the last IIFE
         | call.
        
         | plugin-baby wrote:
         | IIFE: immediately-invoked function expression
         | 
         | https://en.m.wikipedia.org/wiki/Immediately_invoked_function...
        
         | kristopolous wrote:
         | I wrote a tool to do that about 12 years ago. You still need to
         | modify it a bit but you get a big bang for your buck
         | 
         | https://github.com/kristopolous/_inject
         | 
         | You can basically wander around any function context at any
         | arbitrary time and see what happened. It exploits the reference
         | counter to keep the contexts from being destroyed. It was
         | really great back when I did a lot of client side js
         | 
         | The killer app version of this would be to open a repl at any
         | context. As it stands it requires a good bit of competency to
         | do it well.
        
         | Zecc wrote:
         | Are you looking for logpoints?
         | 
         | https://firefox-source-docs.mozilla.org/devtools-user/debugg...
         | 
         | Edit: just realized this is literally the first thing mentioned
         | in the linked article.
        
           | amluto wrote:
           | Not really. Suppose I have access to a closure that was
           | created by the invocation of an IIFE. I would like to access
           | variables that are in scope as seen from inside the closure,
           | and I'd like to do this without executing the closure.
        
         | cantSpellSober wrote:
         | Why use IIFEs in JS now that we have block-scoping with
         | let/const and modules to isolate data? (open question)
        
       | rootsudo wrote:
       | This is something I really need to pick up / is there a dedicated
       | book or study for this or is it just web dev / front end all the
       | way down?
        
         | lancebeet wrote:
         | I can really recommend following the "What's new in DevTools"
         | series by the chrome team. Clicking a link to read release
         | notes when you're in the middle of something may not seem
         | appealing, but spending 5 minutes to skim through it when a new
         | version is released is well worth your time. There are also
         | digestible videos that are just a few minutes long and will
         | give you a brief overview. While their purpose is to show new
         | features, in my experience you will often gain understanding of
         | the current limitations of the tools as well.
        
       | russellbeattie wrote:
       | I can never get watched variables to work. The scoping and
       | updating rules for it are a mystery to me. I assume only global
       | variables can be watched, but even then it never works as I
       | expect, so I end up just flooding the log with values when
       | testing.
       | 
       | I've thought for years the console should add Data.gui [1] style
       | UI for viewing/testing variable and settings values. You can see
       | it action on this CodePen [2].
       | 
       | 1. https://github.com/dataarts/dat.gui
       | 
       | 2. https://codepen.io/russellbeattie/full/kGxaqM
        
         | 20after4 wrote:
         | I've had the same frustration. The browsers have such great
         | debugging features, in theory, but they never seem to work
         | reliably. I can't even get all of my breakpoints to reliably
         | hit.
         | 
         | Everything seems to work ok when the code is unrolled but as
         | soon as it gets bundled, even if not minified, it seems that a
         | lot of debugger features get broken, at least that's been my
         | experience.
         | 
         | Note: I'm not a front-end engineer and I'm probably doing
         | something wrong.
        
         | iudqnolq wrote:
         | Even though minified variables appear under the correct name in
         | the sidebar panel in chrome I still get an error that they're
         | undefined in a watchpoint, which is annoying.
        
       | acemarke wrote:
       | I'm going to put in a very relevant self-plug for the tool that I
       | work on.
       | 
       | I work at Replay.io, and we're building a true "time traveling
       | debugger" for JS. Our app is meant to help simplify debugging
       | scenarios by making it easy to record, reproduce and investigate
       | your code.
       | 
       | The basic idea of Replay: Use our fork of Firefox or Chrome to
       | make a recording of your app, load the recording in our debugger
       | UI, and you can pause at _any_ point in the recording. In fact,
       | you can add print statements to any line of code, and it will
       | show you what it _would_ have printed _every time that line of
       | code ran_!
       | 
       | From there, you can jump to any of those print statement hits,
       | and do typical step debugging and inspection of variables. So,
       | it's the best of both worlds - you can use print statements _and_
       | step debugging, together, at any point in time in the recording.
       | It also lets you inspect the DOM and the React component tree at
       | any point as well.
       | 
       | I honestly wish I'd had Replay available much earlier in my
       | career. I can think of quite a few bugs that I spent hours on
       | that would have been _much_ easier to solve with a Replay
       | recording. And as an OSS maintainer for Redux, there's been a
       | number of bugs that I was _only_ able to solve myself in the last
       | year because I was able to make a recording of a repro and
       | investigate it further (like a tough subscription timing issue in
       | RTK Query, or a transpilation issue in the RTK listener
       | middleware).
       | 
       | If anyone would like to try it out, see https://replay.io/record-
       | bugs for the getting started steps to use Replay (although FYI
       | we're in the middle of a transition from Firefox to Chromium as
       | our primary recording browser fork).
       | 
       | I also did a "Learn with Jason" episode where we talked about
       | debugging concepts in general, looked at browser devtools UI
       | features specifically, and then did an example of recording and
       | debugging with Replay: https://www.learnwithjason.dev/travel-
       | through-time-to-debug-...
       | 
       | If you've got any questions, please come by our Discord and ask!
       | https://replay.io/discord
        
         | lelanthran wrote:
         | > (although FYI we're in the middle of a transition from
         | Firefox to Chromium as our primary recording browser fork)
         | 
         | What's the goal of this transition?
        
           | acemarke wrote:
           | Replay's founders originally worked as engineers on the
           | Firefox DevTools (and in fact our debugger client UI started
           | as a fork of the FF Devtools codebase, although at this point
           | we've rewritten basically every single feature over the last
           | year and a half). So, the original Replay implementation
           | started as a feature built into Firefox, and thus the current
           | Replay recording browser you'd download has been our fork of
           | Firefox with all the recording capabilities built in.
           | 
           | But, Chromium is the dominant browser today. It's what
           | consumers use, it's devs use for daily development, and it's
           | what testing tools like Cypress and Playwright default to
           | running your tests in. So, we're in the process of getting
           | our Chromium fork up to parity with Firefox.
           | 
           | Currently, our Chromium for Linux fork is fully stable in
           | terms of actual recording capability, and we use it
           | extensively for recording E2E tests for ourselves and for
           | customers. (in fact, if you want to, all the E2E recordings
           | for our own PRs are public - you could pop open any of the
           | recordings from this PR I merged yesterday [0] and debug how
           | the tests ran in CI.)
           | 
           | But, our Chromium fork does not yet have the UI in place to
           | let a user manually log in and hit "Record" themselves, the
           | way the Firefox fork does. It actually automatically records
           | each tab you open, saves the recordings locally, and then you
           | use our CLI tool to upload them to your account. We're
           | actually working on this "Record" button _right now_ and hope
           | to have that available in the next few weeks.
           | 
           | Meanwhile, our Chrome for Mac and Windows forks are in early
           | alpha, and the runtime team is focusing on stability and
           | performance.
           | 
           | Our goal is to get the manual recording capabilities in place
           | ASAP so we can switch over and make Chromium the default
           | browser you'd download to make recordings as an individual
           | developer. It's already the default for configuring E2E test
           | setups to record replays, since the interactive UI piece
           | isn't necessary there.
           | 
           | Also, many of the new time-travel-powered features that we're
           | building rely on capabilities exposed by our Chromium fork,
           | which the Firefox fork doesn't have. That includes the
           | improved React DevTools support I've built over the last
           | year, which relies on our time-travel backend API to extract
           | React component tree data, and then does post-processing to
           | enable nifty things like sourcemapping original component
           | names even if you recorded a production app. I did a talk
           | just a couple weeks ago at React Advanced about how I built
           | that feature [1]. Meanwhile, my teammate Brian Vaughn, who
           | was formerly on the React core team and built most of the
           | current React DevTools browser extension UI, has just rebuilt
           | our React DevTools UI components and started to integrate
           | time-travel capabilities. He just got a working example of
           | highlighting which props/hooks/state changed for a selected
           | component, and we've got some other neat features like
           | jumping between each time a component rendered coming soon.
           | All that relies on data extracted from Chromium-based
           | recordings.
           | 
           | [0] https://github.com/replayio/devtools/pull/9885#issuecomme
           | nt-...
           | 
           | [1] https://blog.isquaredsoftware.com/2023/10/presentations-
           | reac...
        
             | Cannabat wrote:
             | Do you plan to maintain the FF Replay fork?
             | 
             | Great work Replay team! Awesome tech.
        
               | acemarke wrote:
               | Thanks! Yeah, the browser runtime team is doing
               | incredible work to make this possible, backend has made
               | great progress speeding up requests and improving
               | scaling, and us frontend folks are getting to build on
               | top of that.
               | 
               | We're not currently doing active dev work on the FF fork
               | due to the focus on Chromium, and I think the goal is to
               | fully try to move over to Chromium as the user recording
               | browser. So, we probably _won't_ be maintaining the FF
               | fork going forward due to limited resources. I think our
               | next runtime focus after Chromium parity will be Node.
               | We've already got an alpha-level Node for Linux fork that
               | actually works decently - I've used it myself to record
               | Jest or Vitest tests or Node scripts, and debug them. But
               | that does need a lot of work to flesh it out.
        
         | altano wrote:
         | I'm the author of the article and my advice is that you stop
         | reading it and go learn about Replay.io instead. It's the most
         | slept on web tech and will up your debugging game immensely.
         | Seriously, go check it out.
        
         | 10000truths wrote:
         | Is replay.io able to deterministically replay multiple
         | WebWorkers interacting with a SharedArrayBuffer?
        
           | acemarke wrote:
           | We might be able to replay the app as a whole, but we don't
           | currently support debugging workers that I know of. I know we
           | don't support recording WebGL at the moment, and there's
           | probably a couple similar recording limitations I can't think
           | of off the top of my head.
           | 
           | We've got some articles linked in our docs that talk about
           | how the recording/replay mechanism uses "effective
           | determinism" that's close enough to the original to be
           | accurate:
           | 
           | https://docs.replay.io/learn-more/contribute/how-replay-
           | work...
        
         | dmitry-vsl wrote:
         | >> you can use print statements and step debugging, together,
         | at any point in time in the recording
         | 
         | I am working on something similar. I am building an IDE that
         | allows to jump from the line printed by a console.log call to a
         | corresponding code location, and observe variables and
         | intermediate expressions.
         | 
         | It also displays a dynamic calltree of a program, allowing to
         | navigate it in a time-travel manner.
         | 
         | Currently it only supports pure functional subset of
         | JavaScript, but I am working on support for imperative
         | programming (mutating data in place).
         | 
         | https://leporello.tech/
        
         | aidos wrote:
         | Once I can replicate an issue locally, I don't normally find it
         | too difficult to understand what's happening.
         | 
         | Harder is reproducing a bug based on what I've got to go on in
         | Sentry. Mostly it's easy enough to figure out but the traces
         | you get in JS are very light in information compared to what
         | you get in Python for example.
         | 
         | Anyone have any tips on getting more information in the initial
         | report?
        
         | crtasm wrote:
         | > Once you launch the browser, you will be prompted to sign in
         | with your Google account.
         | 
         | What is the reason/need for this?
        
           | acemarke wrote:
           | Replay takes data privacy seriously. Recordings can be
           | shared, but you control who has access to them, and we need
           | to know who owns each recording. Our user accounts are
           | currently based on Google auth, so you have to log in before
           | recording so we can track ownership.
        
       | adr1an wrote:
       | For the sake of completeness, I can recommend Werkzeug. I use it
       | for Django backend development and it's incredibly useful. It
       | allows me to have "PDB" shell right in the browser whenever and
       | wherever an exception is met.
        
         | scwoodal wrote:
         | +1. It's easy to drop a 1/0 wherever I want Werkzeug to show up
         | in the browser.
        
         | agumonkey wrote:
         | does it still requires to have django-extension/runserver_plus
         | ?
        
           | adr1an wrote:
           | idk if it's a hard requirement, probably not... but I am with
           | it... at a dev-specific settings.py just like Django debug
           | toolbar, to avoid adding a dependency to production ;)
        
             | agumonkey wrote:
             | Aight, I was just asking because we hit some tiny road
             | bumps with runserver_plus long ago, but it might be worth
             | using it again to shorten debugging time.
        
       | Inviz wrote:
       | One trick i use all the time is debugging by searching through
       | loaded scripts by UI string:
       | 
       | 1) Go to Network panel, start recording network requests
       | 
       | 2) Open left sidebar and invoke search to type in the code/ui
       | string you want to find
       | 
       | 3) It'll usually find it in some weird bundled js chunk file,
       | click on the result
       | 
       | 4) It opens the network request for that file, now right click
       | anywhere in file and pick "Open in Sources" or something along
       | that line, that jumps to debugger
       | 
       | 5) Now place your debugger statement, this will probably load
       | sourcemaps too
        
       | thrdbndndn wrote:
       | Probably a good place to ask a specific question about debugging
       | here.
       | 
       | A few years ago, I was hacking a web bookreader.
       | 
       | It has a function that is used to decode images (they're
       | encrypted in some way) into canvas, and I want to find it so I
       | can call it directly in my user script to batch download decoded
       | images.
       | 
       | So I monkey patched `CanvasRenderingContext2D` function, added
       | breakpoint, and found where the the function is defined in the
       | 100k lines of obfuscated JS source code, easily.
       | 
       | The problem is.. once the page is rendered, the function would be
       | nested in some objects, something like
       | `window.abd.fdsfsd.r2323.fsdfs.fasf.xyy.myfunc`.
       | 
       | I don't know how exactly I can find the full "path" of the
       | function so I can call it, despite I'm literally pausing inside
       | of it. I eventually got it done, but it was manual and painful.
       | 
       | So I'm wandering: is there a better way to do it? The browser
       | obviously knows it, it just lacks of a way to tell.
        
         | kossTKR wrote:
         | I would like to know this as well.
         | 
         | A tree overview of all nested functions and objects with a
         | search function that quickly jumps to that place, and maybe
         | even let you call that function with data from state?
        
         | j-krieger wrote:
         | You can use `trace` to trace the call stack but I don't know of
         | any way to walk back up the call stack.
        
         | gear54rus wrote:
         | Do you want to have this in Tampermonkey script ONLY or not
         | necessarily? You can use ResourceOverride addon to simply
         | replace the 100k script with your own script that is almost the
         | same but also assigns the function you need to window.myFn or
         | something. There it can just be picked up by TM.
        
           | thrdbndndn wrote:
           | Thanks for the suggestion, but the goal is to just _use_ this
           | function in my own code (which has lots of other things going
           | on).
           | 
           | I guess it technically can be done by modifying the existing
           | JS in-place, but doing so with a very large, minified JS
           | would be a nightmare in term of maintenance.
        
             | danShumway wrote:
             | To parent off of GP, I've run into this recently while
             | working on some webextension code and I'm thinking my
             | solution is going to be to monkey-patch the script, but
             | merely to expose a reference to the object/function in
             | question.
             | 
             | So TLDR don't monkey-patch a giant minified source file
             | with a bunch of your own code. Monkey-patch the function
             | just enough to get it to be exposed globally with its
             | context, and then have your code separately reference it.
             | 
             | This is still fragile (unless you have a stable entry point
             | with regex or something, which is not completely certain to
             | exist, it'll likely break whenever the script changes), and
             | is still not ideal, and I'm still thinking a bit to see if
             | I can do anything better, but I suspect it's more stable
             | than trying to access the function directly by coding the
             | path and should be a great deal simpler as well since it
             | will work even if the function/context is in a closure.
             | 
             | ----
             | 
             | Of course, you might be lucky and there might actually be a
             | way to get at the function. For example, I am separately
             | looking into seeing if I can figure out a clean way to
             | reliably look for imports exposed through a webpack bundle,
             | since those are exposed globally and if you can find the
             | paths reliably you should be able to get access to any of
             | the imports (although you still won't have access to the
             | closures). I haven't made much progress on it though,
             | mostly because it's kind of frustrating to work on.
             | 
             | ----
             | 
             | There is also the possibility (although I suspect it would
             | get very messy very quickly, and I'm not sure of current
             | browser support) that you could theoretically maybe rig
             | something together with `function.caller`
             | (https://developer.mozilla.org/en-
             | US/docs/Web/JavaScript/Refe...), possibly patching the
             | minified source file merely to remove "use strict".
             | 
             | I have not messed with `caller` in probably close to a
             | decade at this point, so I make no promises at to whether
             | it still works at all :) but... in its heyday before we
             | realized how wildly insecure it was, it did allow
             | reconstructing the stack from a function in-code in some
             | situations.
        
         | alex7734 wrote:
         | The browser does not know the path. Also, if the function (or
         | one of its parents) is in a closure, there may not even be a
         | path to the function from window.
         | 
         | If you're sure the function is reachable from window you can
         | search for it recursively:                   (function () {
         | function search(prefix, obj, fn, seen = null) {
         | if (!seen) seen = new Set();                      // Prevent
         | cycles.                 if (seen.has(obj)) return false;
         | seen.add(obj);                      console.log('Looking in ' +
         | prefix);                      for (let key of Object.keys(obj))
         | {                     let child = obj[key];
         | if (child === null || child === undefined) {
         | } else if (child === fn) {
         | console.log('Found it! ' + prefix + '.' + key);
         | return prefix + '.' + key;                     } else if
         | (typeof child === 'object') {                          //
         | Search this child.                         let res =
         | search(prefix + '.' + key, child, fn, seen);
         | if (res) {                             return res;
         | }                     }                 }
         | return false;             }                  // For example:
         | let fn = function() { alert('hi'); }             window.a = {};
         | window.a.b = {};             window.a.b.c = {};
         | window.a.b.c.f = fn;             return search('window',
         | window, fn);         })();
        
           | thrdbndndn wrote:
           | Yeah it's reachable (in unsafeWindow for user script), I
           | eventually find it by something similar.
           | 
           | In your example, you already has a reference of `fn` to use,
           | which isn't the case for my userscript (if I have a
           | reference, I would just use it!).
           | 
           | I have to search based on the features in plain text of the
           | function (using some regexes on `fn.toString()` to check how
           | the arguments look like).
        
             | alex7734 wrote:
             | The idea is that you use a breakpoint somewhere where you
             | have a reference to the function to see it then paste the
             | search() function in the debugger console and call it to
             | find it in window
        
               | thrdbndndn wrote:
               | Oh I got it now. Thanks! Will try next time.
        
         | Zecc wrote:
         | Have you tried accessing `arguments.callee`[0]? It is
         | unfortunately deprecated and might throw an error. I've never
         | tried it myself as I rarely use breakpoints in the debugger.
         | [0]: https://developer.mozilla.org/en-
         | US/docs/Web/JavaScript/Reference/Functions/arguments/callee
        
       | Mizza wrote:
       | I've been a Python/Elixir programmer for a long time and I make
       | heavy use of pdb.set_trace()/IEx.pry().
       | 
       | Lately, I've inherited a very messy NodeJS backend and have been
       | pulling my remaining hair out working without proper debugging
       | tools. I've gone back to 'console.log' debugging, but it makes me
       | feel like a caveman.
       | 
       | I can't believe that this whole popular ecosystem doesn't have a
       | proper debugging REPL - can anybody point me in the right
       | direction?
        
         | 0000000000100 wrote:
         | You can do some solid debugging with NodeJS if you use the
         | VSCode dev tools. Just add it as a debugging option and you can
         | add breakpoints and step through functions.
         | 
         | Works pretty great, JavaScript is pretty nice to debug since
         | everything is incapsulated inside an object for the most part.
        
         | madeofpalk wrote:
         | It does. `node --inspect-brk`. You can connect to it with VS
         | Code or Chrome dev tools. The tricky part is whether there's
         | build tooling infront of just the nodejs command, like
         | converting typescript or something like that. But if you run
         | `node`, then it's pretty easy.
         | 
         | Its debugging REPL is just the javascript console itself.
        
           | Mizza wrote:
           | I looked into that a little bit, but I've got this TS
           | transpiling crap to deal with as well, and I don't want to
           | lose my live code reloading.
           | 
           | I guess I'll try again when I find the time. Was hoping there
           | was some 3rd party package I could use to just drop in and
           | set a trace. Thanks.
        
             | connor4312 wrote:
             | That should work fine in the vscode debugger, you just want
             | to make sure that the transpiler you're using is generating
             | sourcemaps. Generally they do by default. If you have
             | issues, open a github issue and I'll fix it :)
        
         | williamdclt wrote:
         | As somebody else pointed out, --inspect or --inspect-brk is
         | what you're after.
         | 
         | In VsCode you can also use the "open JavaScript debug terminal"
         | command: it opens a terminal in which any node command
         | automatically starts with a debugger attached
        
         | kaptainscarlet wrote:
         | What I like about the Elixir repl, which I assume is similar to
         | the Erlang repl is its ability to connect to a live process, a
         | feature I haven't seen in the Node JS ecosystem.
        
         | agumonkey wrote:
         | Maybe not sufficient, but I just found out about python snoop
         | 
         | https://pypi.org/project/snoop/
         | 
         | deep tracer decorator
        
       | lewisjoe wrote:
       | The debugging tools built within the browsers have come a long
       | way in the last couple of decades. I'm a JS veteran and I'm
       | deeply grateful to all the people putting in such efforts to make
       | debugging code in the browser so intuitive.
       | 
       | Whenever I go to a different zone of development, like backend or
       | a different language, I miss this ecosystem of debugging tools
       | that modern browsers have by default.
        
         | beebeepka wrote:
         | Absolutely. It's not perfect but it sure beats the debugging
         | nodejs with vscode experience a fellow developer was pushing. I
         | would take the console over this hell.
        
           | pyrolistical wrote:
           | I don't know if you are making the implication that you could
           | use chrome devtools to debug nodejs, so I'm making it
           | explicitly clear you can!
           | https://nodejs.org/en/docs/guides/debugging-getting-started
        
         | civilitty wrote:
         | Shout outs to the people behind the Firebug extension which
         | really kicked browser devtools into high gear.
        
         | OOPMan wrote:
         | What in particular do you feel is so special about the JS
         | debugging experience?
         | 
         | I've done a lot of debugging on Python, Java and C++ over the
         | years and never felt like I was missing tools (although I
         | certainly met plenty of people that were ignorant of their
         | options in this regard...)
        
           | halvo wrote:
           | I switched to c# dev from web a couple years ago and am
           | baffled there's no built in way to see the network requests
           | my app is making when debugging
        
             | TheBigSalad wrote:
             | Lol been waiting patiently for that for 20 years in .Net.
             | Such an obvious gap.
        
       | elpachongco wrote:
       | I haven't had the need to use it but I've been thinking if
       | something like the last one `Monitor Events for Element` exists.
       | Glad it does. Although according to the article, it's a Chrome-
       | only feature. I wonder if there are any alternatives for Firefox?
        
       | BMorearty wrote:
       | Under the section "Debugging Property Reads": how would you
       | convert `{configOption: true}` to `{get configOption() {
       | debugger; return true; }}` using a conditional breakpoint?
        
       ___________________________________________________________________
       (page generated 2023-11-11 23:01 UTC)