Reputation: 43
After migrating from scala.js 0.6.x
to 1.0
, I've got some code related to @JSGlobalScope
broken.
My use case is like this:
The code looks like this:
@js.native
@JSGlobalScope
object Globals extends js.Object {
var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
}
then I set this var like this:
Globals.callbackFunctionFor3rdPartyLib = () => {
// do things
}
and then I add the script into the DOM.
This was working with scala.js 0.6.x
, but with 1.0
I'm getting an exception like the following:
scala.scalajs.js.JavaScriptException: ReferenceError: callbackFunctionFor3rdPartyLib is not defined
In the changelog for 1.0.0 there's a "Breaking changes" section that mentions this:
Accessing a member that is not declared causes a ReferenceError to be thrown ...
js.Dynamic.global.globalVarThatDoesNotExist = 42
would previously create said global variable. In Scala.js 1.x, it also throws a ReferenceError.
My question is:
what is the right way to do something like this (create a new global var) in scala.js 1.0
?
Upvotes: 3
Views: 288
Reputation: 22085
If you know you'll always be in a browser context, you can use @JSGlobal("window")
instead of @JSGlobalScope
on your Globals
, which will then be equivalent to doing window.myGlobalVarFor3rdPartyLib
in JS. So that will work.
@js.native
@JSGlobal("window")
object Globals extends js.Object {
var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
}
If not, but you are using a script (so not a CommonJS nor an ES module), the best thing is actually to use
object Globals {
@JSExportTopLevel("myGlobalVarFor3rdPartyLib")
var foo: js.Function[Unit] = ...
}
Note that Globals
is a normal Scala object now, not a JS one.
The @JSExportTopLevel
creates a top-level var myGlobalVarFor3rdPartyLib
at the top of the script, and then assigning Globals.foo
will also assign that top-level var
.
If you're not using a script nor know that you're going to always be in a browser, then you need to figure out the global object yourself. Scala.js 0.6.x tried to do that for you, but could fail, so we don't do that anymore. You can at least follow the "instructions" on the documentation of js.special.fileLevelThis
to reproduce what Scala.js 0.6.x was doing. I repeat the instructions here:
Using this value should be rare, and mostly limited to writing code detecting what the global object is. For example, a typical detection code--in case we do not need to worry of ES modules--looks like:
val globalObject = { import js.Dynamic.{global => g} if (js.typeOf(g.global) != "undefined" && (g.global.Object eq g.Object)) { // Node.js environment detected g.global } else { // In all other well-known environment, we can use the global `this` js.special.fileLevelThis } }
Note that the above code is not comprehensive, as there can be JavaScript environments where the global object cannot be fetched neither through
global
northis
. If your code needs to run in such an environment, it is up to you to use an appropriate detection procedure.
Upvotes: 1