Motivation
As of 2015, debug mode serves makes load.php requests serially for each resource (style, scripts) of each module.
It works this way because when serving a raw JS file from disk, browsers execute the file immediately upon download, which means the only way to ensure code executes in the correct order, is to not request the next file until the previous one has completed.
This is is inefficient and slow, and makes debug mode unsuitable for large features such as VisualEditor (see blocked/parent tasks).
The other issue with this is that the execution scope is changed from local module scope, to global scope. This is the only reason that we have the convention to wrap each JS file in a closure (for files in legacy non-packageFiles modules). Because that way, it has module scope even in debug mode. For production mode the closure is redundant, given the load.php/implement() wrapper already has local scope. This module scope has been part of ResourceLoader since the very beginning in 2010, and is similar to what Node.js, RequireJS, Rollup etc. do nowadays.
Requirements
- JavaScript code will execute with local scope in debug mode (same as production).
- Modules that depend on each other will load in parallel in debug mode (same as production).
- Modules with N JS files will require significantly fewer than N web requests to load in debug mode (close to or equal to production).
- JavaScript code and CSS code will continue to be served without minification in debug mode, preserving all code comments and whitespace.
Proposal
debug=2 (and later by default for debug=true)
Create a fresh with a new debug mode that is much closer to production.
It will essentially just do two things at first:
- Disable minification. This means all code comments and whitespace is preserved. It also means the development server won't need to perform as much minification, which helps in slow VM-based environments like MediaWiki-Vagrant.
- Disable multi-module batching. This means each module will load in its own module=… request.
In practical terms, this means debug mode will behave for all modules similar to how it behaves for packageFiles-modules today already. In other words, the only thing we lose is raw file paths. So instead of an error being attributed to ve.ui.FooBar#onClick() on line 150 of ve/ui/Foo/FooBar.js, it would be attributed to ve.ui.FooBar#onClick() of modules=ext.visualEditor.
Depending on your workflow, this might not make much difference. E.g. in most text editors, a file can be quickly opened by typing cmd-P/ctrl-P, enter "ve ui FooBar" and the relevant file is there, etc.
Also, if you've been using production mode as-is for debugging (like me), then this will have been how you open files anyhow. The difference will be that you'd now get code formatting back without needing to use the in-browser "Prettify" button in DevTools, and get code comments as well within the browser.
Long term, we will get line numbers back with source maps (T47514). But in the interest of moving this forward one step at a time, I've changed this proposal from the original version to not include source maps initially.
debug=1
If some people prefer the old debug mode we have today (with its flaws) over the above proposal, I'd be open to maintaining that a little longer (at least until source maps are ready). Which you could opt-in, and possibly rename to debug=old after flipping the defaut. Let me know in the comments below if this is something you think you'd make use of.