diff --git a/_config.yml b/_config.yml index 5076e2ea..41cf90fd 100644 --- a/_config.yml +++ b/_config.yml @@ -27,6 +27,7 @@ assets: paginate: 6 paginate_path: "/news/page:num" excerpt_separator: "" +future: true # Build settings markdown: kramdown @@ -57,7 +58,7 @@ colors: #in hex code if not noted else ### VERSIONS ### versions: - scalaJS: 0.6.5 + scalaJS: 0.6.6 scalaJSBinary: 0.6 scalaJSDOM: 0.8.2 diff --git a/_posts/news/2016-01-25-announcing-scalajs-0.6.6.md b/_posts/news/2016-01-25-announcing-scalajs-0.6.6.md new file mode 100644 index 00000000..a519c536 --- /dev/null +++ b/_posts/news/2016-01-25-announcing-scalajs-0.6.6.md @@ -0,0 +1,173 @@ +--- +layout: post +title: Announcing Scala.js 0.6.6 +category: news +tags: [releases] +permalink: /news/2016/01/25/announcing-scalajs-0.6.6/ +--- + + +We are excited to announce the release of Scala.js 0.6.6! + +It has been a long while since the last release, almost 5 months already. +That was too long, and we apologize. +In the future, we hope never to let more than 2 months elapse between consecutive releases. + +Besides bug fixes, this release brings several major improvements: + +* `js.TupleN`, a JS equivalent of Scala tuples +* Support for JUnit +* Better support of constructors of `@ScalaJSDefined` classes: + they can now have overloads, default parameters and varargs +* A completely redesigned internal API for the linker, whose main visible impact should be reduced memory usage and improved speed +* `js.ConstructorTag[C]`, a `ClassTag` equivalent to `js.constructorOf[C]` + + + +## Getting started + +If you are new to Scala.js, head over to +[the tutorial]({{ BASE_PATH }}/tutorial/). + +## Release notes + +As a minor release, 0.6.6 is (almost, see Breaking changes below) backward source and binary compatible with previous releases in the 0.6.x series. +Libraries compiled with earlier versions can be used with 0.6.6 without change. +However, it is not forward compatible: libraries compiled with 0.6.6 cannot be used by projects using 0.6.{0-5}. + +Please report any issues [on GitHub](https://github.com/scala-js/scala-js/issues). + +## Breaking changes + +### Running in Node.js/PhantomJS + +Until Scala.js 0.6.5, the following sbt setting would, as a side-effect, enable Node.js or PhantomJS: + + scalaJSStage in Global := FastOptStage + +As of Scala.js 0.6.6, this setting is redundant, as it is the default, but `run` and `test` will still use Rhino by default! +To disable Rhino and use Node.js/PhantomJS in 0.6.6, use the following setting instead: + + scalaJSUseRhino in Global := false + +### Tools API + +The [Tools API]({{ site.production_url }}/api/scalajs-tools/0.6.6/#org.scalajs.core.tools.package), +(the API to the Scala.js linker and optimizer) have been completely redesigned. +Users of this API, such as [Scala.jsFiddle](http://www.scala-js-fiddle.com/), will experience breakages. +Contact us if you need help porting your code. + +## Improvements + +### JavaScript Tuple types + +In the same spirit as `js.Function`s, `js.Array`, etc., we have added a series of types representing JavaScript "tuples": `js.Tuple2` to `js.Tuple22`. +The JavaScript representation of a tuple is, in fact, a heterogeneous array of fixed length. + +For example, the value + + val t = js.Tuple2(45, "hello") + +corresponds the JavaScript value + + [45, "hello"] + +You should use `js.Tuple`s in facades to JavaScript libraries that take and return tuples as heterogeneous arrays. + +JavaScript tuples are convertible back and forth to Scala tuples, and you can use deconstruction to extract all values of a JavaScript at the same time. +For example: + + val scalaT: (Int, String) = t + val t2: js.Tuple2[Int, String] = scalaT + val js.Tuple2(a, b) = t2 + +### Support for JUnit + +It is now possible to write JUnit tests for Scala.js! +We have ported the JUnit API to Scala.js, so that it is now possible to write cross-compiling unit tests with JUnit. + +To enable JUnit on your Scala.js project, add the appropriate sbt AutoPlugin using + + enablePlugins(ScalaJSJUnitPlugin) + +(like you would with the basic `ScalaJSPlugin`). +For a `crossProject`, this must be enabled only on the JS variant. +For the JVM variant, use the usual `libraryDependencies` setting: + +{% highlight scala %} +lazy val myCrossProject = crossProject. + jsConfigure(_.enablePlugins(ScalaJSJUnitPlugin)). + jvmSettings( + libraryDependencies += + "com.novocode" % "junit-interface" % "0.9" % "test" + ) +{% endhighlight %} + +### `js.ConstructorTag[C]` + +[`js.ConstructorTag[C]`]({{ site.production_url }}/api/scalajs-library/0.6.6/#scala.scalajs.js.ConstructorTag) is to [`js.constructorOf[C]`]({{ site.production_url }}/api/scalajs-library/0.6.6/#scala.scalajs.js.package@constructorOf[T<:scala.scalajs.js.Any]:scala.scalajs.js.Dynamic) as `ClassTag[C]` is to `classOf[C]`, i.e., you can use an `implicit` parameter of type `js.ConstructorTag[C]` to implicitly get a `js.constructorOf[C]`. +For example: + +{% highlight scala %} +def instantiate[C <: js.Any : js.ConstructorTag]: C = + js.Dynamic.newInstance(js.constructorTag[C].constructor)().asInstanceOf[C] + +val newEmptyJSArray = instantiate[js.Array[Int]] +{% endhighlight %} + +Implicit expansion will desugar the above code into: + +{% highlight scala %} +def instantiate[C <: js.Any](implicit tag: js.ConstructorTag[C]): C = + js.Dynamic.newInstance(tag.constructor)().asInstanceOf[C] + +val newEmptyJSArray = instantiate[js.Array[Int]]( + new js.ConstructorTag[C](js.constructorOf[js.Array[Int]])) +{% endhighlight %} + +although you cannot write the desugared version in user code because the constructor of `js.ConstructorTag` is private. + +This feature is particularly useful for Scala.js libraries wrapping JavaScript frameworks expecting to receive JavaScript constructors as parameters. + +### Query for Development versus Production mode + +The new methods `isDevelopmentMode` and `isProductionMode` allow you to query in your code whether you are running in a Development build or a Production build (for all practical purposes, aka `fastOptJS` and `fullOptJS`, resp.). +The methods are located in [`scala.scalajs.LinkingInfo`]({{ site.production_url }}/api/scalajs-library/0.6.6/#scala.scalajs.LinkingInfo$). +These methods can be used by libraries to provide domain-specific "optimizations" for production, e.g., eliminate expensive run-time checks useful for debugging. +Using these methods should be done with great care as, by definition, they will alter the behavior of your program between `fastOpt` and `fullOpt`. + +### Java library additions + +* Methods of `java.lang.Long` dealing with unsigned values +* Several JDK8 methods of `java.lang.Math` +* `java.util.Comparator.reversed`: the first of the *default* methods of JDK8 +* `java.util.ArrayDeque` +* `java.net.URLDecoder` +* `java.util.concurrent.locks.ReentrantLock` +* `java.util.Objects` + +## Bug fixes + +Among others, the following bugs have been fixed: + +* [#1635](https://github.com/scala-js/scala-js/issues/1635) Touching a file in `src/test/resources` triggers `test:fastOptJS` +* [#1891](https://github.com/scala-js/scala-js/issues/1891) Class with constructors with optional parameters can't be embedded in objects that extend `js.Object` +* [#1899](https://github.com/scala-js/scala-js/issues/1899) Some members of `new js.Object {...}` are not visible from JavaScript +* [#1975](https://github.com/scala-js/scala-js/issues/1975) Inner function in `@ScalaJSDefined` method doesn't get parameter +* [#1979](https://github.com/scala-js/scala-js/issues/1979) [#2042](https://github.com/scala-js/scala-js/issues/2042) Bugs in `java.math.BigDecimal.divideToIntegralValue` +* [#1984](https://github.com/scala-js/scala-js/issues/1984) `-8 % 8` evaluates to negative 0, which then blows up if cast to Integer (duplicate [#2068](https://github.com/scala-js/scala-js/issues/2068)) +* [#2045](https://github.com/scala-js/scala-js/issues/2045) `BigInt.pow(31)` return the negative of the expected number +* [#2067](https://github.com/scala-js/scala-js/issues/2067) Better implicits for combinations of `js.|` and `js.UndefOr` +* [#2114](https://github.com/scala-js/scala-js/issues/2114) `CharBuffer.wrap(CharSequence,Int,Int)` interprets `end` as `length` +* [#2158](https://github.com/scala-js/scala-js/issues/2158) Parsing very large `Long` does not fail properly +* [#2159](https://github.com/scala-js/scala-js/issues/2159) `java.math.BigInteger` violate equals/hashCode law +* [#2178](https://github.com/scala-js/scala-js/issues/2178) sbt `test:run` on Scala.js projects runs it under the JVM +* [#2180](https://github.com/scala-js/scala-js/issues/2180) `Character.isWhitespace` discrepancies + +You can find the full list [on GitHub](https://github.com/scala-js/scala-js/issues?q=is%3Aissue+milestone%3Av0.6.6+is%3Aclosed). + +## Known issues + +The following issues were discovered too late to be fixed in v0.6.6: + +* [#2195](https://github.com/scala-js/scala-js/issues/2195) Source maps to the Scala library are broken diff --git a/doc/all-api.md b/doc/all-api.md index a7bb4bf6..0dc18229 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 0.6.6 +* [0.6.6 scalajs-library]({{ site.production_url }}/api/scalajs-library/0.6.6/#scala.scalajs.js.package) +* [0.6.6 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/0.6.6/) +* [0.6.6 scalajs-stubs]({{ site.production_url }}/api/scalajs-stubs/0.6.6/) +* [0.6.6 scalajs-ir]({{ site.production_url }}/api/scalajs-ir/0.6.6/#org.scalajs.core.ir.package) +* [0.6.6 scalajs-tools]({{ site.production_url }}/api/scalajs-tools/0.6.6/#org.scalajs.core.tools.package) ([Scala.js version]({{ site.production_url }}/api/scalajs-tools-js/0.6.6/#org.scalajs.core.tools.package)) +* [0.6.6 scalajs-js-envs]({{ site.production_url }}/api/scalajs-js-envs/0.6.6/#org.scalajs.jsenv.package) +* [0.6.6 scalajs-test-adapter]({{ site.production_url }}/api/scalajs-sbt-test-adapter/0.6.6/#org.scalajs.testadapter.package) +* [0.6.6 sbt-scalajs]({{ site.production_url }}/api/sbt-scalajs/0.6.6/#org.scalajs.sbtplugin.package) + ### Scala.js 0.6.5 * [0.6.5 scalajs-library]({{ site.production_url }}/api/scalajs-library/0.6.5/#scala.scalajs.js.package) * [0.6.5 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/0.6.5/) diff --git a/doc/internals/downloads.md b/doc/internals/downloads.md index c0aa338b..5a95e64a 100644 --- a/doc/internals/downloads.md +++ b/doc/internals/downloads.md @@ -7,6 +7,12 @@ We strongly recommend using the SBT plugin, as shown in the [bootstrapping skele The CLI distribution requires `scala` and `scalac` (of the right major version) to be on the execution path. Unpack it wherever you like and add the `bin/` folder to your execution path. +#### Scala.js 0.6.6 +* [0.6.6, Scala 2.11 (tgz, 24MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.6.tgz) +* [0.6.6, Scala 2.11 (zip, 24MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.6.zip) +* [0.6.6, Scala 2.10 (tgz, 22MB)]({{ site.production_url }}/files/scalajs_2.10-0.6.6.tgz) +* [0.6.6, Scala 2.10 (zip, 22MB)]({{ site.production_url }}/files/scalajs_2.10-0.6.6.zip) + #### Scala.js 0.6.5 * [0.6.5, Scala 2.11 (tgz, 24MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.5.tgz) * [0.6.5, Scala 2.11 (zip, 24MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.5.zip) diff --git a/doc/interoperability/sjs-defined-js-classes.md b/doc/interoperability/sjs-defined-js-classes.md index de88faef..124a8ec2 100644 --- a/doc/interoperability/sjs-defined-js-classes.md +++ b/doc/interoperability/sjs-defined-js-classes.md @@ -40,10 +40,6 @@ Scala.js-defined JS types have the following restrictions: * Declaring a method with `@JSBracketSelect` or `@JSBracketCall` is illegal. * Mixing fields, pairs of getter/setter, and/or methods with the same name is illegal. (For example `def foo: Int` and `def foo(x: Int): Int` cannot both exist in the same class.) -There is also one implementation restriction, which will be lifted in a future version: - -* A Scala.js-defined JS class cannot have secondary constructors, and its primary constructor cannot have default parameters nor repeated parameters (varargs). - ## Semantics @@ -275,3 +271,29 @@ It can be a native JS class or a Scala.js-defined JS class. The method returns the JavaScript constructor function (aka the class value) for `C`. This can be useful to give to JavaScript libraries expecting constructor functions rather than instances of the classes. + +### `js.ConstructorTag[C]` + +[`js.ConstructorTag[C]`]({{ site.production_url }}/api/scalajs-library/latest/#scala.scalajs.js.ConstructorTag) is to [`js.constructorOf[C]`]({{ site.production_url }}/api/scalajs-library/latest/#scala.scalajs.js.package@constructorOf[T<:scala.scalajs.js.Any]:scala.scalajs.js.Dynamic) as `ClassTag[C]` is to `classOf[C]`, i.e., you can use an `implicit` parameter of type `js.ConstructorTag[C]` to implicitly get a `js.constructorOf[C]`. +For example: + +{% highlight scala %} +def instantiate[C <: js.Any : js.ConstructorTag]: C = + js.Dynamic.newInstance(js.constructorTag[C].constructor)().asInstanceOf[C] + +val newEmptyJSArray = instantiate[js.Array[Int]] +{% endhighlight %} + +Implicit expansion will desugar the above code into: + +{% highlight scala %} +def instantiate[C <: js.Any](implicit tag: js.ConstructorTag[C]): C = + js.Dynamic.newInstance(tag.constructor)().asInstanceOf[C] + +val newEmptyJSArray = instantiate[js.Array[Int]]( + new js.ConstructorTag[C](js.constructorOf[js.Array[Int]])) +{% endhighlight %} + +although you cannot write the desugared version in user code because the constructor of `js.ConstructorTag` is private. + +This feature is particularly useful for Scala.js libraries wrapping JavaScript frameworks expecting to receive JavaScript constructors as parameters. diff --git a/doc/project/building.md b/doc/project/building.md index d0430cb5..2ede5c00 100644 --- a/doc/project/building.md +++ b/doc/project/building.md @@ -18,42 +18,33 @@ You now can run your application already by using the `run` task: This will detect and run classes that extend [`js.JSApp`]({{ site.production_url }}/api/scalajs-library/{{ site.versions.scalaJS }}/#scala.scalajs.js.JSApp), while optionally prompting the user to choose a class if multiple such classes exist (fails with multiple classes if `persistLauncher := true`, see section below for details). -To run the `.sjsir` files, we invoke the Rhino JavaScript interpreter with a special scope that lazily reads and loads required `.sjsir` files on the fly (much like Java class loading). +By default, to run the `.sjsir` files, we invoke the Rhino JavaScript interpreter with a special scope that lazily reads and loads required `.sjsir` files on the fly (much like Java class loading). Note that by default, this environment doesn't have a DOM. If you need it set `jsDependencies += RuntimeDOM` in your settings. -## Fast-Optimize +## Running with Node.js or PhantomJS -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`. +Since Rhino is very slow and limited, we recommend to use [Node.js](http://nodejs.org/) or [PhantomJS](http://phantomjs.org/) instead of Rhino. +You can disable Rhino with the following sbt setting: -If you want to run this code, you can do so by enabling the fastOpt stage with + scalaJSUseRhino in Global := false - sbt> set scalaJSStage in Global := FastOptStage - sbt> run +which you can put in your `build.sbt`, or in a separate `.sbt` file, e.g., +`local.sbt`, which is not checked in your version control. -This will invoke an external JavaScript interpreter and pass the generated file to it. -Depending on your `requiresDOM` setting (which is derived from the presence of `RuntimeDOM` in your `jsDependencies`), it will either invoke [Node.js](http://nodejs.org/) or [PhantomJS](http://phantomjs.org/). +If `RuntimeDOM` is required, `run` (and `test`) will use PhantomJS. +Otherwise, it will use Node.js. *You need to install these separately* and make them available on the execution path (i.e. as shell commands `node` and `phantomjs`). -Note that running in the `fastOptStage` is often faster than running just after compilation because: +The section on [JavaScript environments](./js-environments.html) explains more on the topic, including finer-grained configuration. -a. As their name implies, fast optimizations are *really* fast (starting from the second run in an sbt session), -b. External virtual machines are much faster than Rhino, and -c. The code is, well, optimized, so faster itself. +## Produce one JavaScript file -We recommend you to operate in the `fastOpt` stage in your development cycle. -You can enable it by default with the following sbt setting: +To produce a proper JavaScript file from your code, you need to call the linker: -{% highlight scala %} -scalaJSStage in Global := FastOptStage -{% endhighlight %} + sbt> fastOptJS -which you can put in your `build.sbt`, or in a separate `.sbt` file, e.g., -`local.sbt`, which is not checked in your version control. +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`. ### Disabling the optimizations diff --git a/doc/project/js-environments.md b/doc/project/js-environments.md index b935ca7b..4420265b 100644 --- a/doc/project/js-environments.md +++ b/doc/project/js-environments.md @@ -3,17 +3,14 @@ layout: doc title: JavaScript Environments --- -In order to decide how to run JavaScript code, the Scala.js sbt plugin uses the following two setting keys: - -- `preLinkJSEnv`: the JavaScript Environment (i.e. virtual machine) used to run unlinked `.sjsir` files (defaults to Rhino) -- `postLinkJSEnv`: the JavaScript Environment used to run linked JavaScript (defaults to Node.js if DOM is not required, otherwise PhantomJS) - -You may change these environments at your discretion. However, note that running Rhino on linked JavaScript and Node.js or PhantomJS on unlinked JavaScript is unlikely to work or at least slow. +In order to decide how to run JavaScript code, the Scala.js sbt plugin uses the setting key `jsEnv`. +If it is not set, Scala.js uses Rhino if `scalaJSUseRhino` is `true`, and to Node.js or PhantomJS otherwise (depending on whether the DOM is required). +You can use `jsEnv` to override this default, or to provide finer-grained configuration, as shown in this section. For example, to switch to PhantomJS, you can set: {% highlight scala %} -postLinkJSEnv := PhantomJSEnv().value +jsEnv := PhantomJSEnv().value {% endhighlight %} We'd like to stress here again, that you need to separately install Node.js and PhantomJS if you would like to use these environments. @@ -25,7 +22,7 @@ This may not be what you want, if for example you register time-outs or use WebS You can disable this behavior with the following setting: {% highlight scala %} -postLinkJSEnv := PhantomJSEnv(autoExit = false).value +jsEnv := PhantomJSEnv(autoExit = false).value {% endhighlight %} You can terminate the interpreter from your Scala code with @@ -39,7 +36,7 @@ System.exit(0) You can pass command-line arguments to the PhantomJS interpreter like this: {% highlight scala %} -postLinkJSEnv := PhantomJSEnv(args = Seq("arg1", "arg2")).value +jsEnv := PhantomJSEnv(args = Seq("arg1", "arg2")).value {% endhighlight %} For more options of the PhantomJS environment, see diff --git a/tutorial/basic/index.md b/tutorial/basic/index.md index 9ab5cc24..9df92590 100644 --- a/tutorial/basic/index.md +++ b/tutorial/basic/index.md @@ -33,13 +33,13 @@ enablePlugins(ScalaJSPlugin) name := "Scala.js Tutorial" -scalaVersion := "2.11.5" // or any other Scala version >= 2.10.2 +scalaVersion := "2.11.7" // or any other Scala version >= 2.10.2 {% endhighlight %} Last, we need a `project/build.properties` to specify the sbt version (>= 0.13.7): {% highlight scala %} -sbt.version=0.13.7 +sbt.version=0.13.9 {% endhighlight %} That is all we need to configure the build. @@ -71,15 +71,14 @@ As you expect, this will simply print "HelloWorld" when run. To run this, simply Hello world! [success] (...) -**Troubleshooting**: Should you experience errors with the `PermGen` size of the JVM at this point, you can increase it. Refer, for example, to [this StackOverflow question](http://stackoverflow.com/questions/8331135/transient-outofmemoryerror-when-compiling-scala-classes). +**Troubleshooting on JDK <= 7**: Should you experience errors with the `PermGen` size of the JVM at this point, you can increase it. Refer, for example, to [this StackOverflow question](http://stackoverflow.com/questions/8331135/transient-outofmemoryerror-when-compiling-scala-classes). Congratulations! You have successfully compiled and run your first Scala.js application. The code is actually run by a JavaScript interpreter. If you do not believe this (it happens to us occasionally), you can use the `last` command in sbt: > last (...) [info] Running tutorial.webapp.TutorialApp - [debug] with JSEnv of type class org.scalajs.jsenv.rhino.RhinoJSEnv - [debug] with classpath of type class org.scalajs.core.tools.classpath.IRClasspath + [debug] with JSEnv RhinoJSEnv [success] (...) So your code has actually been executed by the [Rhino](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino) JavaScript interpreter. @@ -91,10 +90,10 @@ But it is *terribly* slow. In general, you do not want to use it for your day-to-day development. [Node.js](http://nodejs.org/) is a much more performant JavaScript engine. -To run your code with Node.js, you need to install it, and enable -`FastOptStage` in sbt using this command: +To run your code with Node.js, you need to install it, and disable Rhino in sbt +using this command: - > set scalaJSStage in Global := FastOptStage + > set scalaJSUseRhino in Global := false > run [info] Fast optimizing C:\Users\Sepi\Documents\Projets\scalajs-tutorial\target\scala-2.11\scala-js-tutorial-fastopt.js [info] Running tutorial.webapp.TutorialApp @@ -106,18 +105,18 @@ The `last` command now shows that this was run with Node.js: > last (...) [info] Running tutorial.webapp.TutorialApp - [debug] with JSEnv of type class org.scalajs.jsenv.nodejs.NodeJSEnv - [debug] with classpath of type class org.scalajs.core.tools.classpath.LinkedClasspath + [debug] with JSEnv ExternalJSEnv for Node.js + [debug] Starting process: node [success] (...) -The stage needs to be set once per sbt session. +Disabling Rhino must be done once per sbt session. Alternatively, you can include the setting directly in your `build.sbt`, or, in order not to disturb your teammates, in a separate `.sbt` file (say, `local.sbt`): - scalaJSStage in Global := FastOptStage + scalaJSUseRhino in Global := false -This will enable the fastOpt stage by default when launching sbt. +This will enable Node.js by default when launching sbt. **Source maps in Node.js**: To get your stack traces resolved on Node.js, you will have to install the `source-map-support` package. @@ -140,7 +139,7 @@ To generate a single JavaScript file using sbt, just use the `fastOptJS` task: This will perform some fast optimizations and generate the `target/scala-2.11/scala-js-tutorial-fastopt.js` file containing the JavaScript code. -(It is possible that the `[info]` does not appear, if you have just run the program in fastOpt mode.) +(It is possible that the `[info]` does not appear, if you have just run the program with Node.js.) ### Create the HTML Page @@ -184,7 +183,7 @@ That's what the DOM API is for. To use the DOM, it is best to use the statically typed Scala.js DOM library. To add it to your sbt project, add the following line to your `build.sbt`: {% highlight scala %} -libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.8.0" +libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.8.2" {% endhighlight %} sbt-savvy folks will notice the `%%%` instead of the usual `%%`. It means we are using a Scala.js library and not a @@ -209,7 +208,7 @@ import org.scalajs.dom import dom.document {% endhighlight %} -`dom` is the root of the JavaScript DOM and corresponds to the global scope of Script (aka the `window` object). +`dom` is the root of the JavaScript DOM and corresponds to the global scope of JavaScript (aka the `window` object). We additionally import `document` (which corresponds to `document` in JavaScript) for convenience. We now create a method that allows us to append a `

` tag with a given text to a given node: @@ -278,7 +277,8 @@ Since we now have a method that is callable from JavaScript, all we have to do i `onclick` attribute (make sure to add the button *before* the `