Announcing Scala.js 1.8.0
Dec 10, 2021.
We are excited to announce the release of Scala.js 1.8.0!
This release supports Node.js 17 out of the box. If you were previously using one of the workarounds described in this issue, you may remove it when upgrading to Scala.js 1.8.0.
It also introduces compiler warnings when using the default ExecutionContext.global
.
Read below for details about the reasons, replacements and ways to silence the warnings.
Finally, it introduces a few new language features, including support for the JavaScript metaproperty new.target
.
Read on for more details.
Getting started
If you are new to Scala.js, head over to the tutorial.
If you need help with anything related to Scala.js, you may find our community on Gitter and on Stack Overflow.
Bug reports can be filed on GitHub.
Release notes
If upgrading from Scala.js 0.6.x, make sure to read the release notes of Scala.js 1.0.0 first, as they contain a host of important information, including breaking changes.
This is a minor release:
- It is backward binary compatible with all earlier versions in the 1.x series: libraries compiled with 1.0.x through 1.7.x can be used with 1.8.0 without change.
- It is not forward binary compatible with 1.7.x: libraries compiled with 1.8.0 cannot be used with 1.7.x or earlier.
- It is not entirely backward source compatible: it is not guaranteed that a codebase will compile as is when upgrading from 1.7.x (in particular in the presence of
-Xfatal-warnings
).
As a reminder, libraries compiled with 0.6.x cannot be used with Scala.js 1.x; they must be republished with 1.x first.
New compiler warnings with broad applicability
The default ExecutionContext.global
is now deprecated
The default ExecutionContext
provided by Scala.js as ExecutionContext.global
and ExecutionContext.Implicits.global
uses JavaScript Promise
s as its underlying mechanism.
While it is standard in ECMAScript 2015+, it turns out that they are not fair with respect to other asynchronous events, like timers and network operations.
Details on this issue are explained in the readme for scalajs-macrotask-executor
.
We cannot fix the default ExecutionContext
because the only existing solutions use features of browsers and Node.js that are outside of the ECMAScript standard.
To address the issue, Scala.js 1.8.0 emits a compiler warning to nudge users towards using scalajs-macrotask-executor
.
Attempts to use either of the following imports:
will emit the following extensive warning:
As the warning says, the recommended fix is to use the executor provided by scalajs-macrotask-executor
, as an external dependency.
If you prefer to keep the existing behavior and silence the warning instead, this can be done in a number of ways:
- Adding
@nowarn("cat=other")
(Scala >= 2.13.x only) - Setting the
-P:scalajs:nowarnGlobalExecutionContext
compiler option (in sbt, withscalacOptions += "-P:scalajs:..."
) - Using
scala.scalajs.concurrent.JSExecutionContext.queue
(the implementation of ExecutionContext.global in Scala.js) directly
New features
@JSImport
’s second argument is now optional
When importing native JS members from a module, we use @JSImport
as follows:
The first argument to @JSImport
represents the module name, while the second one is the module member name to import.
In many cases, like in the examples above, the member name is reused as the Scala name.
Starting with Scala.js 1.8.0, the second argument becomes optional, and defaults to the name of the Scala entity that is annotated. The above example can be simplified as follows, without change of behavior:
@JSGlobal
’s argument is now optional when used inside an object
Similarly to the above change, the argument of @JSGlobal
is now optional when the annotated entity is in a Scala object
.
It was already optional when used at the top-level.
For example, the following is now allowed:
New primitive for JavaScript’s metaproperty new.target
The JavaScript metaproperty new.target
gives access to the constructor that was used in a calling new Foo()
expression.
It is mainly used in a parent class constructor to know what child class is being instantiated:
Scala.js 1.8.0 introduces a new primitive, js.new.target
, which can be used in the constructor of non-native JS classes, and is equivalent to JavaScript’s new.target
.
With it, the above example can be translated to Scala.js as:
Attempting to use js.new.target
anywhere but in the constructor of a non-native JS class will result in a compile error.
While JavaScript also allows to use new.target
in a function
body, there is no equivalent in Scala.js so far.
We expect the use cases for that to be very rare, and we have not found a compelling design for that feature in Scala.js yet.
This is still tracked as issue #4588.
Hashbang lines are accepted in .js file headers
Scala.js 1.7.0 introduced a new linker configuration, jsHeader
, to specify a comment to insert at the top of .js files:
Scala.js 1.8.0 extends that mechanism to allow hashbang lines at the very beginning of the header.
For example, the following header is now valid:
Miscellaneous
New JDK APIs
The following methods of java.lang.String
were added (thanks to @tom91136):
isBlank()
strip()
stripLeading()
stripTrailing()
indent(n: Int)
stripIndent()
translateEscapes()
Upgrade to GCC v20211201
We upgraded to the Google Closure Compiler v20211201.
Bug fixes
Among others, the following bugs have been fixed in 1.8.0:
- #4581 Scala.js v1.7.0 breaks pattern match in constructor of non-native JS class
- #4583 Error while emitting, head of empty list
- #4560 Console output (e.g.,
println
) not redirected to sbt client - #4601 IR checking error with
scala-java-time
- #4604
0/0
should throw an exception
You can find the full list on GitHub.