Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ colors: #in hex code if not noted else

### VERSIONS ###
versions:
scalaJS: 1.9.0
scalaJS: 1.10.0
scalaJSBinary: 1
scalaJS06x: 0.6.33
scalaJS06xBinary: 0.6
Expand Down
136 changes: 136 additions & 0 deletions _posts/news/2022-04-04-announcing-scalajs-1.10.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
layout: post
title: Announcing Scala.js 1.10.0
category: news
tags: [releases]
permalink: /news/2022/04/04/announcing-scalajs-1.10.0/
---


We are pleased to announce the release of Scala.js 1.10.0!

**This release addresses a security vulnerability in `java.util.UUID.randomUUID()`.**
All versions of Scala.js prior to 1.10.0 are affected, including all 0.6.x versions.
We strongly recommend that all users upgrade to Scala.js 1.10.0 as soon as possible.
Read [the security advisory](https://github.com/scala-js/scala-js/security/advisories/GHSA-j2f9-w8wh-9ww4) for more details.
The issue was registered as [CVE-2022-28355](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-28355).

This release also brings a new mode of module splitting, which creates the smallest possible modules for a given list of packages, and the fewest possible modules for the rest.

Finally, it contains some minor optimizations, notably contributed by [@japgolly](https://github.com/japgolly).

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.9.x can be used with 1.10.0 without change.
* Despite being a minor release, 1.10.0 is forward binary compatible with 1.8.x and 1.9.x. It is *not* forward binary compatible with 1.7.x. Libraries compiled with 1.10.0 can be used with 1.8.x and 1.9.x but not 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.9.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.

## Fixes with compatibility concerns

### `java.util.UUID.randomUUID()` now depends on `java.security.SecureRandom`, which is provided by external libraries

Until Scala.js 1.9.x, `java.util.UUID.randomUUID()` was implemented using `java.util.Random`, which is not cryptographically secure.
This is therefore a security issue concerning `randomUUID()`.
To address that, Scala.js 1.10.x uses `java.security.SecureRandom` in the implementation of the latter instead.
`java.util.Random` remains unchanged, since it correctly implements its (deterministic) specification.

However, `SecureRandom` cannot be implemented on all JavaScript environments, as ECMAScript, per se, lacks any primitive to access a good source of entropy.
While it can be implemented on top of browser APIs or Node.js APIs, we have no decent fallback for other cases.
Not fully implementing it correctly for all platforms would go against our policy for the standard library, i.e., that linking code must be correct.
Therefore, Scala.js core does not provide any implementation of `java.security.SecureRandom`.

This means that code that was previously calling `java.util.UUID.randomUUID()` will now fail to link.
To preserve binary compatibility, we introduce two variants of a library that provides `java.security.SecureRandom`:

* [`scalajs-java-securerandom`](https://github.com/scala-js/scala-js-java-securerandom) provides a *correct*, cryptographically secure implementation of `java.security.SecureRandom`, but relies on the Node.js `crypto` module or the Web Crypto API `crypto.getRandomValues` to be available (e.g., in browsers).
* [`scalajs-fake-insecure-securerandom`](https://github.com/scala-js/scala-js-fake-insecure-securerandom) is a fake, *insecure* implementation that works in any ECMAScript environment. The only reason this exists is to unblock migration from Scala.js 1.9.x and earlier, in situations that require `randomUUID()` and can accept that they will be insecure.

Due to the changes in the core library, you may encounter linking errors when upgrading to Scala.js 1.10.0, such as:

{% highlight text %}
[error] Referring to non-existent class java.security.SecureRandom
[error] called from private java.util.UUID$.csprng$lzycompute()java.util.Random
[error] called from private java.util.UUID$.csprng()java.util.Random
[error] called from java.util.UUID$.randomUUID()java.util.UUID
[error] called from static java.util.UUID.randomUUID()java.util.UUID
[error] called from helloworld.HelloWorld$.main([java.lang.String)void
[error] called from static helloworld.HelloWorld.main([java.lang.String)void
[error] called from core module module initializers
[error] involving instantiated classes:
[error] java.util.UUID$
[error] helloworld.HelloWorld$
{% endhighlight %}

You may fix these linking errors by adding the following dependency to your `libraryDependencies`:

{% highlight scala %}
"org.scala-js" %%% "scalajs-java-securerandom" % "1.0.0"
{% endhighlight %}

As mentioned above, this will only work in environments that either provide the Web Crypto API, or Node.js' `crypto` module.

If you need random UUID generation in other environments, we encourage you to implement it yourselves.
Find out if your environment provides a source of cryptographically secure pseudo-random numbers.
If it does, you may want to use it to shim `crypto.getRandomValues`, and/or send a pull request to [`scalajs-java-securerandom`](https://github.com/scala-js/scala-js-java-securerandom).
Otherwise, replace calls to `randomUUID()` with another implementation, in a way that corresponds to your requirements in terms of security and collision likelihood.

If you have **no other choice**, depend on `scalajs-fake-insecure-securerandom` instead.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good that this cannot be copy pasted from the release notes.

As its name implies, this is an *insecure* implementation, and you should get rid of this dependency as soon as possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for completeness, a short paragraph about the optimizations you're teasing in the introduction would be nice I think.

## New module split style: `SmallModulesFor(packages)`

Prior to 1.10.0, Scala.js had two opposite module split styles:

* `FewestModules` (the default), which generates as few modules as possible, and
* `SmallestModules`, which generates as many small modules as possible (up to one per class).

As detailed in [#4327](https://github.com/scala-js/scala-js/issues/4327), those two extremes both suffered from issues for iterative development.

Scala.js 1.10.0 introduces a third style, `ModuleSplitStyle.SmallModulesFor(packages: List[String])`.
That style creates as many small modules as possibles for the classes in the listed packages (and their subpackages).
For all other classes, it generates as few modules as possible.
It is a combination of the previously existing styles.

The typical usage pattern is to list the application's packages as argument.
This way, often-changing classes receive independent, small modules, while the stable classes coming from libraries are bundled together as much as possible.
For example, if your application code lives in `com.example.myapp`, you could configure your module split style as:

{% highlight scala %}
import org.scalajs.linker.interface.ModuleSplitStyle
scalaJSLinkerConfig ~= (_.withModuleSplitStyle(ModuleSplitStyle.SmallModulesFor(List("com.example.myapp"))))
{% endhighlight %}

## Miscellaneous

### Optimizations

Scala.js 1.10.0 brings some new optimizations to the produced JavaScript files:

* Closures that do not need to capture anything produce simple lambdas, instead of redundant IIFEs (Immediately Invoked Function Expressions); contributed by [@japgolly](https://github.com/japgolly)
* `js.dynamicImport` blocks that do nothing but access a native JS class, object or member from a JS module avoid creating an intermediate Scala.js-generated module; instead they directly refer to the target JS module in the generated dynamic `import()` call.

## Bug fixes

Among others, the following bugs have been fixed in 1.10.0:

* [#4657](https://github.com/scala-js/scala-js/issues/4657) Scala.js should not provide a cryptographically insecure `UUID.randomUUID()` implementation

You can find the full list [on GitHub](https://github.com/scala-js/scala-js/issues?q=is%3Aissue+milestone%3Av1.10.0+is%3Aclosed).
9 changes: 9 additions & 0 deletions doc/all-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ title: All previous versions of the Scala.js API

## All previous versions of the API

### Scala.js 1.10.0
* [1.10.0 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.10.0/scala/scalajs/js/index.html)
* [1.10.0 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.10.0/)
* [1.10.0 scalajs-ir]({{ site.production_url }}/api/scalajs-ir/1.10.0/org/scalajs/ir/index.html)
* [1.10.0 scalajs-linker-interface]({{ site.production_url }}/api/scalajs-linker-interface/1.10.0/org/scalajs/linker/interface/index.html) ([Scala.js version]({{ site.production_url }}/api/scalajs-linker-interface-js/1.10.0/org/scalajs/linker/interface/index.html))
* [1.10.0 scalajs-linker]({{ site.production_url }}/api/scalajs-linker/1.10.0/org/scalajs/linker/index.html) ([Scala.js version]({{ site.production_url }}/api/scalajs-linker-js/1.10.0/org/scalajs/linker/index.html))
* [1.10.0 scalajs-test-adapter]({{ site.production_url }}/api/scalajs-sbt-test-adapter/1.10.0/org/scalajs/testing/adapter/index.html)
* [1.10.0 sbt-scalajs]({{ site.production_url }}/api/sbt-scalajs/1.10.0/#org.scalajs.sbtplugin.package)

### Scala.js 1.9.0
* [1.9.0 scalajs-library]({{ site.production_url }}/api/scalajs-library/1.9.0/scala/scalajs/js/index.html)
* [1.9.0 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/1.9.0/)
Expand Down
1 change: 1 addition & 0 deletions doc/internals/version-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ title: Version history

## Version history of Scala.js

- [1.10.0](/news/2022/04/04/announcing-scalajs-1.10.0/)
- [1.9.0](/news/2022/02/14/announcing-scalajs-1.9.0/)
- [1.8.0](/news/2021/12/10/announcing-scalajs-1.8.0/)
- [1.7.1](/news/2021/10/07/announcing-scalajs-1.7.1/)
Expand Down
19 changes: 17 additions & 2 deletions doc/project/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ The Scala.js linker can split a full Scala.js application automatically based on

* Entry points (top-level exports and module initializers)
* Dynamic import boundaries (calls to `js.dynamicImport`)
* The split style (fewest modules or smallest modules)
* The split style (fewest modules, smallest modules, or a combination thereof)

### Entry Points

Expand Down Expand Up @@ -224,7 +224,7 @@ import org.scalajs.linker.interface.ModuleSplitStyle
scalaJSLinkerConfig ~= (_.withModuleSplitStyle(ModuleSplitStyle.SmallestModules))
{% endhighlight %}

There are currently two module split styles: `FewestModules` and `SmallestModules`.
There are currently three module split styles: `FewestModules`, `SmallestModules` and `SmallModulesFor(packages)`.

#### `FewestModules`

Expand Down Expand Up @@ -264,6 +264,21 @@ In the dynamic import example, this would generate:
Generating many small modules can be useful if the output of Scala.js is further processed by downstream JavaScript bundling tools.
In incremental builds, they will not need to reprocess the entire Scala.js-generated .js file, but instead only the small modules that have changed.

#### `SmallModulesFor(packages: List[String])`

Create modules that are as small as possible for the classes in the specified `packages` (and their subpackages).
For all other classes, create as few modules as possible.
This is a combination of the two other split styles.

The typical usage pattern is to list the application's packages as argument.
This way, often-changing classes receive independent, small modules, while the stable classes coming from libraries are bundled together as much as possible.
For example, if your application code lives in `my.app`, you could configure your module split style as:

{% highlight scala %}
import org.scalajs.linker.interface.ModuleSplitStyle
scalaJSLinkerConfig ~= (_.withModuleSplitStyle(ModuleSplitStyle.SmallModulesFor(List("my.app"))))
{% endhighlight %}

### Splitting Granularity

Scala.js only splits modules along class boundaries.
Expand Down