Background
The original debug mode tries to load each file from its original place on disk. For example a request for load.php?module=foo, in debug moode, instead becomes three script tags like <script src=resources/foo/A.js> <script src=resources/foo/B.js> and <script src=resources/foo/C.js>. This was great because it means stack traces all reflect the original file paths, names, line numbers, etc, and of course naturally avoids minification.
There were two main drawbacks, which is why we developed debug mode v2 (T85805):
- Behaviour difference. By loading files raw from disk, we skip all bundling transformations. This is desirable for transformations like minification (which you don't want when debugging). This is neutral for transformations like batching (meh). This is negative for logical transformations such as closure wrapping and package files, because it means local variables become global variables.
- Speed. By loading each file raw, there is no closure wrapper. Without a closure wrapper, we cannot control when it executes. The script just executes as soon as the browser receives it. This means that we cannot load N files of the same module in parallel, and also means dependencies can't be loaded in parallel. The result is that each file is loaded serially with the browser only doing either downloading or parsing at any given time. There is a lot of idle time wasted there which means pages loaded slower in debug=1 mode. This was barely noticable in production for most workloads, but for certain exceptionally large extensions (e.g. VisualEditor) this would add several whole seconds of unavoidable delay.
Since then we have developed debug mode v2 (T85805), which is essentially unmodified production mode with only batching and minification turned off. This means code is easily identifitiable, is not combined with unrelated modules, and maintains concurrency for speed.
Further more, we have shipped support for Source Maps (T47514: ResourceLoader: Implement support for Source Maps) which means that even in production mode, you basically get the "perfect" debug mode without needing to even turn on debug mode.
Related:
- T85805: Introduce ResourceLoader debug mode v2
- T47514: ResourceLoader: Implement support for Source Maps
- T50886: ResourceLoader: Remove obsolete closures from files
Problem
- The experience we serve when turning on debug=true is not the recommended debugging experience. This increases the learning curve and means people run into issues we already solved.
When asked directly, we generally recommend developers to open the devtools directly in production mode, because all modern browsers will automatically apply ResourceLoader's source maps. No need to enable debug mode. Or if you want to enable other debug features (e.g. verbose logging, and disabling localStorage), I generally recommend debug=2 not debug=true.
- The existence of debug mode v1 justifies a fear of leaking global variables. The result is that people (understandably) defensively wrap each JS file in a closure just in case, and may toggle ESLint rules such as no-implicit-globals.
This is something that was meant to be in the past after T50886: ResourceLoader: Remove obsolete closures from files, but as long as our ESLint present does not reflect this, people will likely continue to think that these workarounds are still needed!
Proposal
- Promote debug=2 as the mapping for debug=true. Today it maps to debug=1.
- After a few weeks, remove debug=1.
- Update eslint-config-wikimedia to default to commonjs mode since both package modules and classic modules are always wrapped in commonjs closures by ResourceLoader, there is no risk of leaking variables. The only reason we adopted this convention back in 2010 is because in debug mode, this closure would be omitted. This will not be the case anymore if we remove debug=1.
In communication, it'll be important to emphasize that source maps transparently tell the browser the original location of your code, without needing to actually re-download it from that URL. This means all production behaviours and transformations reliably apply, creating consistency between production mode, debug mode, and debugging with source maps.