From ea067baf2afe492cde8b10b88e9628812cb4d7cd Mon Sep 17 00:00:00 2001 From: Sébastien Doeraene Date: Wed, 28 Jan 2015 17:40:20 +0100 Subject: Disable async block due to bug scala-js#1469. --- examples/demos/src/main/scala/advanced/Async.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/demos/src/main/scala/advanced/Async.scala b/examples/demos/src/main/scala/advanced/Async.scala index a76b78b..7a7e5ff 100644 --- a/examples/demos/src/main/scala/advanced/Async.scala +++ b/examples/demos/src/main/scala/advanced/Async.scala @@ -35,7 +35,8 @@ object Async { val mousedown = new Channel[ME](canvas.onmousedown = _) - async{ + // Disabled due to scala-js#1469 + /*async{ while(true){ val start = await(mousedown()) renderer.beginPath() @@ -58,7 +59,7 @@ object Async { await(mouseup()) renderer.clearRect(0, 0, 1000, 1000) } - } + }*/ } @JSExport def main0(canvas: dom.HTMLCanvasElement) = { -- cgit v1.2.3 From 33129113b3ebf3dd656bd58c34af476fb852e2f6 Mon Sep 17 00:00:00 2001 From: Sébastien Doeraene Date: Thu, 29 Jan 2015 17:50:33 +0100 Subject: Upgrade and update the whole thing for Scala.js 0.6.0-RC2. Both the builds, as well as the text of the book, have been completely updated for Scala.js 0.6.x. --- book/src/main/scala/book/Main.scala | 2 +- book/src/main/scalatex/book/Intro.scalatex | 2 +- .../main/scalatex/book/handson/CanvasApp.scalatex | 10 +- .../scalatex/book/handson/ClientServer.scalatex | 4 +- .../scalatex/book/handson/CommandLine.scalatex | 48 +++-- .../scalatex/book/handson/GettingStarted.scalatex | 42 ++-- .../book/handson/PublishingModules.scalatex | 2 +- .../main/scalatex/book/handson/WebPage.scalatex | 26 +-- .../book/indepth/AdvancedTechniques.scalatex | 16 +- .../book/indepth/CompilationPipeline.scalatex | 80 +++++--- .../scalatex/book/indepth/DesignSpace.scalatex | 4 +- .../main/scalatex/book/indepth/JavaAPIs.scalatex | 2 +- .../book/indepth/SemanticDifferences.scalatex | 214 +++++++++++---------- build.sbt | 8 +- examples/crossBuilds/clientserver/build.sbt | 18 +- .../crossBuilds/clientserver/project/build.sbt | 4 +- .../server/src/main/scala/simple/Page.scala | 2 +- examples/crossBuilds/clientserver2/build.sbt | 20 +- .../clientserver2/project/build.properties | 1 + .../crossBuilds/clientserver2/project/build.sbt | 4 +- .../server/src/main/scala/simple/Page.scala | 2 +- examples/crossBuilds/simple/build.sbt | 2 +- .../crossBuilds/simple/project/build.properties | 1 + examples/crossBuilds/simple/project/build.sbt | 2 +- .../crossBuilds/simple2/project/build.properties | 1 + examples/crossBuilds/simple2/project/build.sbt | 4 +- examples/demos/build.sbt | 12 +- .../src/main/scala/scrollmenu/Controller.scala | 2 +- .../src/main/scala/scrollmenu/ScrollSpy.scala | 2 +- project/build.sbt | 4 +- 30 files changed, 286 insertions(+), 255 deletions(-) create mode 100644 examples/crossBuilds/clientserver2/project/build.properties create mode 100644 examples/crossBuilds/simple/project/build.properties create mode 100644 examples/crossBuilds/simple2/project/build.properties diff --git a/book/src/main/scala/book/Main.scala b/book/src/main/scala/book/Main.scala index 1f8521a..737c130 100644 --- a/book/src/main/scala/book/Main.scala +++ b/book/src/main/scala/book/Main.scala @@ -74,7 +74,7 @@ object Main { frag ) ), - onload:=s"Controller().main($data)" + onload:=s"scrollmenu.Controller().main($data)" ) } diff --git a/book/src/main/scalatex/book/Intro.scalatex b/book/src/main/scalatex/book/Intro.scalatex index a504aa6..d69a2e5 100644 --- a/book/src/main/scalatex/book/Intro.scalatex +++ b/book/src/main/scalatex/book/Intro.scalatex @@ -21,7 +21,7 @@ while ((x < 10)) { x = ((x + 3) | 0) }; - ScalaJS.m.s_Predef() + ScalaJS.m.s_Predef$() .println__O__V(x) // 12 }); diff --git a/book/src/main/scalatex/book/handson/CanvasApp.scalatex b/book/src/main/scalatex/book/handson/CanvasApp.scalatex index b49f1e5..ae97dee 100644 --- a/book/src/main/scalatex/book/handson/CanvasApp.scalatex +++ b/book/src/main/scalatex/book/handson/CanvasApp.scalatex @@ -25,7 +25,7 @@ @hl.ref(canvasapp/"ScratchPad.scala", "/*setup*/", end = "/*code*/") @p - As described earlier, this code uses the @lnk.dom.getElementById} function to fish out the @code{canvas} element that we interested in from the DOM. It then gets a rendering context from that @code{canvas}, and sets the height and width of the canvas to completely fill its containing element. Lastly, it fills out the canvas light-gray, so that we can see it on the page. + As described earlier, this code uses the @lnk.dom.getElementById function to fish out the @code{canvas} element that we interested in from the DOM. It then gets a rendering context from that @code{canvas}, and sets the height and width of the canvas to completely fill its containing element. Lastly, it fills out the canvas light-gray, so that we can see it on the page. @p Next, let's set some event handlers on the canvas: @@ -35,7 +35,7 @@ @hl.ref(canvasapp/"ScratchPad.scala", "/*code*/") @less - @BookData.example(canvas, "ScratchPad().main") + @BookData.example(canvas, "canvasapp.ScratchPad().main") @p This code sets up the @lnk.dom.mousedown and @lnk.dom.mouseup events to keep track of whether or not the mouse has currently been clicked. It then draws black squares any time you move the mouse while the button is down. This lets you basically click-and-drag to draw pictures on the canvas. Try it out! @@ -69,7 +69,7 @@ @hl.ref(canvasapp/"Clock.scala", "/*code*/") @less - @BookData.example(canvas, "Clock().main") + @BookData.example(canvas, "canvasapp.Clock().main") @p As you can see, we're using more @lnk("Canvas APIs", "https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D"), in this case dealing with rendering text on the canvas. Another thing we're using is the Javascript @lnk("Date", "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date") class, in Scala.js under the full name @hl.scala{scala.scalajs.js.Date}, here imported as @hl.scala{js.Date}. Again, click on the link @i(cls:="fa fa-link ") icon to view the full-code if you're having trouble here. @@ -151,7 +151,7 @@ At almost 100 lines of code, this is quite a meaty example! Nonetheless, when all is said and done, you will find that the example actually works! Try it out! @div - @BookData.example(canvas, "FlappyLine().main") + @BookData.example(canvas, "canvasapp.FlappyLine().main") @sect{Canvas Recap} @p @@ -161,7 +161,7 @@ @p We've by now written a good chunk of Scala.js code, and perhaps debugged some mysterious errors, and tried some new things. One thing you've probably noticed is the efficiency of the process: you make a change in your editor, the browser reloads itself, and life goes on. There is a compile cycle, but after a few runs the compiler warms up and the compilation cycle drops to less than a second. @p - Apart from the compilation/reload speed, you've probably noticed the benefit of tooling around Scala.js. Unlike Javascript editors, your existin Scala IDEs like @lnk.misc.IntelliJ or @lnk.misc.Eclipse can give very useful help when you're working with Scala.js. Autocomplete, error-highlighting, jump-to-definition, and a myriad other modern conveniences that are missing when working in dynamically-typed languages are present when working in Scala.js. This makes the code much less mysterious: you're no longer trying to guess what methods a value has, or what a method returns: it's all laid out in front of you in plain sight. + Apart from the compilation/reload speed, you've probably noticed the benefit of tooling around Scala.js. Unlike Javascript editors, your existing Scala IDEs like @lnk.misc.IntelliJ or @lnk.misc.Eclipse can give very useful help when you're working with Scala.js. Autocomplete, error-highlighting, jump-to-definition, and a myriad other modern conveniences that are missing when working in dynamically-typed languages are present when working in Scala.js. This makes the code much less mysterious: you're no longer trying to guess what methods a value has, or what a method returns: it's all laid out in front of you in plain sight. @sect{Full Scala} @p diff --git a/book/src/main/scalatex/book/handson/ClientServer.scalatex b/book/src/main/scalatex/book/handson/ClientServer.scalatex index 87c959d..0d60192 100644 --- a/book/src/main/scalatex/book/handson/ClientServer.scalatex +++ b/book/src/main/scalatex/book/handson/ClientServer.scalatex @@ -12,7 +12,7 @@ @ul @li - Javascript on the client v.s. PHP/Perl/Python/Ruby/Java on the client + Javascript on the client v.s. PHP/Perl/Python/Ruby/Java on the server @li Most back-ends make heavy use of C extensions, and front-end code was tightly coupled to the DOM. Even if you manage to port the main language @p @@ -49,7 +49,7 @@ @hl.ref(wd/'examples/'crossBuilds/'clientserver/"build.sbt") @p - We have two projects: @code{client} and @code{server}, one of which is a Scala.js project (indicated by the presence of @hl.scala{scalaJSSettings}). Both projects share a number of settings: the presence of the @code{shared/} folder, which shared code can live in (similar to what we saw in @sect.ref{Cross Publishing Libraries}) and the settings to add @lnk.github.Scalatags and @lnk.github.uPickle to the build. Note that those two dependencies use the triple @code{%%%} instead of the double @code{%%} to declare: this means that for each dependency, we will pull in the Scala-JVM or Scala.js version depending on whether it's being used in a Scala.js project. Note also the @hl.scala{packageArchetype.java_application} setting, which isn't strictly necessary depending on what you want to do with the application, but this example needs it as part of the deployment to Heroku. + We have two projects: @code{client} and @code{server}, one of which is a Scala.js project (indicated by the presence of @hl.scala{enablePlugins(ScalaJSPlugin)}). Both projects share a number of settings: the presence of the @code{shared/} folder, which shared code can live in (similar to what we saw in @sect.ref{Cross Publishing Libraries}) and the settings to add @lnk.github.Scalatags and @lnk.github.uPickle to the build. Note that those two dependencies use the triple @code{%%%} instead of the double @code{%%} to declare: this means that for each dependency, we will pull in the Scala-JVM or Scala.js version depending on whether it's being used in a Scala.js project. Note also the @hl.scala{packageArchetype.java_application} setting, which isn't strictly necessary depending on what you want to do with the application, but this example needs it as part of the deployment to Heroku. @p The @code{client} subproject is uneventful, with a dependency on the by-now-familiar @code{scalajs-dom} library. The @code{server} project, on the other hand, is interesting: it contains the dependencies required for us to set up out Spray server, and one additional thing: we add the output of @code{fastOptJS} from the client to the @code{resources} on the server. This will allow the @code{server} to serve the compiled-javascript from our @code{client} project from its resources. diff --git a/book/src/main/scalatex/book/handson/CommandLine.scalatex b/book/src/main/scalatex/book/handson/CommandLine.scalatex index ea845da..b7a16cf 100644 --- a/book/src/main/scalatex/book/handson/CommandLine.scalatex +++ b/book/src/main/scalatex/book/handson/CommandLine.scalatex @@ -66,11 +66,11 @@ @hl.bash > package @p - Also like on Scala-JVM, Scala.js also supports the @code{package} command. This command generates a @code{.jar} like it does in Scala-JVM, except this version appends this weird @code{_sjs0.5} suffix. + Also like on Scala-JVM, Scala.js also supports the @code{package} command. This command generates a @code{.jar} like it does in Scala-JVM, except this version appends this weird @code{_sjs0.6} suffix. @hl.bash target/scala-2.11/ - └── example_sjs0.5_2.11-0.1-SNAPSHOT.jar + └── example_sjs0.6_2.11-0.1-SNAPSHOT.jar @p The purpose of this suffix is to link the compiled @code{.jar} file to the version of Scala.js used to compile it. This allows you to make sure that you don't accidentally depend on a version of a jar that is incompatible with your current version. @@ -121,52 +121,62 @@ This exhibits the weirdness of @hl.scala{Double.toString} in Scala.js, which is one of the few ways in which @sect.ref("Deviations from Scala-JVM", "Scala.js deviates from Scala-JVM"). This also shows us we're really running on Scala.js: on Scala-JVM, @hl.scala{(1.0).toString} returns @hl.scala{"1.0"} rather than @hl.scala{"1"}! @p - One thing you may be wondering is: when you run a Scala.js program in the terminal, how does it execute the output Javascript? What about the DOM? and Ajax calls? Can it access the filesystem? The answer to all these questions is "it depends": it turns out there are multiple ways you can run Scala.js from the command-line: + One thing you may be wondering is: when you run a Scala.js program in the terminal, how does it execute the output Javascript? What about the DOM? and Ajax calls? Can it access the filesystem? The answer to all these questions is "it depends": it turns out there are multiple ways you can run Scala.js from the command-line, dictated by the @i{stage} and the @i{environment}. + + @p + By default, runs are done in the @code{PreLinkStage}, which uses the Rhino environment. With the sbt setting @hl.scala{jsDependencies += RuntimeDOM}, the Scala.js runner will automatically set up @b{env.js} in Rhino so that you have access to an emulation of the DOM API. + + @p + You can enable a different stage, @code{FastOptStage} or @code{FullOptStage}, with the following sbt command: + + @hl.bash + > set scalaJSStage in Global := FastOptStage + + @p + In @code{FastOptStage} and @code{FullOptStage}, the environment can be one of @b{Node.js} or @b{PhantomJS}. These JavaScript VMs must be installed separately. @ul @li - @b{Rhino} using @code{sbt run} - @li - @b{Node.js} using @code{sbt fastOptStage::run} or @code{sbt fullOptStage::run}, having installed Node.js separately + By default, Node.js is used. @li - @b{PhantomJS} using @code{sbt fastOptStage::run} or @code{sbt fullOptStage::run}, having installed PhantomJS separately, and turned on @hl.scala{jsDependencies += RuntimeDOM} in SBT + With the sbt setting @hl.scala{jsDependencies += RuntimeDOM}, PhantomJS is used instead, so that a headless DOM is available. @p - Typically, the best way to get started is using Rhino and @code{sbt run}, since it's setup-free, and setting up Node.js or PhantomJS later as necessary. The next two sections elaborate on the differences between these ways of running your code. Check out the later sections on @sect.ref{Headless Runtimes} and @sect.ref{Run Configurations} to learn more about the other settings and why you would want to use them. + Typically, the best way to get started is using Rhino, since it's setup-free, and setting up Node.js or PhantomJS later as necessary. The next two sections elaborate on the differences between these ways of running your code. Check out the later sections on @sect.ref{Headless Runtimes} and @sect.ref{Stages} to learn more about the other settings and why you would want to use them. @sect{The test Command} @hl.bash > test @p - The @code{sbt test} command behaves very similar to @code{sbt run}. It can also be prefixed e.g. @code{sbt fastOptStage::run} or @code{sbt fullOptStage::run}, or run in either Rhino, Node.js or PhantomJS. + The @code{sbt test} command behaves very similarly to @code{sbt run}. It also runs on Rhino, Node.js or PhantomJS, dependending of the stage and the dependency on the DOM. @p - The difference is that instead of simply running your @code{main} method, @code{sbt test} runs whatever test-suite you have set-up, which will look through your @code{tests/} folder to find suites of tests it has to run, and aggregate the results formatted nicely for you to see. The exact operation of this depends on which testing library you're using + The difference is that instead of simply running your @code{main} method, @code{sbt test} runs whatever test-suite you have set-up, which will look through your @code{tests/} folder to find suites of tests it has to run, and aggregate the results formatted nicely for you to see. The exact operation of this depends on which testing library you're using. @p We won't spend much time talking about @code{sbt test} here. Not because it's not important: it most certainly is! Rather, we will be spending a good amount of time setting up tests in @sect.ref("Cross Publishing Libraries", "the next chapter"), so feel free to jump ahead if you want to see an example usage of @code{sbt test}. @sect{Headless Runtimes} @ul @li - @lnk.misc.Rhino is the default way of running Scala.js applications, and occurs when you hit @code{sbt run} from the terminal. The upside of using Rhino is that it is pure-Java, and doesn't need any additional binaries or installation. The downside of using Rhino is that it is slow: maybe a hundred times slower than the alternatives, making it not suitable for running long-running, compute-intensive programs. Furthermore, it's a very sparse runtime environment, with no DOM access or similar. + @lnk.misc.Rhino is the default way of running Scala.js applications. The upside of using Rhino is that it is pure-Java, and doesn't need any additional binaries or installation. The downside of using Rhino is that it is slow: maybe a hundred times slower than the alternatives, making it not suitable for running long-running, compute-intensive programs. @li - @lnk.misc.Nodejs, a relatively new Javascript runtime based on Google's V8 Javascript engine, Node.js lets you run your Scala.js application from the command line much faster than in Rhino, with performance that matches that of modern browsers. However, you need to separately @lnk("install Node.js", "http://nodejs.org/download/") in order to use it. Like Rhino, it comes with a bare-minimal runtime environment, with no DOM or browser-related functionality. You need to run @code{sbt fastOptStage::run} to run using Node.js. + @lnk.misc.Nodejs, a relatively new Javascript runtime based on Google's V8 Javascript engine, Node.js lets you run your Scala.js application from the command line much faster than in Rhino, with performance that matches that of modern browsers. However, you need to separately @lnk("install Node.js", "http://nodejs.org/download/") in order to use it. Node.js does not have DOM or browser-related functionality. You need to set the stage with @code{set scalaJSStage in Global := FastOptStage} to run using Node.js. @li - @lnk.misc.PhantomJS is a headless Webkit browser. This means that unlike Node.js or Rhino, PhantomJS provides you with a full DOM and all its APIs to use in your tests, if you wish to e.g. test interactions with the HTML of the web page. On the other hand, it is somewhat slower than Node.js, though still much faster than Rhino. Like Node.js, it needs to be installed separately. You need to run You need to run @code{sbt fastOptStage::run}, as well as setting the @hl.scala{jsDependencies += RuntimeDOM} flag in your SBT configuration, to use PhantomJS. + @lnk.misc.PhantomJS is a headless Webkit browser. This means that unlike Node.js, PhantomJS provides you with a full DOM and all its APIs to use in your tests, if you wish to e.g. test interactions with the HTML of the web page. On the other hand, it is somewhat slower than Node.js, though still much faster than Rhino. Like Node.js, it needs to be installed separately. You need to set the stage with @code{set scalaJSStage in Global := FastOptStage}, as well as setting the @hl.scala{jsDependencies += RuntimeDOM} flag in your SBT configuration, to use PhantomJS. @p - These are your three options to run your Scala.js code via the command-line. Generally, it's easiest to get started with Rhino since it's the default and requires no setup, though you may find it worthwhile to setup Node or Phantom if you need additional speed or DOM-integration in your runs. + These are your three options to run your Scala.js code via the command-line. Generally, it's easiest to get started with Rhino since it's the default and requires no setup, though you will quickly find it worthwhile to setup Node.js or PhantomJS to speed up your runs and tests. -@sect{Run Configurations} +@sect{Stages} @p - You may have noticed that in Rhino we use @code{sbt run}, whereas for Node.js or PhantomJS we use @code{sbt fastOptStage::run}. It turns out that similar to the split between @code{fastOptJS}/@code{fullOptJS}, you have a range of options of how you want to prepare your Scala.js code for execution from the command line: + Let us recap the three different stages of execution, and what they mean. @ul @li - @code{sbt run}: this does not perform any optimization of the output Scala.js files, and does lazy-loading to minimize the amount of files being loading into the interpreter. This is necessary for Rhino because it can't handle large blobs of Javascript, but doesn't map to any compilation mode you'd use for the browser. + @code{PreLinkStage} (the default): this does not perform any optimization of the output Scala.js files, and does lazy-loading to minimize the amount of files being loading into the interpreter. This is necessary for Rhino because it can't handle large blobs of Javascript, but doesn't map to any compilation mode you'd use for the browser. @li - @code{sbt fastOptStage::run}: this performs the same compilation and optimization as @code{sbt fastOptJS}, as described under Fast Optimizations. It then takes the entire output executable (which probably weighs around 1mb) and hands it to Node.js or PhantomJS, which then run it. + @code{FastOptStage}: this performs the same compilation and optimization as @code{sbt fastOptJS}, as described under Fast Optimizations. It then takes the entire output executable (which probably weighs around 1mb) and hands it to Node.js or PhantomJS, which then run it. @li - @code{sbt fullOptStage::run}: this performs the same compilation and optimization as @code{sbt fullOptJS}, as described under Full Optimizations. This takes longer to run than @code{sbt fastOptStage::run}, and results in a smaller/faster executable. Practically speaking, this size/speed advantage does not matter from the command line, but @code{fullOptStage::run} is still useful to verify that the behavior does not change (it shouldn't!) under the aggressive full optimization. + @code{FullOptStage}: this performs the same compilation and optimization as @code{sbt fullOptJS}, as described under Full Optimizations. This takes longer to run than the @code{FastOptStage}, and results in a smaller/faster executable. Practically speaking, this size/speed advantage does not matter from the command line, but @code{FullOptStage} is still useful to verify that the behavior does not change (it shouldn't!) under the aggressive full optimization. This is typically used in continuous integration builds, but rarely manually. @hr diff --git a/book/src/main/scalatex/book/handson/GettingStarted.scalatex b/book/src/main/scalatex/book/handson/GettingStarted.scalatex index a77245d..c200f1e 100644 --- a/book/src/main/scalatex/book/handson/GettingStarted.scalatex +++ b/book/src/main/scalatex/book/handson/GettingStarted.scalatex @@ -182,7 +182,7 @@ This is the HTML page which our toy app lives in, and the same page that we have so far been using to view the app in the browser. To anyone who has used HTML, most of it is probably familiar. Things of note are the @hl.html{