-
Notifications
You must be signed in to change notification settings - Fork 146
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #646 from sjrd/scalajs-1.17.0
Announcing Scala.js 1.17.0, and add doc for the Wasm backend.
- Loading branch information
Showing
8 changed files
with
287 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,3 +33,4 @@ | |
- 1.12.0 | ||
- 1.13.0 | ||
- 1.16.0 | ||
- 1.17.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
--- | ||
layout: post | ||
title: Announcing Scala.js 1.17.0 | ||
category: news | ||
tags: [releases] | ||
permalink: /news/2024/09/28/announcing-scalajs-1.17.0/ | ||
--- | ||
|
||
|
||
We are excited to announce the release of Scala.js 1.17.0! | ||
|
||
This release comes with a brand new, shiny, experimental WebAssembly backend. | ||
You can now, under certain conditions, take your existing Scala.js application and compile it to WebAssembly instead. | ||
|
||
There were also some bug fixes. | ||
Despite the abnormally long release cycle (v1.16.0 was released 6 months ago), the only external bug report came in 3 weeks ago. | ||
As far as we can tell, nobody was blocked waiting for a bugfix for this long. | ||
|
||
Read on for more details. | ||
|
||
<!--more--> | ||
|
||
## Getting started | ||
|
||
If you are new to Scala.js, head over to [the tutorial]({{ BASE_PATH }}/tutorial/). | ||
|
||
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). | ||
|
||
Bug reports can be filed [on GitHub](https://github.com/scala-js/scala-js/issues). | ||
|
||
## Release notes | ||
|
||
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. | ||
|
||
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.16.x can be used with 1.17.0 without change. | ||
* 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. | ||
* 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`). | ||
|
||
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. | ||
|
||
## Enhancements with compatibility concerns | ||
|
||
### Changes to the IR and linker APIs | ||
|
||
For tooling authors who directly manipulate the IR and linker APIs, there have been some breaking changes in that area. | ||
This is in line with our version policy for the linker APIs. | ||
|
||
The most likely changes you may hit are: | ||
|
||
* The reference types in the IR, such as `ClassType` and `ArrayType`, now have a `nullable: Boolean` flag. | ||
There is also a new type `AnyNotNullType`. | ||
* The `NewArray` node does not accept multiple dimensions anymore. | ||
If you want to emit a multi-dimensional array creation, emit a call to `java.lang.reflect.Array.newInstance` instead. | ||
|
||
## Enhancements | ||
|
||
### Experimental WebAssembly backend | ||
|
||
Starting with this release, Scala.js ships with an *experimental* WebAssembly backend. | ||
Under some conditions, you may use it as a drop-in replacement for the usual JavaScript backend. | ||
|
||
#### Minimal setup | ||
|
||
You can set it up as follows: | ||
|
||
{% highlight scala %} | ||
// Emit ES modules with the Wasm backend | ||
scalaJSLinkerConfig := { | ||
scalaJSLinkerConfig.value | ||
.withExperimentalUseWebAssembly(true) // use the Wasm backend | ||
.withModuleKind(ModuleKind.ESModule) // required by the Wasm backend | ||
}, | ||
|
||
// Configure Node.js (at least v22) to support the required Wasm features | ||
jsEnv := { | ||
val config = NodeJSEnv.Config() | ||
.withArgs(List( | ||
"--experimental-wasm-exnref", // required | ||
"--experimental-wasm-imported-strings", // optional (good for performance) | ||
"--turboshaft-wasm", // optional, but significantly increases stability | ||
)) | ||
new NodeJSEnv(config) | ||
}, | ||
{% endhighlight %} | ||
|
||
Make sure `node -v` reports at least v22.0.0. | ||
If not, install a newer version. | ||
|
||
You are then set up to `run` and `test` your codebase with the WebAssembly backend from sbt. | ||
|
||
#### Limitations | ||
|
||
Note that the WebAssembly backend *silently ignores* all the `@JSExport` and `@JSExportAll` annotations. | ||
It is never possible to call methods of Scala classes from JavaScript, which includes `toString()`, even through string concatenation. | ||
JavaScript code may still call all public members of JavaScript classes (classes that inherit from `js.Any`). | ||
Moreover, `@JSExportTopLevel` is supported, as well as all the other `@JS...` annotations. | ||
|
||
The WebAssembly backend does not yet support emitting multiple modules. | ||
The module split style must be set to `ModuleSplitStyle.FewestModules` (which is the default). | ||
Moreover, the codebase must not contain any feature that require emitting multiple modules: `@JSExportToplevel` annotations with several module names, or `js.dynamicImport`. | ||
We expect to lift that limitation in the future. | ||
|
||
Other than that, we expect the WebAssembly backend to support all Scala.js semantics. | ||
Please report any issues you may find. | ||
|
||
Stack traces are currently suboptimal. | ||
|
||
#### Use in browsers | ||
|
||
If you want to use it in browsers, you will need: | ||
|
||
* For Firefox: in `about:config`, enable `javascript.options.wasm_exnref`. | ||
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)) | ||
* For Chrome: in `chrome://flags/`, enable ["Experimental WebAssembly"](chrome://flags/#enable-experimental-webassembly-features). | ||
|
||
#### More information | ||
|
||
Read more detailed information about [the WebAssembly backend in the docs]({{ BASE_PATH }}/doc/project/webassembly.html). | ||
|
||
## Miscellaneous | ||
|
||
### New JDK APIs | ||
|
||
This release adds support for the following JDK methods: | ||
|
||
* In `java.lang.Character`: `codePointAt`, `codePointBefore`, `codePointCount` and `offsetByCodePoints` | ||
* In `java.util.concurrent.ConcurrentHashMap`: `forEach`, `forEachKey` and `forEachValue` | ||
|
||
### Unicode version | ||
|
||
The Unicode database used by the methods of `java.lang.Character` was updated to Unicode v15.0. | ||
|
||
## Bug fixes | ||
|
||
Among others, the following bugs have been fixed in 1.17.0: | ||
|
||
* [#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. | ||
* [#5044](https://github.com/scala-js/scala-js/issues/5044) `jl.reflect.Array.newInstance()` does not throw the `IllegalArgumentException`s it is supposed to. | ||
|
||
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). |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
--- | ||
layout: doc | ||
title: Emitting JavaScript modules | ||
--- | ||
|
||
# Experimental WebAssembly backend | ||
|
||
Since Scala.js 1.17.0, there is an *experimental* WebAssembly backend (Wasm for short). | ||
Under some conditions, it is designed to be a *drop-in* replacement for the usual JavaScript backend. | ||
|
||
## Experimental status | ||
|
||
Being experimental means that: | ||
|
||
* The Wasm backend may be removed in a future *minor* version of Scala.js (or moved to a separate plugin). | ||
* Future versions of Scala.js may emit Wasm that requires *newer* versions of Wasm engines, dropping support for older engines. | ||
|
||
However, we do *not* expect the the Wasm backend to be any less *correct* than the JS backend, modulo the limitations listed below. | ||
Feel free to report any issue you may experience with the same expectations as for the JS backend. | ||
|
||
Non-functional aspects, notably performance and size of the generated code, may not be as good as the JS backend for now. | ||
The backend is also not incremental yet, which means a slower `fastLinkJS` in the development cycle. | ||
|
||
## Requirements | ||
|
||
The Wasm backend emits code with the following requirements: | ||
|
||
* A JavaScript host (i.e., we do not currently generate standalone Wasm) | ||
* A Wasm engine with support for: | ||
* Wasm 3.0 | ||
* Wasm GC | ||
* Exception handling, including the latest `exnref`-based variant | ||
* The `ESModule` module kind (see [emitting modules](./module.html)) | ||
* Strict floats (which is the default since Scala.js 1.9.0; non-strict floats are deprecated) | ||
|
||
Supported engines include Node.js 22, Chrome and Firefox, all using some experimental flags (see below). | ||
|
||
## Language semantics | ||
|
||
The Wasm backend is nothing but an alternative backend for the Scala.js language. | ||
Its semantics are the same as Scala.js-on-JS, including JavaScript interoperability features, with one big limitation. | ||
|
||
### Limitation: no `@JSExport` support | ||
|
||
Due to the current feature set of Wasm, it is not possible to implement the semantics of `@JSExport`. | ||
Therefore, the Wasm backend currently *silently ignores* all `@JSExport` and `@JSExportAll` annotations (the latter being sugar for many `@JSExport`s). | ||
|
||
This limitation has the following consequences: | ||
|
||
* JavaScript code cannot call `@JSExport`ed methods of Scala classes. | ||
* Since that includes `toString()`, instances of Scala classes cannot be converted to string from JavaScript, including as part of string concatenation. | ||
|
||
(String concatenation *in Scala.js code* is supported.) | ||
|
||
### Limitation: no support for emitting multiple modules | ||
|
||
The WebAssembly backend does not yet support emitting multiple modules. | ||
The module split style must be set to `ModuleSplitStyle.FewestModules` (which is the default). | ||
Moreover, the codebase must not contain any feature that require emitting multiple modules: `@JSExportToplevel` annotations with several module names, or `js.dynamicImport`. | ||
We expect to lift that limitation in the future. | ||
|
||
## Minimal setup | ||
|
||
The following sbt setup enables the Wasm backend and configures flags for Node.js 22. | ||
|
||
{% highlight scala %} | ||
// Emit ES modules with the Wasm backend | ||
scalaJSLinkerConfig := { | ||
scalaJSLinkerConfig.value | ||
.withExperimentalUseWebAssembly(true) // use the Wasm backend | ||
.withModuleKind(ModuleKind.ESModule) // required by the Wasm backend | ||
}, | ||
|
||
// Configure Node.js (at least v22) to support the required Wasm features | ||
jsEnv := { | ||
val config = NodeJSEnv.Config() | ||
.withArgs(List( | ||
"--experimental-wasm-exnref", // required | ||
"--experimental-wasm-imported-strings", // optional (good for performance) | ||
"--turboshaft-wasm", // optional, but significantly increases stability | ||
)) | ||
new NodeJSEnv(config) | ||
}, | ||
{% endhighlight %} | ||
|
||
Compared to a setup with ES modules with the JS backend, the above setup should be a drop-in replacement. | ||
The backend emits ES modules with the same layout and interface as those produced by the JS backend. | ||
|
||
## Supported engines | ||
|
||
Here are some engines known to support enough Wasm features. | ||
|
||
### Node.js 22 | ||
|
||
As mentioned above, Node.js 22 and above requires the following flags: | ||
|
||
* `--experimental-wasm-exnref`: required | ||
* `--experimental-wasm-imported-strings`: optional (good for performance) | ||
* `--turboshaft-wasm`: optional, bug significantly increases stability | ||
|
||
### Chrome | ||
|
||
In `chrome://flags/`, enable ["Experimental WebAssembly"](chrome://flags/#enable-experimental-webassembly-features). | ||
|
||
### Firefox | ||
|
||
In `about:config`, enable `javascript.options.wasm_exnref`. | ||
|
||
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)). | ||
|
||
## Performance | ||
|
||
Performance of the generated code is currently a hit-or-miss. | ||
Depending on the codebase, it may be several times faster or slower than the JS backend. | ||
|
||
Further work on improving performance is ongoing. | ||
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. | ||
|
||
## Code size | ||
|
||
The generated code size of the Wasm backend is currently about twice as big as the JS backend in `fullLink` mode. | ||
|
||
We hope to significantly improve code size in the future by using [`wasm-opt`](https://github.com/WebAssembly/binaryen), a Wasm-to-Wasm optimizer. | ||
|
||
## Implementation details | ||
|
||
Looking for some implementation details of how we compile Scala.js to WebAssembly? | ||
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). |