Skip to content

Commit 197e0a8

Browse files
authored
Merge pull request #654 from sjrd/scalajs-1.19.0
Announcing Scala.js 1.19.0.
2 parents 6d5adb9 + 3c82f80 commit 197e0a8

File tree

8 files changed

+248
-30
lines changed

8 files changed

+248
-30
lines changed

_config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ colors: #in hex code if not noted else
6464

6565
### VERSIONS ###
6666
versions:
67-
scalaJS: 1.18.2
67+
scalaJS: 1.19.0
6868
scalaJSBinary: 1
6969
scalaJS06x: 0.6.33
7070
scalaJS06xBinary: 0.6

_data/library/versions.yml

+1
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@
3535
- 1.16.0
3636
- 1.17.0
3737
- 1.18.0
38+
- 1.19.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
---
2+
layout: post
3+
title: Announcing Scala.js 1.19.0
4+
category: news
5+
tags: [releases]
6+
permalink: /news/2025/04/21/announcing-scalajs-1.19.0/
7+
---
8+
9+
10+
We are pleased to announce the release of Scala.js 1.19.0!
11+
12+
This release comes with significant performance improvements to the WebAssembly backend.
13+
For codebase where performance is dominated by computations (rather than JS interop), you can now expect the Wasm output to be faster than the JS output.
14+
15+
Moreover, as of this writing, the latest versions of Firefox (since v131) and Safari (since v18.4) support all the WebAssembly features required to run Scala.js-on-Wasm.
16+
Chrome still requires a flag to enable exception handling.
17+
18+
If you haven't tried the WebAssembly target yet, now is a good time to do so!
19+
20+
Other highlights:
21+
22+
* Native support for JavaScript `async/await`, through `js.async { ... }` and `js.await(...)`.
23+
* Small code size improvements for the JavaScript target when using SAM lambdas.
24+
* For Wasm only: support for the JavaScript Promise Integration feature (JSPI).
25+
26+
Read on for more details.
27+
28+
<!--more-->
29+
30+
## Getting started
31+
32+
If you are new to Scala.js, head over to [the tutorial]({{ BASE_PATH }}/tutorial/).
33+
34+
If you need help with anything related to Scala.js, you may find our community [in `#scala-js` on Discord](https://discord.com/invite/scala) and [on Stack Overflow](https://stackoverflow.com/questions/tagged/scala.js).
35+
36+
Bug reports can be filed [on GitHub](https://github.com/scala-js/scala-js/issues).
37+
38+
## Release notes
39+
40+
If upgrading from Scala.js 0.6.x, make sure to read [the release notes of Scala.js 1.0.0]({{ BASE_PATH }}/news/2020/02/25/announcing-scalajs-1.0.0/) first, as they contain a host of important information, including breaking changes.
41+
42+
This is a **minor** release:
43+
44+
* It is backward binary compatible with all earlier versions in the 1.x series: libraries compiled with 1.0.x through 1.18.x can be used with 1.19.0 without change.
45+
* It is *not* forward binary compatible with 1.18.x: libraries compiled with 1.19.0 cannot be used with 1.18.x or earlier.
46+
* It is *not* entirely backward source compatible: it is not guaranteed that a codebase will compile *as is* when upgrading from 1.18.x (in particular in the presence of `-Xfatal-warnings`).
47+
48+
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.
49+
50+
## Enhancements with compatibility concerns
51+
52+
### Drop support for non-strict floats
53+
54+
Support for non-strict `Float`s was deprecated 3 years ago in Scala.js 1.9.0.
55+
We now removed that support.
56+
Builds configured to use non-strict floats (with `withStrictFloats(false)`) will refuse to compile.
57+
If that setting is used through an indirect dependency, it will be silently ignored.
58+
59+
Strict floats are almost entirely backward compatible with non-strict floats.
60+
In general, strict floats mandate behavior which non-strict floats leave unspecified (so non-strict floats were always permitted to behave like strict floats).
61+
The only exception is that tests of the form `x.isInstanceOf[Float]` (or `case x: Float =>`) will answer `false` for number values that cannot exactly be represented in a 32-bit `Float`.
62+
63+
We are not aware of any codebase that was ever adversely affected by strict float semantics.
64+
65+
### Deprecate support for targeting ECMAScript 5.1
66+
67+
The support for targeting ECMAScript 5.1 is currently the biggest source of alternative code paths and polyfills in our codebase.
68+
Moreover, the ES 5.1 output does not even have exactly the same semantics as later versions:
69+
70+
* JS classes are not true classes. Notably, that means they cannot extend native ES classes, and they do not inherit static members.
71+
* Top-level exports are declared as vars instead of lets.
72+
73+
10 years after the introduction of ECMAScript 2015, we believe it is time to deprecate the support for targeting ES 5.1, so that we can eventually remove it.
74+
The removal will happen in a future major or minor release of Scala.js.
75+
76+
### Changes to the IR and linker APIs
77+
78+
For tooling authors who directly manipulate the IR and linker APIs, there have been some breaking changes in that area.
79+
This is in line with our version policy for the linker APIs.
80+
81+
The most likely changes you may hit are:
82+
83+
* The `ir.Trees.Closure` node has two additional fields: `flags` and `resultType`.
84+
* All the "well-known" names that were previously in `ir.Names` have been moved to a new object `ir.WellKnownNames`.
85+
* `ir.Types.PrimRef` is not a case class anymore.
86+
87+
## Enhancements
88+
89+
### Native support for JS `async/await`
90+
91+
Note 1: Scala 3 users will have to wait for a future release of Scala 3---likely 3.8.0---to be able to use this new feature.
92+
93+
Note 2: when targeting WebAssembly, this feature requires support for JSPI (JavaScript Promise Integration).
94+
You can [check support for JSPI in various browsers here](https://webassembly.org/features/#table-row-jspi).
95+
On Node.js v23+, this requires the flag `--experimental-wasm-jspi`.
96+
97+
This release adds a pair of primitives, `js.async` and `js.await`, which correspond to the `async/await` feature of JavaScript.
98+
In order to use these functions, you must configure Scala.js to target ECMAScript 2017 or later.
99+
In an sbt build, use the following setting:
100+
101+
{% highlight scala %}
102+
// Target ES 2017 to enable async/await
103+
scalaJSLinkerConfig := {
104+
scalaJSLinkerConfig.value
105+
.withESFeatures(_.withESVersion(ESVersion.ES2017)) // enable async/await
106+
},
107+
{% endhighlight %}
108+
109+
You can then use `js.async { ... }` blocks containing `js.await` calls.
110+
For example:
111+
112+
{% highlight scala %}
113+
val p: js.Promise[String] = downloadSomething()
114+
val result: js.Promise[Int] = js.async {
115+
val text: String = js.await(p)
116+
text.toInt
117+
}
118+
{% endhighlight %}
119+
120+
`js.async { ... }` executes a block of code under a JavaScript `async` context.
121+
The block of code can await `js.Promise`s using `js.await`.
122+
Doing so will continue the execution after the call to `js.await` when the given `Promise` is resolved.
123+
If the `Promise` is rejected, the exception gets rethrown at the call site.
124+
125+
A block such as `js.async { body }` is equivalent to an immediately-applied JavaScript `async` function:
126+
127+
{% highlight javascript %}
128+
(async () => body)()
129+
{% endhighlight %}
130+
131+
`js.async` returns a `js.Promise` that will be resolved with the result of the code block.
132+
If the block throws an exception, the `Promise` will be rejected.
133+
134+
Calls to `js.await` can only appear within a `js.async` block.
135+
They must not be nested in any local method, class, by-name argument or closure.
136+
The latter includes `for` comprehensions.
137+
They may appear within conditional branches, `while` loops and `try/catch/finally` blocks.
138+
139+
### Orphan `await`s in WebAssembly
140+
141+
When compiling for Scala.js-on-Wasm only, you can allow calls to `js.await` anywhere, by adding the following import:
142+
143+
{% highlight scala %}
144+
import scala.scalajs.js.wasm.JSPI.allowOrphanJSAwait
145+
{% endhighlight %}
146+
147+
Calls to orphan `js.await`s are validated at run-time.
148+
There must exist a dynamically enclosing `js.async { ... }` block on the call stack.
149+
Moreover, there cannot be any JavaScript frame (JavaScript function invocation) in the call stack between the `js.async { ... }` block and the call to `js.await`.
150+
If those conditions are not met, a JavaScript exception of type `WebAssembly.SuspendError` gets thrown.
151+
152+
The ability to detach `js.await` calls from their corresponding `js.async` block is a new superpower offered by JSPI.
153+
It means that, as long as you enter into a `js.async` block somewhere, you can *synchronously await* `Promise`s in any arbitrary function!
154+
This is a power of the same sort as Loom on the JVM.
155+
We are looking forward to seeing new libraries built on these primitives to offer efficient and straightforward APIs.
156+
157+
### Performance improvements for WebAssembly
158+
159+
Scala.js 1.19.0 brings significant performance improvements to the WebAssembly output.
160+
Starting with this release, the WebAssembly output is faster than the JavaScript output on our benchmarks (geomean of the running time is 15% lower).
161+
162+
Note that our benchmarks do not measure JavaScript interop in any significant way.
163+
If your application's performance depends mostly on JS interop, the JavaScript output is probably still faster (and will remain so for the foreseeable future).
164+
However, if your bottleneck is in computations inside Scala code, compiling to WebAssembly should now give you a free performance boost.
165+
166+
The WebAssembly target also received additional improvements in terms of code size and run-time memory consumption.
167+
168+
As a reminder, you may read detailed information about [the WebAssembly backend in the docs]({{ BASE_PATH }}/doc/project/webassembly.html).
169+
170+
## Miscellaneous
171+
172+
### New JDK APIs
173+
174+
This release adds support for the following JDK methods:
175+
176+
* Most of `java.util.random.RandomGenerator`
177+
178+
### Improvements to the JUnit interface
179+
180+
Thanks to [`@dubinsky`](https://github.com/dubinsky) for contributing two improvements to the integration of our JUnit implementation with external tooling (in particular Gradle):
181+
182+
* populate `sbt.testing.Event.throwable` on test failure, and
183+
* populate `sbt.testing.Event.duration`.
184+
185+
## Bug fixes
186+
187+
The following bugs have been fixed in 1.19.0:
188+
189+
* [#5131](https://github.com/scala-js/scala-js/issues/5131) Linker not noticing instance test changes
190+
* [#5135](https://github.com/scala-js/scala-js/issues/5135) Deadlock in concurrent initialization of `ir.Names` and `ir.Types`.
191+
192+
You can find the full list [on GitHub](https://github.com/scala-js/scala-js/issues?q=is%3Aissue+milestone%3Av1.19.0+is%3Aclosed).

assets/badges/scalajs-1.19.0.svg

+1
Loading

doc/all-api.md

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ title: All previous versions of the Scala.js API
55

66
## All previous versions of the API
77

8+
### Scala.js 1.19.0
9+
* [1.19.0 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.19.0/scala/scalajs/js/index.html)
10+
* [1.19.0 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.19.0/)
11+
* [1.19.0 scalajs-javalib-intf]({{ site.production_url }}/api/scalajs-javalib-intf/1.19.0/)
12+
* [1.19.0 scalajs-ir]({{ site.production_url }}/api/scalajs-ir/1.19.0/org/scalajs/ir/index.html)
13+
* [1.19.0 scalajs-linker-interface]({{ site.production_url }}/api/scalajs-linker-interface/1.19.0/org/scalajs/linker/interface/index.html) ([Scala.js version]({{ site.production_url }}/api/scalajs-linker-interface-js/1.19.0/org/scalajs/linker/interface/index.html))
14+
* [1.19.0 scalajs-linker]({{ site.production_url }}/api/scalajs-linker/1.19.0/org/scalajs/linker/index.html) ([Scala.js version]({{ site.production_url }}/api/scalajs-linker-js/1.19.0/org/scalajs/linker/index.html))
15+
* [1.19.0 scalajs-test-adapter]({{ site.production_url }}/api/scalajs-sbt-test-adapter/1.19.0/org/scalajs/testing/adapter/index.html)
16+
* [1.19.0 sbt-scalajs]({{ site.production_url }}/api/sbt-scalajs/1.19.0/#org.scalajs.sbtplugin.package)
17+
818
### Scala.js 1.18.2
919
* [1.18.2 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.18.2/scala/scalajs/js/index.html)
1020
* [1.18.2 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.18.2/)

doc/internals/version-history.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ title: Version history
55

66
## Version history of Scala.js
77

8+
- [1.19.0](/news/2025/04/21/announcing-scalajs-1.19.0/)
89
- [1.18.2](/news/2025/01/23/announcing-scalajs-1.18.2/)
910
- [1.18.1](/news/2025/01/09/announcing-scalajs-1.18.1/)
1011
- ~~1.18.0~~ ([severely broken](https://github.com/scala-js/scala-js/issues/5107) and therefore never announced)

doc/project/webassembly.md

+21-10
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ The Wasm backend emits code with the following requirements:
3131
* Wasm GC
3232
* Exception handling, including the latest `exnref`-based variant
3333
* The `ESModule` module kind (see [emitting modules](./module.html))
34-
* Strict floats (which is the default since Scala.js 1.9.0; non-strict floats are deprecated)
3534

36-
Supported engines include Node.js 22, Chrome and Firefox, all using some experimental flags (see below).
35+
Supported engines include Node.js 23, Chrome, Firefox and Safari.
36+
Node.js and Chrome currently require using some experimental flags (see below).
3737

3838
## Language semantics
3939

@@ -75,7 +75,8 @@ scalaJSLinkerConfig := {
7575
jsEnv := {
7676
val config = NodeJSEnv.Config()
7777
.withArgs(List(
78-
"--experimental-wasm-exnref", // required
78+
"--experimental-wasm-exnref", // always required
79+
"--experimental-wasm-jspi", // required for js.async/js.await
7980
"--experimental-wasm-imported-strings", // optional (good for performance)
8081
"--turboshaft-wasm", // optional, but significantly increases stability
8182
))
@@ -90,29 +91,39 @@ The backend emits ES modules with the same layout and interface as those produce
9091

9192
Here are some engines known to support enough Wasm features.
9293

93-
### Node.js 22
94+
### Node.js 23
9495

9596
As mentioned above, Node.js 23 and above requires the following flags:
9697

97-
* `--experimental-wasm-exnref`: required
98+
* `--experimental-wasm-exnref`: always required
99+
* `--experimental-wasm-jspi`: required to use `js.async`/`js.await`
98100
* `--experimental-wasm-imported-strings`: optional (good for performance)
99101
* `--turboshaft-wasm`: optional, bug significantly increases stability
100102

101103
### Chrome
102104

103105
In `chrome://flags/`, enable ["Experimental WebAssembly"](chrome://flags/#enable-experimental-webassembly-features).
104106

107+
For `js.async`/`js.await` support, also enable ["Experimental WebAssembly JavaScript Promise Integration (JSPI)"](chrome://flags/#enable-experimental-webassembly-jspi).
108+
105109
### Firefox
106110

107-
In `about:config`, enable `javascript.options.wasm_exnref`.
111+
Firefox supports all the "always required" features since v131, with enhanced performance since v134.
112+
113+
For `js.async/js.await` support, go to `about:config`, enable `javascript.options.wasm_js_promise_integration`.
114+
This may require a Firefox Nightly build when you read these lines, although it should be available by default soon.
115+
116+
### Safari
108117

109-
Make sure to *disable* `javascript.options.wasm_js_string_builtins`.
110-
Firefox has two issues with it that break Scala.js ([1919901](https://bugzilla.mozilla.org/show_bug.cgi?id=1919901) and [1920337](https://bugzilla.mozilla.org/show_bug.cgi?id=1920337)).
118+
Safari supports all the "always required" features since v18.4.
119+
120+
`js.async/js.await` is not supported yet, however.
111121

112122
## Performance
113123

114-
Performance of the generated code is currently a hit-or-miss.
115-
Depending on the codebase, it may be several times faster or slower than the JS backend.
124+
If the performance of your application depends a lot on JavaScript interop, the Wasm output may be (significantly) slower than the JS output.
125+
126+
For applications whose performance is dominated by computions inside Scala code, the Wasm output should be significantly faster than the JS output (geomean 15% lower run time across our benchmarks).
116127

117128
Further work on improving performance is ongoing.
118129
Keep in mind that performance work on the Wasm backend is a few months old, compared to a decade of optimizations in the JS backend.

doc/semantics.md

+21-19
Original file line numberDiff line numberDiff line change
@@ -89,25 +89,6 @@ Instead, it uses the more sensible `java.lang.Void`, as `Void` is the boxed clas
8989
This means that while `java.lang.Void` is not instantiable on the JVM, in Scala.js it has a singleton instance, namely `()`.
9090
This also manifests itself in `Array[Unit]` which is effectively `Array[java.lang.Void]` at run-time, instead of `Array[scala.runtime.BoxedUnit]`.
9191

92-
### Non-strict floats (deprecated; default until Scala.js 1.8.0)
93-
94-
Until v1.8.0, Scala.js underspecified the behavior of `Float`s by default with so-called *non-strict floats*.
95-
96-
Non-strict floats can still be enabled with the following sbt setting:
97-
98-
{% highlight scala %}
99-
scalaJSLinkerConfig ~= { _.withSemantics(_.withStrictFloats(false)) }
100-
{% endhighlight %}
101-
102-
Under non-strict floats, any `Float` value can be stored as a `Double` instead, and any operation on `Float`s can be computed with double precision.
103-
The choice of whether or not to behave as such, when and where, is left to the implementation.
104-
In addition, `x.isInstanceOf[Float]` will return `true` for any `number` values (not only the ones that fit in a 32-bit float).
105-
106-
Non-strict floats are deprecated and will eventually be removed in a later major or minor version of Scala.js.
107-
108-
Enabling non-strict floats may significantly improve the performance (up to 4x for `Float`-intensive applications) when targeting JS engines that do not support [the `Math.fround` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround), such as Internet Explorer (which implies emitting ES 5.1 code).
109-
If you are in that situation, we advise to use `Double`s instead of `Float`s as much as possible.
110-
11192
## Undefined behaviors
11293

11394
The JVM is a very well specified environment, which even specifies how some
@@ -238,3 +219,24 @@ val <ident> = Value(
238219
We believe that this covers most use cases of
239220
`scala.Enumeration`. Please let us know if another (generalized)
240221
rewrite would make your life easier.
222+
223+
## Historical
224+
225+
### Non-strict floats (removed in Scala.js 1.19.0; default until 1.8.0)
226+
227+
Until v1.8.0, Scala.js underspecified the behavior of `Float`s by default with so-called *non-strict floats*.
228+
229+
Non-strict floats could be enabled with the following sbt setting, until v1.19.0 excluded:
230+
231+
{% highlight scala %}
232+
scalaJSLinkerConfig ~= { _.withSemantics(_.withStrictFloats(false)) }
233+
{% endhighlight %}
234+
235+
Under non-strict floats, any `Float` value can be stored as a `Double` instead, and any operation on `Float`s can be computed with double precision.
236+
The choice of whether or not to behave as such, when and where, is left to the implementation.
237+
In addition, `x.isInstanceOf[Float]` will return `true` for any `number` values (not only the ones that fit in a 32-bit float).
238+
239+
Non-strict floats were deprecated in v1.8.0 and removed in v1.19.0.
240+
241+
Non-strict floats could significantly improve the performance (up to 4x for `Float`-intensive applications) when targeting JS engines that do not support [the `Math.fround` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround), such as Internet Explorer (which implies emitting ES 5.1 code).
242+
If you are in that situation, we advise to use `Double`s instead of `Float`s as much as possible.

0 commit comments

Comments
 (0)