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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions doc/project/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,12 @@ This will generate `.sjsir` and `.class` files for each class in your project (j

The `.sjsir` files are an internal representation which can be linked to actual JavaScript code as will be explained shortly.

## Produce one JavaScript file

To produce a proper JavaScript file from your code, you need to call the linker:

sbt> fastOptJS

This will perform fast Scala.js-specific optimizations and write the resulting code to a single JavaScript file. You can now use this JavaScript file in your HTML page or in whatever way you like. The resulting file in the target folder will have the suffix `-fastopt.js`.

## Actually *do* something

By default, Scala.js produces "libraries", that do not actually *do* anything when their `-fastopt.js` file is loaded.
To make it do something, you need a top-level object with a `main` method:
To produce JavaScript code, we need to either export something (e.g. a method or a class) or do something when the JavaScript code is loaded.
Otherwise, Scala.js will not produce any JavaScript code (because to do nothing, there is no need for any code).

To do something when your code is loaded, you need a top-level object with a `main` method (to export something, see [Export Scala.js APIs to JavaScript]({{ site.production_url }}/doc/interoperability/export-to-javascript.html)).

{% highlight scala %}
object Main {
Expand All @@ -39,7 +33,6 @@ scalaJSUseMainModuleInitializer := true
{% endhighlight %}

Just like in a JVM project, sbt will automatically detect the object with a `main(Array[String]): Unit` method, and use it as the main method of the application.
Now, the .js file produced by `fastOptJS` will print `"Hello world!"`.

Note that this will require that there is a *unique* such object or that the one to use be explicitly set with `mainClass in Compile := Some(<name>)`.
If you explicitly set `mainClass`, note that it needs to be set on a per-configuration basis (i.e. the part `in Compile` is essential, otherwise the setting will be ignored). For further information see the Stack Overflow entry ['How to set mainClass in ScalaJS build.sbt?'](http://stackoverflow.com/questions/34965072/how-to-set-mainclass-in-scalajs-build-sbt) (specific to Scala.js) and the Stack Overflow entry ['How to set main class in build?'](http://stackoverflow.com/questions/6467423/how-to-set-main-class-in-build) (not specific to Scala.js).
Expand All @@ -49,14 +42,29 @@ Since 0.6.18, any object with a standard `main` method will be recognized.
`js.JSApp` is now deprecated.
See [the Scaladoc of `js.JSApp`]({{ site.production_url }}/api/scalajs-library/0.6.20/#scala.scalajs.js.JSApp) for migration tips.

## Produce JavaScript code

To produce JavaScript code from your Scala code, you need to call the linker:

sbt> fastLinkJS

This will perform fast Scala.js-specific optimizations and write the resulting JavaScript code to a directory.
With the default options, it will write a single file `main.js`.
You can now use this JavaScript file in your HTML page or in whatever way you like.
The resulting directory in the target folder will have the suffix `-fastopt`.

Loading the `main.js` file produced by `fastLinkJS` will print `"Hello world!"`.

**Note for Scala.js 1.2.x and earlier:** in Scala.js 1.2.x and earlier, we used `fastOptJS` instead of `fastLinkJS`, which always produces a single file with the suffix `-fastopt.js` directly in the target directory.

## Running in the console

You can run a Scala.js application (that has `scalaJSUseMainModuleInitializer` set to `true`) by using the `run` task:

sbt> run

This will run the `-fastopt.js` file right inside of your sbt console.
By default, the file is run with [Node.js](http://nodejs.org/), which you need to install separately.
This will run the `main.js` file right inside of your sbt console.
By default, the file is run with [Node.js](https://nodejs.org/), which you need to install separately.

**Scala.js 0.6.x only:** If your application or one of its libraries requires a DOM (which can be specified with `jsDependencies += RuntimeDOM`), you will also need to install [`jsdom`](https://github.com/jsdom/jsdom) with `npm install jsdom`.
`jsDependencies += RuntimeDOM` is now deprecated, and should be replaced by `jsEnv := new org.scalajs.jsenv.jsdomnodejs.JSDOMNodeJSEnv()`.
Expand Down Expand Up @@ -86,16 +94,19 @@ See [the Scaladoc of `StandardLinker.Config`]({{ site.production_url }}/api/scal

To make the resulting JavaScript even smaller (and usually faster as well), the sbt plugin integrates the Google Closure Compiler under the so-called full-optimizations. You can use them by issuing:

sbt> fullOptJS
sbt> fullLinkJS

This will produce another single JavaScript file that is fully optimized.
This will produce a `main.js` file that is fully optimized in another directory.
Note that this can take a while and is therefore not recommended in the development cycle.
The resulting file in the target folder will have the suffix `-opt.js`.
The resulting directory in the target folder will have the suffix `-opt`.

You can run your code and tests in fullOpt stage with the following command:

sbt> set scalaJSStage in Global := FullOptStage

**Note for Scala.js 1.2.x and earlier:** in Scala.js 1.2.x and earlier, we used `fullOptJS` instead of `fullLinkJS`, which always produces a single file with the suffix `-opt.js`.
`scalaJSStage` works the same way in Scala.js 1.2.x and in later versions.

## Deprecated: Writing Launcher Code

**Scala.js 0.6.x only**
Expand Down
8 changes: 4 additions & 4 deletions doc/project/linking-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ layout: doc
title: Linking Errors
---

When linking a Scala.js application, either directly through `fastOptJS`/`fullOptJS` or indirectly through `run` or `test`, Scala.js can sometimes report *linking errors*.
When linking a Scala.js application, either directly through `fastLinkJS`/`fullLinkJS` (`fastOptJS`/`fullOptJS` up to Scala.js 1.2.x) or indirectly through `run` or `test`, Scala.js can sometimes report *linking errors*.
They look like the following:

```
[info] Fast optimizing .../helloworld/target/scala-2.12/helloworld-fastopt.js
[info] Fast optimizing .../helloworld/target/scala-2.12/helloworld-fastopt
[error] Referring to non-existent method scala.concurrent.impl.Promise$CompletionLatch.releaseShared(scala.Int)scala.Boolean
[error] called from scala.concurrent.impl.Promise$CompletionLatch.apply(scala.util.Try)scala.Unit
[error] called from scala.concurrent.impl.Promise$CompletionLatch.apply(java.lang.Object)java.lang.Object
[error] ...
[error] There were linking errors
[error] (helloworld/compile:fastOptJS) There were linking errors
[error] (helloworld/compile:fastLinkJS) There were linking errors
[error] Total time: 2 s, completed Sep 13, 2019 1:30:39 PM
```

Expand Down Expand Up @@ -97,7 +97,7 @@ libraryDependencies += "io.suzaku" %%% "boopickle" % "1.3.1"
```

```
[info] Fast optimizing .../helloworld/target/scala-2.12/helloworld-fastopt.js
[info] Fast optimizing .../helloworld/target/scala-2.12/helloworld-fastopt
[success] Total time: 3 s, completed Sep 13, 2019 1:44:25 PM
```

Expand Down
35 changes: 22 additions & 13 deletions doc/project/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,26 +82,35 @@ exports.Babar = Foobaz;

## ES modules and Node.js

Support for ECMAScript modules is [still experimental in Node.js](https://nodejs.org/api/esm.html).
To run and test a Scala.js application or library using ES modules with Node.js, you will need the following additional settings:
Node.js needs explicit signaling that a module is an ECMAScript module (the default is CommonJS).

There are two ways to achieve this:
* Use the file extension `.mjs`.
* Configure it in `package.json`.

For details, see the [Node.js packages documentation](https://nodejs.org/api/packages.html#packages_determining_module_system).

To set the extension used by Scala.js to `.mjs` use the following setting:

{% highlight scala %}
jsEnv := {
new org.scalajs.jsenv.NodeJSEnv(
org.scalajs.jsenv.NODEJSEnv.Config()
.withArguments(List("--experimental-modules"))
)
import org.scalajs.linker.interface.OutputPatterns

scalaJSLinkerConfig ~= {
// Enable ECMAScript module output.
_.withModuleKind(ModuleKind.ESModule)
// Use .mjs extension.
.withOutputPatterns(OutputPatterns.fromJSFile(".mjs"))
}
{% endhighlight %}

**Note for Scala.js 1.2.x and earlier:**

`OutputPatterns` was introduced in Scala.js 1.3.0. In earlier versions, the following settings were necessary:

{% highlight scala %}
artifactPath in (proj, Compile, fastOptJS) :=
(crossTarget in (proj, Compile)).value / "myproject.mjs"

artifactPath in (proj, Test, fastOptJS) :=
(crossTarget in (proj, Test)).value / "myproject-test.mjs"
{% endhighlight %}

The first setting is required to enable the support of ES modules in Node.js.
The other two make sure that the JavaScript produced have the extension `.mjs`, which is required for Node.js to interpret them as ES modules.

The support for running and testing ES modules with Node.js is *experimental*, as the support of ES modules by Node.js is itself experimental.
Things could change in future versions of Node.js and/or Scala.js.
6 changes: 3 additions & 3 deletions doc/project/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ A list of testing frameworks compatible with Scala.js can be found [here](../../

Note: Don't forget to mark a test framework SBT dependency as `test,it` if you have both unit and integration tests.

## Testing over `fullOptJS`-generated files
## Testing over `fullLinkJS`-generated files

By default, tests runs over `fastOptJS`-built JS files since their build time are shorter than `fullOptJS`.
By default, tests run over `fastLinkJS`-built (resp. `fastOptJS` up to Scala.js 1.2.x) JS files since their build time is shorter than `fullLinkJS` (resp. `fullLinkJS`).

If you want to run tests over `fullOptJS`-build JS files for some reason, run `set scalaJSStage in Global := FullOptStage` before test.
If you want to run tests over `fullLinkJS`-build JS files for some reason, run `set scalaJSStage in Global := FullOptStage` before test.
This increases test time significantly, and omit checks for undefined behavior, so not recommended in default build settings. Instead, consider run test both in `FastOptStage` and `FullOptStage` in CI.
10 changes: 5 additions & 5 deletions doc/semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,20 @@ Every configurable undefined behavior has 3 possible modes:
* `Unchecked`: completely unchecked and undefined
* `Fatal`: checked, but throws `UndefinedBehaviorError`s instead of the specified exception

By default, undefined behaviors are in `Fatal` mode for `fastOptJS` and in
`Unchecked` mode for `fullOptJS`.
By default, undefined behaviors are in `Fatal` mode for `fastLinkJS` and in
`Unchecked` mode for `fullLinkJS` (`fastOptJS` / `fullOptJS` up to Scala.js 1.2.x).
This is so that bugs can be detected more easily during development, with
predictable exceptions and stack traces.
In production code (`fullOptJS`), the checks are removed for maximum
In production code (`fullLinkJS`), the checks are removed for maximum
efficiency.

`UndefinedBehaviorError`s are *fatal* in the sense that they are not matched by
`case NonFatal(e)` handlers.
This makes sure that they always crash your program as early as possible, so
that you can detect and fix the bug.
It is *never* OK to catch an `UndefinedBehaviorError` (other than in a testing
framework), since that means your program will behave differently in `fullOpt`
stage than in `fastOpt`.
framework), since that means your program will behave differently in `fullLinkJS`
stage than in `fastLinkJS`.

If you need a particular kind of exception to be thrown in compliance with the
JVM semantics, you can do so with an sbt setting.
Expand Down