There does not appear to be a way to do the JS equivalent of import 'foo'; in Scala.js. Our workaround is this pattern:
@js.native
@JSImport("@material/mwc-button", JSImport.Default)
object RawMwcButton extends js.Object
private val dummy = RawMwcButton
If we don't have the dummy variable, object gets optimized out and import never happens.
Is there / should there be a better way to do this?
You don't necessarily need a dummy variable. It's OK to only refer to the object as a statement, for example in your main or in the constructor body of a class/object that relies on that functionality. In other words, wherever you put the
private val dummy = RawMwcButton
you can equally write just
RawMwcButton
There is no better way to do this. Since Scala.js only reaches external imports for things that are themselves reachable, you need to make sure that the object is somehow reachable.
AFAICT, it's also not really possible to change Scala.js to make this any different. Much of the specification relies on having no real entry points besides main methods and exports. We do have the notion of static initializers, which are "out of the blue" entry points, so there is precedent for adding other kinds of entry points. But adding a different kind @JSImport that would automatically reach its target module if it is on the classpath would behave very differently from the other @JSImports, and for that there is no precedent.
Could we allow local native objects/classes so that this can be hidden away? (maybe even with a macro library)?
def loadMwc(): Unit = {
@js.native
@JSImport("@material/mwc-button", JSImport.Default)
object RawMwcButton extends js.Object
RawMwcButton
}
It can already be hidden away by making it private in a companion object or something like that. It doesn't have to leak into the public API.
Ah, fair enough. Although that wouldn't work with a def macro. But not sure that is actually necessary.
Shall we close this as wontfix then? @uosis is that OK with you?
Yep, the "object as a statement" is a reasonable workaround, and is probably a better approach than classpath scanning for imports anyway.
Thanks for clarifying this!
Most helpful comment
You don't necessarily need a dummy variable. It's OK to only refer to the object as a statement, for example in your
mainor in the constructor body of a class/object that relies on that functionality. In other words, wherever you put theyou can equally write just
There is no better way to do this. Since Scala.js only reaches external
imports for things that are themselves reachable, you need to make sure that the object is somehow reachable.AFAICT, it's also not really possible to change Scala.js to make this any different. Much of the specification relies on having no real entry points besides
mainmethods and exports. We do have the notion of static initializers, which are "out of the blue" entry points, so there is precedent for adding other kinds of entry points. But adding a different kind@JSImportthat would automatically reach its target module if it is on the classpath would behave very differently from the other@JSImports, and for that there is no precedent.