Page MenuHomePhabricator

Non-packaged gadgets leak variables into global scope when loaded with ?debug=1
Closed, InvalidPublicBUG REPORT

Description

Steps to replicate the issue (include links if applicable):

  • Create a non-packaged gadget (without package in gadget definition) with code like const test = 1;
  • Load a page with this gadget and ?debug=1

What happens?:
test is leaked to global scope, which doesn't happen in normal mode and ?debug=2.

What should have happened instead?:
test is not leaked, which is consistent with normal mode.

Other information (browser name/version, screenshots, etc.):
I believe we should keep this consistent because it can introduce unexpected bugs and conflicts when debugging.

Event Timeline

Restricted Application added a subscriber: Aklapper. · View Herald Transcript

As it occurs only with debug=1, it might not be worth spending too much time on fixing this given T367441: Remove ResourceLoader debug mode v1.

Krinkle closed this task as Invalid.EditedJan 6 2025, 3:50 PM
Krinkle subscribed.

This is not a bug. This is by design. Debug mode v1 promises to load your code exactly as you wrote it. This means that, unless your code includes a closure ("IIFE" function) or something, the code will be evaluated in the global scope. There is no other way to load your code in a way that still has line numbers, columns, and file paths exactly as the original. This is not limited to Gadgets either, the same is true for core and extension JavaScript files as well, and has been this way since 2011, and is why older MediaWiki core files often used a closure: T50886: ResourceLoader: Remove obsolete closures from files.

In debug v2, we make a different promise. We don't promise to "load" your code as written. Instead we only promise to "include" your code as written, still bundled and wrapped like in production. This is a compromise, with pros and cons. Pros, it behaves like production. Cons, it doesn't look exaclty like the code in your editor.

Note that if you use a "package" module, you opt-in to essentially forcing debug=2 mode for your module, thus allowing you to safely remove redundant closures from your code. If you write non-package module code, and wish to use debug=1, you should include closures in the code.

We also have source maps nowadays, so you do not need to enable debug mode to debug your code. In production mode, you should already be able to see your code "as written". This is in many ways the best of both worlds. You get to fully have production behaviour (bundled, minified, wrapped) and fully see your code as written (like debug v1) thanks to source maps informing the browser to "show" the original code, without actually executing it that way (which would leak global variables).

I agree debug=1 is indeed worth removing for this and other reasons.