GistTree.Com
Entertainment at it's peak. The news is by your side.

Scala.js 1.3.0

0

Oct 16, 2020.

We’re angry to yelp the originate of Scala.js 1.3.0!

This originate brings one in every of basically the most awaited functions for Scala.js: module splitting reinforce!
It is now that you just might perhaps well seemingly imagine to split the generated .js file into more than one modules, to optimize get hang of dimension in multi-web page applications or tempo up incremental bundling.

To boot, this originate incorporates a gaggle of latest systems and classes in the JDK implementation, amongst which the higher-recount systems of the java.util collections, and the locale-sensitive overloads of String.toLowerCase, toUpperCase and structure.

Be taught on for more particulars.

Getting started

While you might perhaps well seemingly seemingly be new to Scala.js, head over to the educational.

While you want motivate with the rest associated to Scala.js, you might perhaps well seemingly score our community on Gitter and on Stack Overflow.

Malicious program reports might perhaps well perhaps be filed on GitHub.

Commence notes

If upgrading from Scala.js 0.6.x, be definite to study the originate notes of Scala.js 1.0.0 first, as they hang a host of noteworthy info, in conjunction with breaking adjustments.

Right here is a minor originate:

  • It is backward binary smartly righteous with all earlier versions in the 1.x sequence: libraries compiled with 1.0.x by 1.2.x might perhaps well perhaps be feeble with 1.3.0 with out change.
  • It is no longer ahead binary smartly righteous with 1.2.x: libraries compiled with 1.3.0 can no longer be feeble with 1.2.x or earlier.
  • It is no longer entirely backward provide smartly righteous: it’s no longer assured that a codebase will assemble as is when upgrading from 1.2.x (in particular in the presence of -Xfatal-warnings).

As a reminder, libraries compiled with 0.6.x can no longer be feeble with Scala.js 1.x; they must peaceable be republished with 1.x first.

Known provide breaking adjustments

js.Promise.then

The consequence form of js.Promise.then used to be modified from js.Thenable to js.Promise.
Right here is unlikely to motive any discipline most regularly, since js.Promise extends js.Thenable.
It might perhaps well perhaps motive compilation errors in some uncommon cases as a consequence of kind inference, or in case you account for a subclass of js.Promise.

Module splitting

Quickstart

First, rather then fastOptJS / fullOptJS, use fastLinkJS / fullLinkJS.
The outputs of these instructions might perhaps well be in a subdirectory cherish mission/aim/scala-2.13/mission-fastopt/, rather then as a single file .../scala-2.13/mission-fastopt.js.
It is probably you’ll be in a position to then affect a quantity of entry aspects and/or generate as many miniature modules as that you just might perhaps well seemingly imagine the use of the next setups.

For varied entry aspects

House the moduleID for your top-level exports and/or module initializers explicitly (a module initializer is in actuality a vital design for the module).
The default moduleID is "vital".

@JSExportTopLevel(name = "startAdmin", moduleID = "admin")
def startAdmin():  Unit = ???
import org.scalajs.linker.interface.ModuleInitializer
scalaJSModuleInitializers in Bring collectively += {
  ModuleInitializer.mainMethod("my.app.admin.Predominant", "vital")
    .withModuleID("admin")
}

All the pieces with the same moduleID will creep into the same entry point module.

For many miniature modules

By default, module splitting genereates as few modules as that you just might perhaps well seemingly imagine.
In some cases, generates as many modules as miniature as that you just might perhaps well seemingly imagine is preferable, which is ready to be configured with:

import org.scalajs.linker.interface.ModuleSplitStyle
scalaJSLinkerConfig ~= (_.withModuleSplitStyle(ModuleSplitStyle.SmallestModules))

What’s Module Splitting?

With module splitting, the Scala.js linker splits its output into more than one JavaScript modules (i.e. info).
Both ES6 modules (ModuleKind.ESModule) and CommonJS modules (ModuleKind.CommonJSModule) are supported.

