Bindings where `@scope` has same name as module can result in runtime errors
When a binding's @scope has the same name as a module, the binding's scope is shadowed by the module:
module URL = {
@val @scope("URL")
external revokeObjectURL: string => unit = "revokeObjectURL"
}
URL.revokeObjectURL("some url")
let URL = {};
URL.revokeObjectURL("some url");
I think this is not a v12 issue per se, it's just that v12 doesn't escape URL with $$ anymore.
If the module name is different, the same problem exists in v11:
module URRL = {
@val @scope("URRL")
external revokeObjectURL: string => unit = "revokeObjectURL"
}
URRL.revokeObjectURL("some url")
https://rescript-lang.org/try?version=v11.1.4&module=esmodule&code=LYewJgrgNgpgBAVQEpIDJwLxwN5zgKDwAEA3AQyjiIGcBjEABxgAoAiZNVgSkLhgA8ALjABOAOwpwRMEiADWMAPIAjAFYxag5KgBccaoJEBLMQHNMAPjgQxRwZjitpshSvWbtrfAF98+DqgAdM7ySmoaWmhs1CDA8BAiUNz4QA
Ah I didn't read the breaking changes section of v12.0.0-alpha.1 carefully enough - I see now that since https://github.com/rescript-lang/rescript/pull/6831 we're not escaping browser globals anymore.
I'll update this issue title and description to not be v12 specific 👍
The problem is not because of @scope, but the module name.
I see. It should be something like:
let URL$1 = {};
URL.revokeObjectURL("some url");
export {
URL$1 as URL,
}
Workaround (IMO the correct resolution):
module URL = {
@val @scope("globalThis.URL")
external revokeObjectURL: string => unit = "revokeObjectURL"
}
URL.revokeObjectURL("some url")
Although this can be broken in basically the same way:
module URL = {
@val @scope("globalThis.URL")
external revokeObjectURL: string => unit = "revokeObjectURL"
}
let globalThis = 0
URL.revokeObjectURL("some url")
globalThis should be mangled by default.
The output in v12 is:
let URL = {};
globalThis.URL.revokeObjectURL("some url");
let $$globalThis = 0;
export {
URL,
$$globalThis,
}
/* Not a pure module */
One downside of leveraging globalThis is that it doesn't look handwritten. But I guess there's no other good way around this.
Maybe we can make it as a standard like @globalScope(..) ?
Are there any alternative ways around this? Could we detect when this unintended clash happens and only then emit globalThis?
globalThisshould be mangled by default.
Ah, right, it is mangled in v12, but not v11.