summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Haoyi <haoyi@dropbox.com>2015-02-04 09:11:56 -0800
committerLi Haoyi <haoyi@dropbox.com>2015-02-04 09:11:56 -0800
commitd2b59cfd4d11d69f11cd69c90ad825b882328438 (patch)
tree0297b7b4a92c75e7d5c4dc88220608eda04fca86
parent5ca33ebaaf60a7eb2e4fa3412aba0f5027c2f20a (diff)
downloadhands-on-scala-js-d2b59cfd4d11d69f11cd69c90ad825b882328438.tar.gz
hands-on-scala-js-d2b59cfd4d11d69f11cd69c90ad825b882328438.tar.bz2
hands-on-scala-js-d2b59cfd4d11d69f11cd69c90ad825b882328438.zip
.
-rw-r--r--index.html259
1 files changed, 146 insertions, 113 deletions
diff --git a/index.html b/index.html
index 4224989..40fff10 100644
--- a/index.html
+++ b/index.html
@@ -15,7 +15,7 @@
ga('create', 'UA-27464920-4', 'auto');
ga('send', 'pageview');
- </script></head><body onload="scrollmenu.Controller().main({&quot;value&quot;:&quot;root&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Hands-on Scala.js&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Intro to Scala.js&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;About Javascript&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Javascript-the-language&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Javascript-the-platform&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;About Scala.js&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;The Language&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Sharing Code&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Client-Server Integration&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Hands On&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Getting Started&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Opening up the Project&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The Application Code&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The Project Code&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;project/build.sbt&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;build.sbt&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;src/main/resources/index-dev.html&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Publishing&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Optimization&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Blob Size&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Recap&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Making a Canvas App&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Making a Sketchpad using Mouse Input&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Making a Clock using setInterval&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Tying it together: Flappy Box&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Setting Up the Canvas&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Defining our State&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Game Logic&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;A Working Product&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Canvas Recap&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Development Speed&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Full Scala&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Seamless Javascript Interop&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Interactive Web Pages&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Hello World: HTML&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Scalatags&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;User Input&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Re-rendering&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Using Web Services&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Raw Javascript&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;dom.extensions&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Parsing the Data&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Tying it together: Weather Search&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Interactive Web Pages Recap&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;The Command Line&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Commands&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;The compile Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The package Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The fastOptJS Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The fullOptJS Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The run Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The test Command&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Headless Runtimes&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Stages&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Cross Publishing Libraries&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;A Simple Cross-Built Module&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Build Configuration&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Source Files&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Running the Module&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Integrating Client-Server&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;A Client-Server Setup&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Client-Server Reflections&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Shared Templating&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Shared Code&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Boilerplate-free Serialization&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;What's Left?&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Autowire&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Setting up Autowire&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Why Autowire?&quot;,&quot;children&quot;:[]}]}]}]},{&quot;value&quot;:&quot;In Depth&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Advanced Techniques&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Functional-Reactive UIs&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Why FRP&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;FRP with Scala.Rx&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;More Rx&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Asynchronous Workflows&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Futures &amp; Promises&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Direct Use of XMLHttpRequest&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Using dom.extensions.Ajax&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Future Combinators&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Scala-Async&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Traditional Asynchrony&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Using Scala-Async&quot;,&quot;children&quot;:[]}]}]}]},{&quot;value&quot;:&quot;Deviations from Scala-JVM&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Language Differences&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Primitive data types&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Floats can behave as Doubles by default&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;toString of Float, Double and Unit&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Runtime type tests are based on values&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Undefined behaviors&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Reflection&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Regular expressions&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Symbols&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Enumerations&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Library Differences&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Standard Library&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Macros v.s. Reflection&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Pure-Scala v.s. Java Libraries&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Javascript APIs v.s. JVM APIs&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Scala/Browser tooling v.s. Java tooling&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;The Compilation Pipeline&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Whole Program Optimizaton&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;How Compilation Works&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Compilation&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Fast Optimization&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Full Optimization&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Scala.js' Design Space&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Why No Reflection?&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Dead Code Elimination&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Whither Reflection?&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Macros&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Why does error behavior differ?&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Divide-by-zero: a case study&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The Performance/Correctness Tradeoff&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Small Executables&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Raw Verbosity&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Browsers Performance&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Deployment Size&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Java APIs&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Available Java APIs&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Porting Java APIs&quot;,&quot;children&quot;:[]}]}]}]})"><div id="layout"><a href="#menu" id="menuLink" class="menu-link"><span></span></a><div id="menu"></div></div><div id="main"><div id="main-box" class="scalatex-content" style="max-width: 840px;lineheight: 1.6em;">
+ </script></head><body onload="scrollmenu.Controller().main({&quot;value&quot;:&quot;root&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Hands-on Scala.js&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Intro to Scala.js&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;About Javascript&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Javascript-the-language&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Javascript-the-platform&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;About Scala.js&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;The Language&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Sharing Code&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Client-Server Integration&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Hands On&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Getting Started&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Opening up the Project&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The Application Code&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The Project Code&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;project/build.sbt&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;build.sbt&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;src/main/resources/index-dev.html&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Publishing&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Optimization&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Blob Size&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Recap&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Making a Canvas App&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Making a Sketchpad using Mouse Input&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Making a Clock using setInterval&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Tying it together: Flappy Box&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Setting Up the Canvas&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Defining our State&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Game Logic&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;A Working Product&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Canvas Recap&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Development Speed&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Full Scala&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Seamless Javascript Interop&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Interactive Web Pages&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Hello World: HTML&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Scalatags&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;User Input&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Re-rendering&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Using Web Services&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Raw Javascript&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;dom.extensions&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Parsing the Data&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Tying it together: Weather Search&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Interactive Web Pages Recap&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;The Command Line&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Commands&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;The compile Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The package Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The fastOptJS Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The fullOptJS Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The run Command&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The test Command&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Headless Runtimes&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Stages&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Cross Publishing Libraries&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;A Simple Cross-Built Library&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Build Configuration&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Source Files&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Running the Module&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Further Work&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Other Testing Libraries&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Integrating Client-Server&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;A Client-Server Setup&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Client-Server Reflections&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Shared Templating&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Shared Code&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Boilerplate-free Serialization&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;What's Left?&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Autowire&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Setting up Autowire&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Why Autowire?&quot;,&quot;children&quot;:[]}]}]}]},{&quot;value&quot;:&quot;In Depth&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Advanced Techniques&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Functional-Reactive UIs&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Why FRP&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;FRP with Scala.Rx&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;More Rx&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Asynchronous Workflows&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Futures &amp; Promises&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Direct Use of XMLHttpRequest&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Using dom.extensions.Ajax&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Future Combinators&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Scala-Async&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Traditional Asynchrony&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Using Scala-Async&quot;,&quot;children&quot;:[]}]}]}]},{&quot;value&quot;:&quot;Deviations from Scala-JVM&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Language Differences&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Primitive data types&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Floats can behave as Doubles by default&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;toString of Float, Double and Unit&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Runtime type tests are based on values&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Undefined behaviors&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Reflection&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Regular expressions&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Symbols&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Enumerations&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Library Differences&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Standard Library&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Macros v.s. Reflection&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Pure-Scala v.s. Java Libraries&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Javascript APIs v.s. JVM APIs&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Scala/Browser tooling v.s. Java tooling&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;The Compilation Pipeline&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Whole Program Optimizaton&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;How Compilation Works&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Compilation&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Fast Optimization&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Full Optimization&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Scala.js' Design Space&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Why No Reflection?&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Dead Code Elimination&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Whither Reflection?&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Macros&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Why does error behavior differ?&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Divide-by-zero: a case study&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;The Performance/Correctness Tradeoff&quot;,&quot;children&quot;:[]}]},{&quot;value&quot;:&quot;Small Executables&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Raw Verbosity&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Browsers Performance&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Deployment Size&quot;,&quot;children&quot;:[]}]}]},{&quot;value&quot;:&quot;Java APIs&quot;,&quot;children&quot;:[{&quot;value&quot;:&quot;Available Java APIs&quot;,&quot;children&quot;:[]},{&quot;value&quot;:&quot;Porting Java APIs&quot;,&quot;children&quot;:[]}]}]}]})"><div id="layout"><a href="#menu" id="menuLink" class="menu-link"><span></span></a><div id="menu"></div></div><div id="main"><div id="main-box" class="scalatex-content" style="max-width: 840px;lineheight: 1.6em;">
<div class="header scalatex-header scalatex-hover-container" id="Hands-onScala.js" style="display: block;"><h1>Hands-on Scala.js<a class="scalatex-header-link" href="#Hands-onScala.js" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a></h1><br /><h2>Writing client-side web applications in Scala</h2></div><div class="content">
<div class="pure-g">
<div class="pure-u-1 pure-u-md-13-24">
@@ -143,7 +143,7 @@ is a set of detailed expositions on various parts of the Scala.js platform. Noth
</p>
<h1 id="Javascript-the-platform" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#Javascript-the-platform" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>Javascript-the-platform</h1>
<p>
- However, even as Javascript-the-language sucks, Javascript-the-platform has some very nice properties that make it a good target for application developers:
+ However, even though Javascript-the-language is pretty bad, Javascript-the-platform has some very nice properties that make it a good target for application developers:
</p>
<ul>
<li>
@@ -1754,7 +1754,7 @@ In Scala.js, (1.0).toString is 1!
Not all code is developed in the browser. Maybe you want to run simple snippets of Scala.js which don't interact with the browser at all, and having to keep a browser open is an overkill. Maybe you want to write unit tests for your browser-destined code, so you can verify that it works without firing up Chrome. Maybe it's not a simple script but a re-distributable library, and you want to run the same command-line unit tests on both Scala.js and Scala-JVM to verify that the behavior is identical. This chapter will go through all these cases.
</p>
-<h1 id="ASimpleCross-BuiltModule" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#ASimpleCross-BuiltModule" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>A Simple Cross-Built Module</h1>
+<h1 id="ASimpleCross-BuiltLibrary" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#ASimpleCross-BuiltLibrary" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>A Simple Cross-Built Library</h1>
<p>
As always, we will start with an example: in this case a toy library whose sole purpose in life is to take a series of timestamps (milliseconds UTC) and format them into a single, newline-delimited string. This is what the project layout looks like:
@@ -1762,53 +1762,54 @@ In Scala.js, (1.0).toString is 1!
<pre><code class="bash scalatex-highlight-js">$ tree
.
├── build.sbt
-├── js
-│   ├── shared/main/scala/simple/Simple.scala
-│   └── src/main/scala/simple/Platform.scala
-├── jvm
-│   ├── shared -&gt; ../js/shared
-│   └── src/main/scala/simple/Platform.scala
-└── project/ build.sbt</code></pre>
+├── project/build.sbt
+└── library
+    ├── js/src/main/scala/simple/Platform.scala
+    ├── jvm/src/main/scala/simple/Platform.scala
+    └── shared/src/main/scala/simple/Simple.scala
+</code></pre>
<p>
- In this case the two <code>shared/</code> folders are symlinked together to keep them in sync. This can be done by first creating <code>js/shared</code>, and then running
+ As you can see, we have three main places where code lives: <code>js/</code> is where Scala-JS specific code lives, <code>jvm/</code> for Scala-JVM specific code, and <code>shared/</code> for code that is common between both platforms. Depending on your project, you may have more or less code in the <code>shared/</code> folder: a mostly-the-same cross-compiled module may have most or all its code in <code>shared/</code> while a <a href="#IntegratingClient-Server">client-server web application</a> would have lots of client/server js/jvm-specific code.
</p>
- <pre><code class="bash scalatex-highlight-js">$ ln -s ../js/shared jvm/shared
-</code></pre>
<h2 id="BuildConfiguration" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#BuildConfiguration" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>Build Configuration</h2>
<p>
From the bash shell in the project root. Let's take a look at the various files that make up this project. First, the <code>build.sbt</code> files:
</p>
<pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">/*project/build.sbt*/
-addSbtPlugin(&quot;org.scala-js&quot; % &quot;sbt-scalajs&quot; % &quot;0.6.0-RC2&quot;)</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/project/build.sbt#L0-L2" target="_blank"><i class="fa fa-link "></i></a></pre>
+addSbtPlugin(&quot;org.scala-js&quot; % &quot;sbt-scalajs&quot; % &quot;0.6.0&quot;)</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/project/build.sbt#L0-L2" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
The <code>project/build.sbt</code> file is uneventful: it simply includes the Scala.js SBT plugin. However, the <code>build.sbt</code> file is a bit more interesting:
</p>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">val sharedSettings = Seq(
- unmanagedSourceDirectories in Compile +=
- baseDirectory.value / &quot;shared&quot; / &quot;main&quot; / &quot;scala&quot;
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">
+val library = crossProject.settings(
+ libraryDependencies += &quot;com.lihaoyi&quot; %%% &quot;utest&quot; % &quot;0.3.0&quot;,
+ testFrameworks += new TestFramework(&quot;utest.runner.Framework&quot;)
+).jsSettings(
+ // JS-specific settings here
+).jvmSettings(
+ // JVM-specific settings here
)
-lazy val js = project.in(file(&quot;js&quot;)).enablePlugins(ScalaJSPlugin)
- .settings(sharedSettings:_*)
+lazy val js = library.js
-lazy val jvm = project.in(file(&quot;jvm&quot;)).settings(sharedSettings:_*)</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/build.sbt#L0-L9" target="_blank"><i class="fa fa-link "></i></a></pre>
+lazy val jvm = library.jvm</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/build.sbt#L0-L13" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
- Unlike the equivalent <code>build.sbt</code> files you saw in earlier chapters, this does not simply enable the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">ScalaJSPlugin</code> to the root project. Rather, it sets up two projects: one in the <code>js/</code> folder and one in the <code>jvm/</code> folder, with the <code>js/</code> version getting the Scala.js plugin. To both of these, we add <code>shared/main/scala</code> to the list of source directories. This means that both projects will pick up the sources we symlinked between <code>js/shared/</code> and <code>jvm/shared/</code>.
+ Unlike the equivalent <code>build.sbt</code> files you saw in earlier chapters, this does not simply enable the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">ScalaJSPlugin</code> to the root project. Rather, it uses the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">crossProject</code> function provided by the Scala.js plugin to set up two projects: one in the <code>app/js/</code> folder and one in the <code>jvm/</code> folder. We also have places to put settings related to either the JS side, the JVM side, or both. In this case, we add a dependency on <a href="https://github.com/lihaoyi/utest">uTest</a>, which we will use as the test framework for our library. Note how we use triple <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">%%%</code> to indicate that we're using the platform-specific version of uTest, such that the Scala.js or Scala-JVM version will be properly pulled in when compiling for each platform.
</p>
<h2 id="SourceFiles" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#SourceFiles" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>Source Files</h2>
<p>
Now, let's look at the contents of the <code>.scala</code> files that make up the meat of this project:
</p>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">/*shared/main/scala/simple/Simple.scala*/
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">// library/shared/src/main/scala/simple/Simple.scala
package simple
object Simple{
def formatTimes(timestamps: Seq[Long]): Seq[String] = {
timestamps.map(Platform.format).map(_.dropRight(5))
}
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/js/shared/main/scala/simple/Simple.scala#L0-L7" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/library/shared/src/main/scala/simple/Simple.scala#L0-L7" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
In <code>Simple.scala</code> we have the shared, cross-platform API of our library: a single <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">object</code> with a single method <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">def</code> which does what we want, which can then be used in either Scala.js or Scala-JVM. In general, you can put as much shared logic here as you want: classes, objects, methods, anything that can run on both Javascript and on the JVM. We're chopping off the last 5 characters (the milliseconds) to keep the formatted dates slightly less verbose.
@@ -1818,29 +1819,21 @@ object Simple{
</p>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">//js/src/main/scala/simple/Platform.scala
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">// library/js/src/main/scala/simple/Platform.scala
package simple
import scalajs.js
-object Platform extends js.JSApp{
+object Platform{
def format(ts: Long) = {
new js.Date(ts).toISOString()
}
- def main() = {
- val times = Seq(
- 0L,
- 1L &lt;&lt; 32
- )
- println(&quot;Running on JS! &quot; + 1.0d)
- println(Simple.formatTimes(times))
- }
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/js/src/main/scala/simple/Platform.scala#L0-L17" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/library/js/src/main/scala/simple/Platform.scala#L0-L9" target="_blank"><i class="fa fa-link "></i></a></pre>
</div>
<div class="pure-u-1 pure-u-md-1-2">
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">//jvm/src/main/scala/simple/Platform.scala
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">// library/jvm/src/main/scala/simple/Platform.scala
package simple
import java.text.SimpleDateFormat
-import java.util.{TimeZone, Locale}
+import java.util.TimeZone
object Platform{
def format(ts: Long) = {
@@ -1850,49 +1843,95 @@ object Platform{
fmt.setTimeZone(TimeZone.getTimeZone(&quot;UTC&quot;))
fmt.format(new java.util.Date(ts))
}
- def main(args: Array[String]) = {
- val times = Seq(
- 0L,
- 1L &lt;&lt; 32
- )
- println(&quot;Running on JVM! &quot; + 1.0d)
- println(Simple.formatTimes(times))
- }
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/jvm/src/main/scala/simple/Platform.scala#L0-L22" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/simple/library/jvm/src/main/scala/simple/Platform.scala#L0-L14" target="_blank"><i class="fa fa-link "></i></a></pre>
</div></div>
<p>
In the <code>js/</code> version, we are using the Javascript <code class="javascript scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Date</code> object to take the millis and do what we want. In the <code>jvm/</code> version, we instead use <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">java.text.SimpleDateFormat</code> with a custom formatter (The syntax is defined <a href="http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html">here</a>).
</p>
<p>
- Again, you can put as much platform-specific logic in these files as you want, to account for differences in the available APIs. Maybe you want to use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">Json.parse</a> for parsing JSON blobs in <code>js/</code>, but <a href="http://jackson.codehaus.org/">Jackson</a> or <a href="https://code.google.com/p/google-gson/">GSON</a> for parsing them in <code>jvm/</code>.</p>
- <p>
- Lastly, you'll also have noticed the two identical <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">main</code> methods in the platform-specific code. This is an implementation detail around the fact that Scala.js picks up the main method differently from Scala-JVM, using <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">js.JSApp</code> instead of looking for a <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">main(args: Array[String]): Unit</code> method. These two main methods allow us to test our implementations</p>
+ Again, you can put as much platform-specific logic in these files as you want, to account for differences in the available APIs. Maybe you want to use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">Json.parse</a> for parsing JSON blobs in <code>js/</code>, but <a href="http://jackson.codehaus.org/">Jackson</a> or <a href="https://code.google.com/p/google-gson/">GSON</a> for parsing them in <code>jvm/</code>.
+</p>
<h2 id="RunningtheModule" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#RunningtheModule" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>Running the Module</h2>
- <pre><code class="bash scalatex-highlight-js">&gt; ; js/run; jvm/run
-[info] Running simple.Platform
-Running on JS! 1
-November 2, 2014 2:58:48 PM PST
-November 2, 2014 2:58:49 PM PST
-[success] Total time: 4 s, completed Nov 2, 2014 2:58:48 PM
-[info] Running simple.Platform
-Running on JVM! 1.0
-November 2, 2014 2:58:49 PM PST
-November 2, 2014 2:58:50 PM PST
-[success] Total time: 0 s, completed Nov 2, 2014 2:58:49 PM
+ <pre><code class="bash scalatex-highlight-js">&gt; ;libraryJS/test ;libraryJVM/test
+[info] Compiling 1 Scala source to library/js/target/scala-2.10/test-classes...
+[info] ---------------------------Results---------------------------
+[info] simple.SimpleTest Success
+[info] format Success
+[info] nil Success
+[info] timeZero Success
+[info] zero Success
+[info] 0
+[info]
+[info] Tests: 5
+[info] Passed: 5
+[info] Failed: 0
+[success] Total time: 12 s, completed Feb 4, 2015 8:44:49 AM
+[info] Compiling 1 Scala source to library/jvm/target/scala-2.10/test-classes...
+[info] 1/5 simple.SimpleTest.format.nil Success
+[info] 2/5 simple.SimpleTest.format.timeZero Success
+[info] 3/5 simple.SimpleTest.format Success
+[info] 4/5 simple.SimpleTest.zero Success
+[info] 0.0
+[info] 5/5 simple.SimpleTest Success
+[info] ---------------------------Results---------------------------
+[info] simple.SimpleTest Success
+[info] format Success
+[info] nil Success
+[info] timeZero Success
+[info] zero Success
+[info] 0.0
+[info]
+[info] Tests: 5
+[info] Passed: 5
+[info] Failed: 0
+[success] Total time: 2 s, completed Feb 4, 2015 8:44:51 AM
</code></pre>
<p>
As you can see, both runs printed the same results, modulo three things:
</p>
<ul>
<li>
- The &quot;Running on XXX!&quot; statement which shows us we're actually running on two platforms.</li>
+ The <code>&quot;Compiling 1 Scala source to...&quot;</code> line, which tells us that both JS and JVM versions are being compiled.</li>
<li>
- The other hint is the time taken: the second run is instant while the first takes three seconds! This is because by default we run on <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino">Rhino</a>, which is a simple interpreter hundreds of times slower than running code natively on the JVM.</li>
+ The time taken: the second run is instant while the first takes eleven seconds! This is because by default we run on <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino">Rhino</a>, which is a simple interpreter hundreds of times slower than running code natively on the JVM.</li>
<li>
In Scala-JVM the double 1.0 is printed as <code>1.0</code>, while in Scala.js it's printed as <code>1</code>. This is one of a small number of differences between Scala.js and Scala-JVM, and verifies that we are indeed running on both platforms!
</li></ul>
<p>
- You've by this point set up a basic cross-building Scala.js/Scala-JVM project!</p>
+ Apart from running each sub-project manually as we did above, you can also simply hit <code>test</code> and SBT will run tests for both
+</p>
+<h1 id="FurtherWork" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#FurtherWork" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>Further Work</h1>
+ <p>
+ You've by this point set up a basic cross-building Scala.js/Scala-JVM project! If you wish, you can do more things with this project you've set up:
+</p>
+ <ul>
+ <li>
+ Flesh it out! Currently this module only does a single, trivial thing. If you've done any web development before, I'm sure you can find some code snippet, function or algorithm that you'd like to share between client and server. Try implementing it in the <code>shared/</code> folder to be usable in both Scala.js and Scala-JVM</li>
+ <li>
+ Publish it! Both <code>sbt publishLocal</code> and <code>sbt publishSigned</code> work on this module, for publishing either locally, Maven Central via Sonatype, or Bintray. Running the command bare should be sufficient to publish both the <code>js</code> or <code>jvm</code> projects, or you can also specify which one e.g. <code>jvm/publishLocal</code> to publish only one subproject.</li>
+ <li>
+ Cross-cross build it! You can use <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">crossScalaVersions</code> in your <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">crossProject</code> to build a library that works across all of {Scala.js, Scala-JVM} X {2.10, 2.11}. Many existing libraries, such as <a href="https://github.com/lihaoyi/scalatags">Scalatags</a> or <a href="https://github.com/lihaoyi/utest">uTest</a> are published like that.
+</li></ul>
+ <p>
+ Now that you've gotten your code cross-compiling to Scala.js/Scala-JVM, the sky's the limit in what you can do. In general, although a large amount of your Scala-JVM code <i>does</i> deal with files or networks or other Scala-JVM-speciic functionality, in most applications there is a large library of helpers which don't. These could easily be packaged up into a cross-platform library and shared with your front-end Scala.js (or even pure-Javascript!) code.
+</p>
+<h1 id="OtherTestingLibraries" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#OtherTestingLibraries" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>Other Testing Libraries</h1>
+ <p>
+ You can also try using a different testing library. While uTest was the first Scala.js testing library, it is definitely not the last! Here are a few alternatives worth trying:
+</p>
+ <ul>
+ <li>
+ <a href="https://github.com/monifu/minitest">Minitest</a></li>
+ <li>
+ <a href="https://github.com/InTheNow/zcheck">zCheck</a></li>
+ <li>
+ <a href="https://github.com/cgta/otest">oTest</a>
+</li></ul>
+ <p>
+ These (and others) are built and maintained by members of the community, so if one of them does not fit your tastes, it is worth trying the others.
+</p>
+ <p>
+ Note that you cannot use <a href="http://www.scalatest.org/">Scalatest</a> or <a href="http://etorreborre.github.io/specs2">Specs2</a> in Scala.js. Despite the popularity of those libraries, they depend on too many Java-specific details of Scala-JVM to be easily ported to Scala.js. Thus you'll have to use one of the (relatively new) libraries which supports Scala.js, such as uTest or those above.</p>
<div class="header scalatex-header scalatex-hover-container" id="IntegratingClient-Server" style="display: block;"><h1 id="IntegratingClient-Server">Integrating Client-Server<a class="scalatex-header-link" href="#IntegratingClient-Server" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a></h1><br /></div>
@@ -1917,62 +1956,54 @@ November 2, 2014 2:58:50 PM PST
<h1 id="AClient-ServerSetup" style="display: block;" class="scalatex-header scalatex-hover-container"><a class="scalatex-header-link" href="#AClient-ServerSetup" style="position: absolute;right: 0;"><i class="fa fa-link"></i></a>A Client-Server Setup</h1>
<p>
- Getting started with client-server integration, let's go with the simplest configuration possible: a Spray server and a Scala.js client. Most of the other web-frameworks (<a href="https://www.playframework.com/">Play</a>, <a href="http://www.scalatra.org/">Scalatra</a>, etc.) will have more complex configurations, but the basic mechanism of wiring up Scala.js to your web framework will be the same. Our project will look like this:
+ Getting started with client-server integration, let's go with the simplest configuration possible: a Spray server and a Scala.js client. Most of the other web-frameworks (<a href="https://www.playframework.com/">Play</a>, <a href="http://www.scalatra.org/">Scalatra</a>, etc.) will have more complex configurations, but the basic mechanism of wiring up Scala.js to your web framework will be the same. Just like our project in <a href="#CrossPublishingLibraries">Cross Publishing Libraries</a>, our project will look like this:
</p>
<pre><code class="bash scalatex-highlight-js">$ tree
.
├── build.sbt
-├── client
-│   ├── shared/main/scala/simple/FileData.scala
-│   └── src/main/scala/simple/Client.scala
-├── project
-│   └── build.sbt
-└── server
- ├── shared -&gt; ../client/shared
- └── src/main/scala/simple
- ├── Page.scala
- └── Server.scala
+├── project/build.sbt
+└── app
+    ├── shared/src/main/scala/simple/FileData.scala
+    ├── js/src/main/scala/simple/Client.scala
+    └── jvm/src/main/scala/simple/
+ ├── Page.scala
+ └── Server.scala
</code></pre>
<p>
First, let's do the wiring in <code>build.sbt</code>:
</p>
<pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">import NativePackagerKeys._
-val sharedSettings = Seq(
+
+val app = crossProject.settings(
unmanagedSourceDirectories in Compile +=
baseDirectory.value / &quot;shared&quot; / &quot;main&quot; / &quot;scala&quot;,
libraryDependencies ++= Seq(
&quot;com.lihaoyi&quot; %%% &quot;scalatags&quot; % &quot;0.4.5&quot;,
- &quot;com.lihaoyi&quot; %%% &quot;upickle&quot; % &quot;0.2.7&quot;
+ &quot;com.lihaoyi&quot; %%% &quot;upickle&quot; % &quot;0.2.6&quot;
),
scalaVersion := &quot;2.11.5&quot;
-)
-
-lazy val client = project.in(file(&quot;client&quot;))
- .enablePlugins(ScalaJSPlugin)
- .settings(sharedSettings:_*)
- .settings(
+).jsSettings(
libraryDependencies ++= Seq(
&quot;org.scala-js&quot; %%% &quot;scalajs-dom&quot; % &quot;0.8.0&quot;
)
-)
-
-lazy val server = project.in(file(&quot;server&quot;))
- .settings(sharedSettings:_*)
- .settings(packageArchetype.java_application:_*)
- .settings(
+).jvmSettings(
libraryDependencies ++= Seq(
&quot;io.spray&quot; %% &quot;spray-can&quot; % &quot;1.3.2&quot;,
&quot;io.spray&quot; %% &quot;spray-routing&quot; % &quot;1.3.2&quot;,
&quot;com.typesafe.akka&quot; %% &quot;akka-actor&quot; % &quot;2.3.6&quot;
- ),
- (resources in Compile) += (fastOptJS in (client, Compile)).value.data
-)</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/build.sbt#L0-L31" target="_blank"><i class="fa fa-link "></i></a></pre>
+ )
+)
+
+lazy val appJS = app.js
+lazy val appJVM = app.jvm.settings(
+ (resources in Compile) += (fastOptJS in (appJS, Compile)).value.data
+)</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/build.sbt#L0-L26" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
- We have two projects: <code>client</code> and <code>server</code>, one of which is a Scala.js project (indicated by the presence of <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">enablePlugins(ScalaJSPlugin)</code>). Both projects share a number of settings: the presence of the <code>shared/</code> folder, which shared code can live in (similar to what we saw in <a href="#CrossPublishingLibraries">Cross Publishing Libraries</a>) and the settings to add <a href="https://github.com/lihaoyi/scalatags">Scalatags</a> and <a href="https://github.com/lihaoyi/upickle">uPickle</a> to the build. Note that those two dependencies use the triple <code>%%%</code> instead of the double <code>%%</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 <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">packageArchetype.java_application</code> 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.
+ Again, we are using <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">crossProject</code> to define our <code>js/</code> and <code>jvm/</code> sub-projects. Both projects share a number of settings: the settings to add <a href="https://github.com/lihaoyi/scalatags">Scalatags</a> and <a href="https://github.com/lihaoyi/upickle">uPickle</a> to the build. Note that those two dependencies use the triple <code>%%%</code> instead of the double <code>%%</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 <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">packageArchetype.java_application</code> 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>
<p>
- The <code>client</code> subproject is uneventful, with a dependency on the by-now-familiar <code>scalajs-dom</code> library. The <code>server</code> 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</code> from the client to the <code>resources</code> on the server. This will allow the <code>server</code> to serve the compiled-javascript from our <code>client</code> project from its resources.
+ The <code>js/</code> sub-project is uneventful, with a dependency on the by-now-familiar <code>scalajs-dom</code> library. The <code>jvm/</code> 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</code> from the client to the <code>resources</code> on the server. This will allow the <code>server</code> to serve the compiled-javascript from our <code>client</code> project from its resources.
</p>
<p>
Next, let's kick off the Spray server in our Scala-JVM main method:
@@ -2023,7 +2054,7 @@ object Server extends SimpleRoutingApp{
if f.getName.startsWith(last)
} yield FileData(f.getName, f.length())
}
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/server/src/main/scala/simple/Server.scala#L0-L46" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/jvm/src/main/scala/simple/Server.scala#L0-L46" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
This is a not-very-interesting <a href="http://spray.io/documentation/1.2.2/spray-routing/">spray-routing</a> application: we set up a server on <code>localhost:8080</code>, have the root URL serve the main page on GET, and have other GET URLs serve resources. This includes the <code>js-fastopt.js</code> file that is now in our resources because of our <code>build.sbt</code> config earlier! We also add a POST route to allow the client ask the server to list files various directories.
@@ -2040,7 +2071,7 @@ object Page{
val skeleton =
html(
head(
- script(src:=&quot;/client-fastopt.js&quot;),
+ script(src:=&quot;/appjs-fastopt.js&quot;),
link(
rel:=&quot;stylesheet&quot;,
href:=&quot;https://cdnjs.cloudflare.com/ajax/libs/pure/0.5.0/pure-min.css&quot;
@@ -2051,7 +2082,7 @@ object Page{
div(id:=&quot;contents&quot;)
)
)
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/server/src/main/scala/simple/Page.scala#L0-L21" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/jvm/src/main/scala/simple/Page.scala#L0-L21" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
This is a typical <a href="https://github.com/lihaoyi/scalatags">Scalatags</a> HTML snippet. Note that since we're serving it directly from the server in Scala code, we do not need to leave a <code>.html</code> file somewhere on the filesystem! We can declare all HTML, including the skeleton of the page, in Scalatags. Otherwise it's the same as what we saw in earlier chapters: A simple HTML page which includes a script tag to run our Scala.js application.</p>
@@ -2063,7 +2094,8 @@ object Page{
import scalatags.JsDom.all._
import scalajs.concurrent.JSExecutionContext.Implicits.runNow
import org.scalajs.dom
-import dom.extensions.Ajax
+import dom.html
+import dom.ext.Ajax
import scalajs.js.annotation.JSExport
@JSExport
@@ -2093,7 +2125,7 @@ object Client extends{
).render
)
}
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/client/src/main/scala/simple/Client.scala#L0-L36" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/js/src/main/scala/simple/Client.scala#L0-L37" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Again this is a simple Scala.js application, not unlike what we saw in earlier chapters. However, there is one difference: earlier, we made our Ajax calls to <code>api.openweathermap.org/...</code>. Here, we're making it to <code>/ajax</code>: the same server the page is served from!
@@ -2104,7 +2136,7 @@ object Client extends{
</p>
<pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">package simple
-case class FileData(name: String, size: Long)</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/client/shared/main/scala/simple/FileData.scala#L0-L3" target="_blank"><i class="fa fa-link "></i></a></pre>
+case class FileData(name: String, size: Long)</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/shared/src/main/scala/simple/FileData.scala#L0-L3" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Now, if we go to the browser at <code>localhost:8080</code>, we should see our web-page!
@@ -2151,10 +2183,10 @@ case class FileData(name: String, size: Long)</code><a class="scalatex-header-li
<p>
However, there is still some amount of duplication in the code. In particular, the definition of the endpoint name &quot;list&quot; is duplicated 4 times:
</p>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">path(&quot;ajax&quot; / &quot;list&quot;){</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/server/src/main/scala/simple/Server.scala#L25-L26" target="_blank"><i class="fa fa-link "></i></a></pre>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">upickle.write(list(e))</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/server/src/main/scala/simple/Server.scala#L28-L29" target="_blank"><i class="fa fa-link "></i></a></pre>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def list(path: String) = {</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/server/src/main/scala/simple/Server.scala#L35-L36" target="_blank"><i class="fa fa-link "></i></a></pre>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajax.post(&quot;/ajax/list&quot;, inputBox.value).foreach{ xhr =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/client/src/main/scala/simple/Client.scala#L14-L15" target="_blank"><i class="fa fa-link "></i></a></pre>
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">path(&quot;ajax&quot; / &quot;list&quot;){</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/jvm/src/main/scala/simple/Server.scala#L25-L26" target="_blank"><i class="fa fa-link "></i></a></pre>
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">upickle.write(list(e))</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/jvm/src/main/scala/simple/Server.scala#L28-L29" target="_blank"><i class="fa fa-link "></i></a></pre>
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def list(path: String) = {</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/jvm/src/main/scala/simple/Server.scala#L35-L36" target="_blank"><i class="fa fa-link "></i></a></pre>
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajax.post(&quot;/ajax/list&quot;, inputBox.value).foreach{ xhr =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/js/src/main/scala/simple/Client.scala#L15-L16" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Three times on the server and once on the client! What's worse, two of the appearances of <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">&quot;list&quot;</code> are in string literals, which are not checked by the compiler to match up with themselves or the name of the method <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">list</code>. Apart from this, there is one other piece of duplication that is unchecked: the type being returned from <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">list</code> (<code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Seq[FileData]</code>) is being repeated on the client in <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">upickle.read[Seq[FileData]]</code> in order to de-serialize the serialized data. This leaves three opportunities for error wide-open:
@@ -2177,13 +2209,13 @@ case class FileData(name: String, size: Long)</code><a class="scalatex-header-li
<p>
<a href="https://github.com/lihaoyi/autowire">Autowire</a> is a library that turns your request routing layer from a fragile, hand-crafted mess into a solid, type-checked, boilerplate-free experience. Autowire basically turns what was previously a stringly-typed, hand-crafted Ajax call and route:
</p>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajax.post(&quot;/ajax/list&quot;, inputBox.value).foreach{ xhr =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/client/src/main/scala/simple/Client.scala#L14-L15" target="_blank"><i class="fa fa-link "></i></a></pre>
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajax.post(&quot;/ajax/list&quot;, inputBox.value).foreach{ xhr =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver/app/js/src/main/scala/simple/Client.scala#L15-L16" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Into a safe, type-checked function call:
</p>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajaxer[Api].list(inputBox.value).call().foreach{ data =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/client/src/main/scala/simple/Client.scala#L25-L26" target="_blank"><i class="fa fa-link "></i></a></pre>
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajaxer[Api].list(inputBox.value).call().foreach{ data =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/js/src/main/scala/simple/Client.scala#L26-L27" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Let's see how we can do that.
@@ -2210,7 +2242,7 @@ case class FileData(name: String, size: Long)
trait Api{
def list(path: String): Seq[FileData]
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/client/shared/main/scala/simple/Shared.scala#L0-L7" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/shared/src/main/scala/simple/Shared.scala#L0-L7" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Here, you can see that in addition to sharing the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">FileData</code> class, we are also creating an <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Api</code> trait which contains the signature of our <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">list</code> method. The exact name of the trait doesn't matter. We need it to be in <code>shared/</code> so that the code in both client and server can reference it.
@@ -2271,7 +2303,7 @@ object Server extends SimpleRoutingApp with Api{
if f.getName.startsWith(last)
} yield FileData(f.getName, f.length())
}
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/server/src/main/scala/simple/Server.scala#L0-L54" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/jvm/src/main/scala/simple/Server.scala#L0-L54" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Now, instead of hard-coding the route <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">&quot;ajax&quot; / &quot;list&quot;</code>, we now take in any route matching <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">&quot;ajax&quot; / Segments</code>, feeding the resultant path segments into the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Router</code> object:
@@ -2287,14 +2319,14 @@ object Server extends SimpleRoutingApp with Api{
)
}
}
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/server/src/main/scala/simple/Server.scala#L28-L40" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/jvm/src/main/scala/simple/Server.scala#L28-L40" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
The <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Router</code> object in turn simply defines how you intend the objects to be serialized and deserialized:
</p>
<pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">object Router extends autowire.Server[String, upickle.Reader, upickle.Writer]{
def read[Result: upickle.Reader](p: String) = upickle.read[Result](p)
def write[Result: upickle.Writer](r: Result) = upickle.write(r)
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/server/src/main/scala/simple/Server.scala#L7-L12" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/jvm/src/main/scala/simple/Server.scala#L7-L12" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
In this case using uPickle. Note how the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">route</code> call explicitly states the type (here <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Api</code>) that it is to generate routes against; this ensures that only methods which you explicitly put in your public interface <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Api</code> are publically reachable.
@@ -2305,13 +2337,14 @@ object Server extends SimpleRoutingApp with Api{
<pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">package simple
import scalatags.JsDom.all._
import org.scalajs.dom
+import dom.html
import scalajs.js.annotation.JSExport
import scalajs.concurrent.JSExecutionContext.Implicits.runNow
import autowire._
object Ajaxer extends autowire.Client[String, upickle.Reader, upickle.Writer]{
override def doCall(req: Request) = {
- dom.extensions.Ajax.post(
+ dom.ext.Ajax.post(
url = &quot;/ajax/&quot; + req.path.mkString(&quot;/&quot;),
data = upickle.write(req.args)
).map(_.responseText)
@@ -2347,14 +2380,14 @@ object Client extends{
).render
)
}
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/client/src/main/scala/simple/Client.scala#L0-L46" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/js/src/main/scala/simple/Client.scala#L0-L47" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
There are two main modifications here: the existence of the new <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Ajaxer</code> object, and the modification to the Ajax call-site. Let's first look at <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Ajaxer</code>:
</p>
<pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">object Ajaxer extends autowire.Client[String, upickle.Reader, upickle.Writer]{
override def doCall(req: Request) = {
- dom.extensions.Ajax.post(
+ dom.ext.Ajax.post(
url = &quot;/ajax/&quot; + req.path.mkString(&quot;/&quot;),
data = upickle.write(req.args)
).map(_.responseText)
@@ -2362,7 +2395,7 @@ object Client extends{
def read[Result: upickle.Reader](p: String) = upickle.read[Result](p)
def write[Result: upickle.Writer](r: Result) = upickle.write(r)
-}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/client/src/main/scala/simple/Client.scala#L7-L19" target="_blank"><i class="fa fa-link "></i></a></pre>
+}</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/js/src/main/scala/simple/Client.scala#L8-L20" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
Like the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Router</code> object, <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Ajaxer</code> also defines how you perform the serialization and deserialization of data-structures, again using uPickle. Unlike the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Router</code> object, <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Ajaxer</code> also defines how the out-going Ajax call gets sent over the network. Here we're doing it using the <code class="scala scalatex-highlight-js" style="display: inline;padding: 0;margin: 0;">Ajax.post</code> method.
@@ -2370,7 +2403,7 @@ object Client extends{
<p>
Lastly, let's look at the modified callsite for the ajax call itself:
</p>
- <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajaxer[Api].list(inputBox.value).call().foreach{ data =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/client/src/main/scala/simple/Client.scala#L25-L26" target="_blank"><i class="fa fa-link "></i></a></pre>
+ <pre class="scalatex-hover-container"><code class="scala scalatex-highlight-js hljs">def update() = Ajaxer[Api].list(inputBox.value).call().foreach{ data =&gt;</code><a class="scalatex-header-link" style="position: absolute;right: 0.5em;top: 0.5em;display: block;font-size: 24px;" href="https://github.com/lihaoyi/hands-on-scala-js/blob/master/examples/crossBuilds/clientserver2/app/js/src/main/scala/simple/Client.scala#L26-L27" target="_blank"><i class="fa fa-link "></i></a></pre>
<p>
There are a few things of note here: