From 08d2baf9cf5af691ea9cec813f2eaaf3faaf3386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Sun, 22 Sep 2024 13:43:11 +0200 Subject: [PATCH] Announcing Scala.js 1.17.0, and add doc for the Wasm backend. --- _config.yml | 2 +- _data/doc.yml | 2 + _data/library/versions.yml | 1 + .../2024-09-28-announcing-scalajs-1.17.0.md | 142 ++++++++++++++++++ assets/badges/scalajs-1.17.0.svg | 1 + doc/all-api.md | 10 ++ doc/internals/version-history.md | 1 + doc/project/webassembly.md | 129 ++++++++++++++++ 8 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 _posts/news/2024-09-28-announcing-scalajs-1.17.0.md create mode 100644 assets/badges/scalajs-1.17.0.svg create mode 100644 doc/project/webassembly.md diff --git a/_config.yml b/_config.yml index 271a476..2f62822 100644 --- a/_config.yml +++ b/_config.yml @@ -64,7 +64,7 @@ colors: #in hex code if not noted else ### VERSIONS ### versions: - scalaJS: 1.16.0 + scalaJS: 1.17.0 scalaJSBinary: 1 scalaJS06x: 0.6.33 scalaJS06xBinary: 0.6 diff --git a/_data/doc.yml b/_data/doc.yml index 06066d9..5d9501a 100644 --- a/_data/doc.yml +++ b/_data/doc.yml @@ -29,6 +29,8 @@ url: /doc/project/module.html - text: JavaScript Environments url: /doc/project/js-environments.html + - text: Emitting WebAssembly + url: /doc/project/webassembly.html - text: Cross-building url: /doc/project/cross-build.html - text: Testing diff --git a/_data/library/versions.yml b/_data/library/versions.yml index 47db79b..5029c60 100644 --- a/_data/library/versions.yml +++ b/_data/library/versions.yml @@ -33,3 +33,4 @@ - 1.12.0 - 1.13.0 - 1.16.0 +- 1.17.0 diff --git a/_posts/news/2024-09-28-announcing-scalajs-1.17.0.md b/_posts/news/2024-09-28-announcing-scalajs-1.17.0.md new file mode 100644 index 0000000..3792f6a --- /dev/null +++ b/_posts/news/2024-09-28-announcing-scalajs-1.17.0.md @@ -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. + + + +## 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). diff --git a/assets/badges/scalajs-1.17.0.svg b/assets/badges/scalajs-1.17.0.svg new file mode 100644 index 0000000..72bcaf7 --- /dev/null +++ b/assets/badges/scalajs-1.17.0.svg @@ -0,0 +1 @@ +scala.js: 1.17.0+scala.js1.17.0+ diff --git a/doc/all-api.md b/doc/all-api.md index 5de509d..f7044ca 100644 --- a/doc/all-api.md +++ b/doc/all-api.md @@ -5,6 +5,16 @@ title: All previous versions of the Scala.js API ## All previous versions of the API +### Scala.js 1.17.0 +* [1.17.0 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.17.0/scala/scalajs/js/index.html) +* [1.17.0 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.17.0/) +* [1.17.0 scalajs-javalib-intf]({{ site.production_url }}/api/scalajs-javalib-intf/1.17.0/) +* [1.17.0 scalajs-ir]({{ site.production_url }}/api/scalajs-ir/1.17.0/org/scalajs/ir/index.html) +* [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)) +* [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)) +* [1.17.0 scalajs-test-adapter]({{ site.production_url }}/api/scalajs-sbt-test-adapter/1.17.0/org/scalajs/testing/adapter/index.html) +* [1.17.0 sbt-scalajs]({{ site.production_url }}/api/sbt-scalajs/1.17.0/#org.scalajs.sbtplugin.package) + ### Scala.js 1.16.0 * [1.16.0 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.16.0/scala/scalajs/js/index.html) * [1.16.0 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.16.0/) diff --git a/doc/internals/version-history.md b/doc/internals/version-history.md index 0f0e972..f2e0da6 100644 --- a/doc/internals/version-history.md +++ b/doc/internals/version-history.md @@ -5,6 +5,7 @@ title: Version history ## Version history of Scala.js +- [1.17.0](/news/2024/09/28/announcing-scalajs-1.17.0/) - [1.16.0](/news/2024/03/19/announcing-scalajs-1.16.0/) - [1.15.0](/news/2023/12/29/announcing-scalajs-1.15.0/) - [1.14.0](/news/2023/09/25/announcing-scalajs-1.14.0/) diff --git a/doc/project/webassembly.md b/doc/project/webassembly.md new file mode 100644 index 0000000..0d56f5a --- /dev/null +++ b/doc/project/webassembly.md @@ -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).