There are a lot of reasons to split JavaScript output into more than one info:

  • Share code between a quantity of parts of an software (e.g. user/admin interfaces).
  • Fabricate smaller info to gash adjustments for incremental downstream tooling.
  • Load parts of a huge app progressively (no longer supported yet, look #4201).

The Scala.js linker can split a paunchy Scala.js software automatically in response to:

  • The entry aspects (top-level exports and module initializers)
  • The split style (fewest modules or smallest modules)

Entry Facets

Scala.js-generated code has two a quantity of kinds of entry aspects:

  • High level exports: Definitions to be known as from exterior JS code.
  • Module initializers: Code that gets accomplished when a module is imported (i.e., vital systems).

The Scala.js linker determines crew entry aspects into a quantity of (public) modules by the use of their assigned moduleID.
The default moduleID is "vital".

The moduleID of a top-level export might perhaps well perhaps be specified the use of the moduleID parameter.
The moduleID of a ModuleInitializer might perhaps well perhaps be specified by the withModuleID design.

Instance:

Order you’ve got the next App.scala and affect.sbt:

equipment my.app

import scala.collection.mutable
import scala.scalajs.js.annotation._

// Separate objects to enable for splitting.

object AppA {
  @JSExportTopLevel(name = "open", moduleID = "a")
  def a():  Unit = println("hi there from a")
}

object AppB {
  non-public val x = mutable.House.empty[String]

  @JSExportTopLevel(name = "open", moduleID = "b")
  def b():  Unit = {
    println("hi there from b")
    println(x)
  }

  def vital():  Unit = x.add("one thing")
}
import org.scalajs.linker.interface.ModuleInitializer

scalaJSModuleInitializers in Bring collectively += {
  ModuleInitializer.mainMethod("my.app.AppB", "vital").withModuleID("b")
}

This might perhaps well generate two public modules a.js / b.js.
a.js will export a contrivance named open that calls AppA.a.
b.js will export a contrivance named open that calls AppB.b.
Further, importing b.js will name AppB.vital.

Show screen that there is now not any public module vital.js, as a consequence of there is now not any entry point the use of the default moduleID.

Module Spoil up Kinds

To this point, now we hang considered how public modules might perhaps well perhaps be configured.
Per the general public modules, the Scala.js linker generates inside modules for the shared code between the general public modules.
In inequity to public modules, inside modules is no longer going to be imported by user code.
Doing so is undefined behavior and discipline to change at any time.

The linker generates inside modules automatically in response to the dependency graph of the code and moduleSplitStyle.
It is probably you’ll be in a position to change it as follows:

import org.scalajs.linker.interface.ModuleSplitStyle
scalaJSLinkerConfig ~= (_.withModuleSplitStyle(ModuleSplitStyle.SmallestModules))

There are for the time being two module split kinds: FewestModules and SmallestModules.

FewestModules

Fabricate as few modules as that you just might perhaps well seemingly imagine with out in conjunction with useless code.
Right here is the default.

In the instance above, this would generate:

  • a.js: public module, containing AppA and the export of open.
  • b.js: public module, containing AppB, mutable.House, the export of open and the choice to AppB.vital
  • a-b.js: inside module, Scala.js core and the implementation of println.

This moreover works for higher than two public modules, developing intermediate shared (inside) modules as most indispensable.

SmallestModules

Fabricate modules which might perhaps well perhaps seemingly be as miniature as that you just might perhaps well seemingly imagine.
The smallest unit of splitting is a Scala class.

Utilizing this mode in overall finally ends up in an inside module per class aside from for classes that hang round dependencies: these are assign into the same module to lead definite of a round module dependency graph.

In the instance above, this would generate:

  • a.js: public module, containing the export of open.
  • b.js: public module, containing the export of open and the choice to AppB.vital
  • many inside miniature modules (~50 for this instance), approximately one per class.

Generating many miniature modules might perhaps well perhaps be functional if the output of Scala.js is extra processed by downstream JavaScript bundling instruments.
In incremental builds, they is no longer going to must reprocess the total Scala.js-generated .js file, however instead most attention-grabbing the miniature modules that hang modified.

Linker Output

With module splitting, the location of information created by the linker is no longer known at invocation time.
To spice up this new requirement, the linker output is configured as follows:

  • A directory where all info creep: scalaJSLinkerOutputDirectory
  • Patterns for output file names: outputPatterns on scalaJSLinkerConfig.

Both of these hang affordable defaults and in most cases attain no longer must peaceable be modified.
The exception is file extensions.
If it’s needed to affect *.mjs info for Node.js, use:

import org.scalajs.linker.interface.OutputPatterns
scalaJSLinkerConfig ~= (_.withOutputPatterns(OutputPatterns.fromJSFile("%s.mjs")))

In mumble to construct sense of the information in the directory, linking returns a Memoir itemizing the general public modules and their file names.

sbt backwards compatibility

For the reason that fastOptJS / fullOptJS keys/projects mediate that linking will affect a single file, we needed to introduce two new keys/projects for linking: fastLinkJS / fullLinkJS.
These projects return the Memoir rather then an particular person File.

In mumble to be sure backwards compatibility, the fastOptJS / fullOptJS projects now invoke fastLinkJS / fullLinkJS respectively and copy the produced info to their aim discipline.
On the different hand, this most attention-grabbing works if the linker produced a single public module.
So with staunch module splitting, fastOptJS / fullOptJS will fail.

The flee and take a look at projects now rely on fastLinkJS / fullLinkJS (counting on the scalaJSStage) and cargo the general public module with moduleID="vital" (they fail if no such module exists).
This would now not change their behavior for present builds however permits working and testing with module splitting enabled.

Miscellaneous

Unique JDK APIs

This originate incorporates a vital quantity of components in the JDK APIs that we reinforce, notably thanks to contributions by @er1c, @ekrich and @exoego.

Unique interface definitions in java.util.aim.*:

  • BiConsumer, Seller, Characteristic, BiFunction, UnaryOperator, BinaryOperator and BiPredicate
  • Specializations of Seller, and Predicate

Unique classes:

  • java.lang.Character.UnicodeBlock
  • java.util.StringTokenizer
  • java.io.CharArrayWriter
  • java.io.CharArrayReader

Systems with fixed behavior to alter to the JDK specification:

  • In java.lang.Character:
    • toLowerCase(Char) and toUpperCase(Char)
  • In java.lang.String:
    • compareTo
    • equalsIgnoreCase
    • compareToIgnoreCase

Unique systems in present classes and interfaces (some are most attention-grabbing on hand when compiling on a novel ample JDK):

  • In java.lang.String:
    • repeat (JDK 11+)
  • In java.lang.Character:
    • toLowerCase(codePoint: Int) and toUpperCase(codePoint: Int)
    • toTitleCase(ch: Char) and toTitleCase(codePoint: Int)
    • highSurrogate and lowSurrogate
    • hashCode(ch: Char)
    • reverseBytes(ch: Char)
    • toString(codePoint: Int) (JDK 11+)
  • Default systems in java.util.Iterator:
    • take away
    • forEachRemaining
  • Default systems in java.util.Checklist:
    • kind
    • replaceAll
  • Default systems in java.util.Map:
    • getOrDefault
    • forEach
    • replaceAll
    • putIfAbsent
    • take away(key, worth)
    • replace(key, oldValue, newValue)
    • replace(key, worth)
    • computeIfAbsent
    • computeIfPresent
    • compute
    • merge
  • In java.util.Elective:
    • isEmpty (JDK 11+)
    • ifPresent
    • ifPresentOrElse (JDK 9+)
    • filter
    • design
    • flatMap
    • or (JDK 9+)
    • orElse
    • orElseGet
    • orElseThrow(Seller)
    • orElseThrow() (JDK 10+)
  • In java.util.Properties:
    • load
    • save
    • retailer
    • checklist

In the raze, the next Locale-sensitive systems were added, though they’ll most attention-grabbing transitively link if reinforce for java.util.Locale APIs is enabled the use of scala-java-locales:

  • In java.lang.String:
    • toLowerCase(Locale) and toUpperCase(Locale)
    • structure(Locale, ...)
  • In java.util.Formatter:
    • constructors with a Locale parameter
    • structure(Locale, ...)

Speaking of locales, now we hang somewhat modified the definition of the default locale of Scala.js.
Previously, it used to be specified as en-US.
Initiating from Scala.js 1.3.0, it’s specified as Locale.ROOT.
This change makes no inequity by behavior (most attention-grabbing by “spirit”), since your complete systems that were previously implemented in Scala.js hang the same behavior for ROOT than for en-US.

Show screen that it’s no longer that you just might perhaps well seemingly imagine to change the default locale, as systems that attain no longer take Locale arguments are tense-coded for the behavior of Locale.ROOT (even when scala-java-locales is feeble).
To score locale-sensitive behavior, the overloads taking bid Locale arguments must peaceable be feeble.

Malicious program fixes

Amongst others, the next bugs were fixed in 1.3.0:

  • #4195 LinkedHashMap iteration no longer empty after definite
  • #4188 Fabricate js.Promise.then return js.Promise rather then js.Thenable
  • #4203 Matcher.discipline no longer mutating the matcher
  • #4204 Matcher.open()/close() give inaccurate results
  • #4210 java.util.Date.from(Fast) throws the hurry more or much less exception

It is probably you’ll be in a position to score the paunchy checklist on GitHub.

Read More

Leave A Reply

Your email address will not be published.