Skip to content

Commit 7b36cc2

Browse files
committed
Announcing Scala.js 1.17.0, and add doc for the Wasm backend.
1 parent 66972b8 commit 7b36cc2

File tree

8 files changed

+287
-1
lines changed

8 files changed

+287
-1
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.16.0
67+
scalaJS: 1.17.0
6868
scalaJSBinary: 1
6969
scalaJS06x: 0.6.33
7070
scalaJS06xBinary: 0.6

_data/doc.yml

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
url: /doc/project/module.html
3030
- text: JavaScript Environments
3131
url: /doc/project/js-environments.html
32+
- text: Emitting WebAssembly
33+
url: /doc/project/webassembly.html
3234
- text: Cross-building
3335
url: /doc/project/cross-build.html
3436
- text: Testing

_data/library/versions.yml

+1
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@
3333
- 1.12.0
3434
- 1.13.0
3535
- 1.16.0
36+
- 1.17.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
---
2+
layout: post
3+
title: Announcing Scala.js 1.17.0
4+
category: news
5+
tags: [releases]
6+
permalink: /news/2024/09/25/announcing-scalajs-1.17.0/
7+
---
8+
9+
10+
We are excited to announce the release of Scala.js 1.17.0!
11+
12+
This release comes with a brand new, shiny, experimental WebAssembly backend.
13+
You can now, under certain conditions, take your existing Scala.js application and compile it to WebAssembly instead.
14+
15+
There were also some bug fixes.
16+
Despite the abnormally long release cycle (v1.16.0 was released 6 months ago), the only external bug report came in 3 weeks ago.
17+
As far as we can tell, nobody was blocked waiting for a bugfix for this long.
18+
19+
Read on for more details.
20+
21+
<!--more-->
22+
23+
## Getting started
24+
25+
If you are new to Scala.js, head over to [the tutorial]({{ BASE_PATH }}/tutorial/).
26+
27+
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).
28+
29+
Bug reports can be filed [on GitHub](https://github.com/scala-js/scala-js/issues).
30+
31+
## Release notes
32+
33+
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.
34+
35+
This is a **minor** release:
36+
37+
* It is backward binary compatible with all earlier versions in the 1.x series: libraries compiled with 1.0.x through 1.16.x can be used with 1.17.0 without change.
38+
* It is *not* forward binary compatible with 1.16.x: libraries compiled with 1.17.0 cannot be used with 1.16.x or earlier.
39+
* It is *not* entirely backward source compatible: it is not guaranteed that a codebase will compile *as is* when upgrading from 1.16.x (in particular in the presence of `-Xfatal-warnings`).
40+
41+
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.
42+
43+
## Enhancements with compatibility concerns
44+
45+
### Changes to the IR and linker APIs
46+
47+
For tooling authors who directly manipulate the IR and linker APIs, there have been some breaking changes in that area.
48+
This is in line with our version policy for the linker APIs.
49+
50+
The most likely changes you may hit are:
51+
52+
* The reference types in the IR, such as `ClassType` and `ArrayType`, now have a `nullable: Boolean` flag.
53+
There is also a new type `AnyNotNullType`.
54+
* The `NewArray` node does not accept multiple dimensions anymore.
55+
If you want to emit a multi-dimensional array creation, emit a call to `java.lang.reflect.Array.newInstance` instead.
56+
57+
## Enhancements
58+
59+
### Experimental WebAssembly backend
60+
61+
Starting with this release, Scala.js ships with an *experimental* WebAssembly backend.
62+
Under some conditions, you may use it as a drop-in replacement for the usual JavaScript backend.
63+
64+
#### Minimal setup
65+
66+
You can set it up as follows:
67+
68+
{% highlight scala %}
69+
// Emit ES modules with the Wasm backend
70+
scalaJSLinkerConfig := {
71+
scalaJSLinkerConfig.value
72+
.withExperimentalUseWebAssembly(true) // use the Wasm backend
73+
.withModuleKind(ModuleKind.ESModule) // required by the Wasm backend
74+
},
75+
76+
// Configure Node.js (at least v22) to support the required Wasm features
77+
jsEnv := {
78+
val config = NodeJSEnv.Config()
79+
.withArgs(List(
80+
"--experimental-wasm-exnref", // required
81+
"--experimental-wasm-imported-strings", // optional (good for performance)
82+
"--turboshaft-wasm", // optional, but significantly increases stability
83+
))
84+
new NodeJSEnv(config)
85+
},
86+
{% endhighlight %}
87+
88+
Make sure `node -v` reports at least v22.0.0.
89+
If not, install a newer version.
90+
91+
You are then set up to `run` and `test` your codebase with the WebAssembly backend from sbt.
92+
93+
#### Limitations
94+
95+
Note that the WebAssembly backend *silently ignores* all the `@JSExport` and `@JSExportAll` annotations.
96+
It is never possible to call methods of Scala classes from JavaScript, which includes `toString()`, even through string concatenation.
97+
JavaScript code may still call all public members of JavaScript classes (classes that inherit from `js.Any`).
98+
Moreover, `@JSExportTopLevel` is supported, as well as all the other `@JS...` annotations.
99+
100+
The WebAssembly backend does not yet support emitting multiple modules.
101+
The module split style must be set to `ModuleSplitStyle.FewestModules` (which is the default).
102+
Moreover, the codebase must not contain any feature that require emitting multiple modules: `@JSExportToplevel` annotations with several module names, or `js.dynamicImport`.
103+
We expect to lift that limitation in the future.
104+
105+
Other than that, we expect the WebAssembly backend to support all Scala.js semantics.
106+
Please report any issues you may find.
107+
108+
Stack traces are currently suboptimal.
109+
110+
#### Use in browsers
111+
112+
If you want to use it in browsers, you will need:
113+
114+
* For Firefox: in `about:config`, enable `javascript.options.wasm_exnref`.
115+
Also make sure to *disable* `javascript.options.wasm_js_string_builtins`: 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))
116+
* For Chrome: in `chrome://flags/`, enable ["Experimental WebAssembly"](chrome://flags/#enable-experimental-webassembly-features).
117+
118+
#### More information
119+
120+
Read more detailed information about [the WebAssembly backend in the docs]({{ BASE_PATH }}/doc/project/webassembly.html).
121+
122+
## Miscellaneous
123+
124+
### New JDK APIs
125+
126+
This release adds support for the following JDK methods:
127+
128+
* In `java.lang.Character`: `codePointAt`, `codePointBefore`, `codePointCount` and `offsetByCodePoints`
129+
* In `java.util.concurrent.ConcurrentHashMap`: `forEach`, `forEachKey` and `forEachValue`
130+
131+
### Unicode version
132+
133+
The Unicode database used by the methods of `java.lang.Character` was updated to Unicode v15.0.
134+
135+
## Bug fixes
136+
137+
Among others, the following bugs have been fixed in 1.17.0:
138+
139+
* [#5026](https://github.com/scala-js/scala-js/issues/5026) Output .js file names can be too long on Windows, esp. for non-ASCII class names.
140+
* [#5044](https://github.com/scala-js/scala-js/issues/5044) `jl.reflect.Array.newInstance()` does not throw the `IllegalArgumentException`s it is supposed to.
141+
142+
You can find the full list [on GitHub](https://github.com/scala-js/scala-js/issues?q=is%3Aissue+milestone%3Av1.17.0+is%3Aclosed).

assets/badges/scalajs-1.17.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.17.0
9+
* [1.17.0 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.17.0/scala/scalajs/js/index.html)
10+
* [1.17.0 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.17.0/)
11+
* [1.17.0 scalajs-javalib-intf]({{ site.production_url }}/api/scalajs-javalib-intf/1.17.0/)
12+
* [1.17.0 scalajs-ir]({{ site.production_url }}/api/scalajs-ir/1.17.0/org/scalajs/ir/index.html)
13+
* [1.17.0 scalajs-linker-interface]({{ site.production_url }}/api/scalajs-linker-interface/1.17.0/org/scalajs/linker/interface/index.html) ([Scala.js version]({{ site.production_url }}/api/scalajs-linker-interface-js/1.17.0/org/scalajs/linker/interface/index.html))
14+
* [1.17.0 scalajs-linker]({{ site.production_url }}/api/scalajs-linker/1.17.0/org/scalajs/linker/index.html) ([Scala.js version]({{ site.production_url }}/api/scalajs-linker-js/1.17.0/org/scalajs/linker/index.html))
15+
* [1.17.0 scalajs-test-adapter]({{ site.production_url }}/api/scalajs-sbt-test-adapter/1.17.0/org/scalajs/testing/adapter/index.html)
16+
* [1.17.0 sbt-scalajs]({{ site.production_url }}/api/sbt-scalajs/1.17.0/#org.scalajs.sbtplugin.package)
17+
818
### Scala.js 1.16.0
919
* [1.16.0 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.16.0/scala/scalajs/js/index.html)
1020
* [1.16.0 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.16.0/)

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.17.0](/news/2024/09/25/announcing-scalajs-1.17.0/)
89
- [1.16.0](/news/2024/03/19/announcing-scalajs-1.16.0/)
910
- [1.15.0](/news/2023/12/29/announcing-scalajs-1.15.0/)
1011
- [1.14.0](/news/2023/09/25/announcing-scalajs-1.14.0/)

doc/project/webassembly.md

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
layout: doc
3+
title: Emitting JavaScript modules
4+
---
5+
6+
# Experimental WebAssembly backend
7+
8+
Since Scala.js 1.17.0, there is an *experimental* WebAssembly backend (Wasm for short).
9+
Under some conditions, it is designed to be a *drop-in* replacement for the usual JavaScript backend.
10+
11+
## Experimental status
12+
13+
Being experimental means that:
14+
15+
* The Wasm backend may be removed in a future *minor* version of Scala.js (or moved to a separate plugin).
16+
* Future versions of Scala.js may emit Wasm that requires *newer* versions of Wasm engines, dropping support for older engines.
17+
18+
However, we do *not* expect the the Wasm backend to be any less *correct* than the JS backend, modulo the limitations listed below.
19+
Feel free to report any issue you may experience with the same expectations as for the JS backend.
20+
21+
Non-functional aspects, notably performance and size of the generated code, may not be as good as the JS backend for now.
22+
The backend is also not incremental yet, which means a slower `fastLinkJS` in the development cycle.
23+
24+
## Requirements
25+
26+
The Wasm backend emits code with the following requirements:
27+
28+
* A JavaScript host (i.e., we do not currently generate standalone Wasm)
29+
* A Wasm engine with support for:
30+
* Wasm 3.0
31+
* Wasm GC
32+
* Exception handling, including the latest `exnref`-based variant
33+
* 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)
35+
36+
Supported engines include Node.js 22, Chrome and Firefox, all using some experimental flags (see below).
37+
38+
## Language semantics
39+
40+
The Wasm backend is nothing but an alternative backend for the Scala.js language.
41+
Its semantics are the same as Scala.js-on-JS, including JavaScript interoperability features, with one big limitation.
42+
43+
### Limitation: no `@JSExport` support
44+
45+
Due to the current feature set of Wasm, it is not possible to implement the semantics of `@JSExport`.
46+
Therefore, the Wasm backend currently *silently ignores* all `@JSExport` and `@JSExportAll` annotations (the latter being sugar for many `@JSExport`s).
47+
48+
This limitation has the following consequences:
49+
50+
* JavaScript code cannot call `@JSExport`ed methods of Scala classes.
51+
* Since that includes `toString()`, instances of Scala classes cannot be converted to string from JavaScript, including as part of string concatenation.
52+
53+
(String concatenation *in Scala.js code* is supported.)
54+
55+
### Limitation: no support for emitting multiple modules
56+
57+
The WebAssembly backend does not yet support emitting multiple modules.
58+
The module split style must be set to `ModuleSplitStyle.FewestModules` (which is the default).
59+
Moreover, the codebase must not contain any feature that require emitting multiple modules: `@JSExportToplevel` annotations with several module names, or `js.dynamicImport`.
60+
We expect to lift that limitation in the future.
61+
62+
## Minimal setup
63+
64+
The following sbt setup enables the Wasm backend and configures flags for Node.js 22.
65+
66+
{% highlight scala %}
67+
// Emit ES modules with the Wasm backend
68+
scalaJSLinkerConfig := {
69+
scalaJSLinkerConfig.value
70+
.withExperimentalUseWebAssembly(true) // use the Wasm backend
71+
.withModuleKind(ModuleKind.ESModule) // required by the Wasm backend
72+
},
73+
74+
// Configure Node.js (at least v22) to support the required Wasm features
75+
jsEnv := {
76+
val config = NodeJSEnv.Config()
77+
.withArgs(List(
78+
"--experimental-wasm-exnref", // required
79+
"--experimental-wasm-imported-strings", // optional (good for performance)
80+
"--turboshaft-wasm", // optional, but significantly increases stability
81+
))
82+
new NodeJSEnv(config)
83+
},
84+
{% endhighlight %}
85+
86+
Compared to a setup with ES modules with the JS backend, the above setup should be a drop-in replacement.
87+
The backend emits ES modules with the same layout and interface as those produced by the JS backend.
88+
89+
## Supported engines
90+
91+
Here are some engines known to support enough Wasm features.
92+
93+
### Node.js 22
94+
95+
As mentioned above, Node.js 22 and above requires the following flags:
96+
97+
* `--experimental-wasm-exnref`: required
98+
* `--experimental-wasm-imported-strings`: optional (good for performance)
99+
* `--turboshaft-wasm`: optional, bug significantly increases stability
100+
101+
### Chrome
102+
103+
In `chrome://flags/`, enable ["Experimental WebAssembly"](chrome://flags/#enable-experimental-webassembly-features).
104+
105+
### Firefox
106+
107+
In `about:config`, enable `javascript.options.wasm_exnref`.
108+
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)).
111+
112+
## Performance
113+
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.
116+
117+
Further work on improving performance is ongoing.
118+
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.
119+
120+
## Code size
121+
122+
The generated code size of the Wasm backend is currently about twice as big as the JS backend in `fullLink` mode.
123+
124+
We hope to significantly improve code size in the future by using [`wasm-opt`](https://github.com/WebAssembly/binaryen), a Wasm-to-Wasm optimizer.
125+
126+
## Implementation details
127+
128+
Looking for some implementation details of how we compile Scala.js to WebAssembly?
129+
Start with [the technical readme of the Wasm backend](https://github.com/scala-js/scala-js/tree/main/linker/shared/src/main/scala/org/scalajs/linker/backend/wasmemitter#readme).

0 commit comments

Comments
 (0)