New Scala.js SinglePageApplication tutorial released

1,276 views
Skip to first unread message

Otto Chrons

unread,
Feb 10, 2015, 4:15:59 PM2/10/15
to scal...@googlegroups.com
Hi!

After spending countless hours during the past week banging my head against a wall figuring out some silly simple things with Scala.js, I created a tutorial so that others might avoid those same walls :)

It focuses on demonstrating practical things you need when building a client-server SPA with Scala.js and Spray. It utilizes scalajs-react, autowire and uPickle libraries.


All comments and improvement suggestions are more than welcome, preferably on Gitter chat at https://gitter.im/ochrons/scalajs-spa-tutorial

- Otto

Simone Scarduzio

unread,
Feb 10, 2015, 6:18:06 PM2/10/15
to scal...@googlegroups.com
Great job Otto, exactly what I was looking for :)

Ngoc Dao

unread,
Feb 11, 2015, 11:29:05 PM2/11/15
to scal...@googlegroups.com
Great tutorial.
Thanks for sharing.

Egon Nijns

unread,
Feb 12, 2015, 4:07:19 PM2/12/15
to scal...@googlegroups.com
That's a great tutorial! Thanks!

Since you're asking: I'd like to find out how to deal with authentication and authorization when using autowire. The authentication part seems simple, but what if I'd like certain methods of my API to only be accessible to certain kind of users? Just split up the API for each role (e.g. a public API and an API for administrators)?

Egon

Egon Nijns

unread,
Feb 12, 2015, 4:24:21 PM2/12/15
to Justin du coeur, scal...@googlegroups.com
I've toyed around with these ideas a while ago and now I remember where exactly I was stuck. Sometimes you need to know who is calling into your code and you can't just pass it as an extra argument from the client (never trust the clients). In the old days I would just have a session with a user object in it and magically access it from the request.


2015-02-12 22:18 GMT+01:00 Justin du coeur <jduc...@gmail.com>:
On Thu, Feb 12, 2015 at 4:07 PM, Egon Nijns <egon....@gmail.com> wrote:
That's a great tutorial! Thanks!

Since you're asking: I'd like to find out how to deal with authentication and authorization when using autowire. The authentication part seems simple, but what if I'd like certain methods of my API to only be accessible to certain kind of users? Just split up the API for each role (e.g. a public API and an API for administrators)?

There's no one-size fits all answer (for instance, authorization is much more complex in my app), but that seems like a good approach.  If you do it this way, you can do your authorization checks before invoking the Autowire router, and the individual Autowire entry points don't need to worry about it...

Justin du coeur

unread,
Feb 12, 2015, 4:26:36 PM2/12/15
to Egon Nijns, scal...@googlegroups.com
I wound up using an object-per-call architecture: there is an implementation class matching each Autowire trait, and I create an instance of that for each invocation.  I pass session-contextual information such as the caller in as constructor parameters to that...

Justin du coeur

unread,
Feb 12, 2015, 4:30:57 PM2/12/15
to Egon Nijns, scal...@googlegroups.com
Actually -- Otto, that's a useful enough model that you might want to incorporate it into your tutorial.  I put quite a lot of work into my original approach (with a single implementation object) before realizing that I really needed instance-per-call to deal with complex problems; I lost a couple of days rewriting everything once I figured that out.

I suspect that for serious code you *typically* want instance-per-call, because there is so often external context that you need to inject into the implementation, and we might want to encourage folks to think that way...

Egon Nijns

unread,
Feb 12, 2015, 4:32:27 PM2/12/15
to Justin du coeur, scal...@googlegroups.com

Good idea. Thanks for sharing Justin.

I really hope to find some time soon to pick up all this stuff again...

Op 12-feb.-2015 22:26 schreef "Justin du coeur" <jduc...@gmail.com>:

Justin du coeur

unread,
Feb 12, 2015, 4:18:51 PM2/12/15
to Egon Nijns, scal...@googlegroups.com
On Thu, Feb 12, 2015 at 4:07 PM, Egon Nijns <egon....@gmail.com> wrote:
That's a great tutorial! Thanks!

Since you're asking: I'd like to find out how to deal with authentication and authorization when using autowire. The authentication part seems simple, but what if I'd like certain methods of my API to only be accessible to certain kind of users? Just split up the API for each role (e.g. a public API and an API for administrators)?

Otto Chrons

unread,
Feb 13, 2015, 6:26:46 AM2/13/15
to scal...@googlegroups.com, egon....@gmail.com
Why not just the traditional session cookie -based authorization? Server assigns a cookie when you authenticate and each request comes with that cookie which the server can again authorize. Then the question is only about how Autowire can incorporate session/user/authorization information in the "Api" call.

Perhaps Haoyi can share some thoughts on how to incorporate "session" data in Autowire?

- Otto

Justin du coeur

unread,
Feb 13, 2015, 8:16:43 AM2/13/15
to Otto Chrons, scal...@googlegroups.com, Egon Nijns
On Fri, Feb 13, 2015 at 6:26 AM, Otto Chrons <otto....@gmail.com> wrote:
Why not just the traditional session cookie -based authorization? Server assigns a cookie when you authenticate and each request comes with that cookie which the server can again authorize. Then the question is only about how Autowire can incorporate session/user/authorization information in the "Api" call.

Perhaps Haoyi can share some thoughts on how to incorporate "session" data in Autowire?

That's essentially what I'm saying: you use standard authentication mechanisms using session cookies.  But the thing is, in my experience you usually need to use some of that session information in your Autowire API handler, and Autowire is (deliberately, I believe) silent on that subject.  So you need to "inject" it into the handler somehow, external to the API itself.  There aren't a huge number of good ways to do that, and I've found that, given the asynchronous nature of Autowire, instance-per-request seems to be the easiest and most robust.

Haoyi, what's your take?

Otto Chrons

unread,
Feb 13, 2015, 3:04:55 PM2/13/15
to scal...@googlegroups.com
I did a bit of refactoring after a good discussion with @japgolly and released a new version of the tutorial.
  • Refactored the router system to follow the intended design of the Scala.js React router (thanks to @japgolly for feedback)
  • Separated MainMenu into its own component as part of the router refactoring
  • Updated libraries scalajs-dom and scalajs-react to 0.8.0
  • Changed all tags to use <^ prefixes (less potential for name conflicts)
  • Documentation updated to reflect the changes
Functionally it's identical to the previous release, but the code should be more "best practices".

- Otto

Egon Nijns

unread,
Feb 15, 2015, 9:59:48 AM2/15/15
to scal...@googlegroups.com
Are you using an IDE for development?
I'm trying to load the project in IntelliJ (using SBT project import), but I'm having some troubles...
(I'm using the latest IntelliJ EAP and latest Scala EAP releases)

Aliquip

unread,
Feb 15, 2015, 10:58:11 AM2/15/15
to scal...@googlegroups.com
Intellij's auto import of sbt projects seems beyond hopeless to me. Even if you manage to have idea auto import a sbt configuraion the solution seems so hackish that it feels bound to break in an update of idea or a change in your sbt. So the (non) solution is to not use intellij's auto import and just create an empty project from scratch, mark the folders with sources as sources, if you want add multiple modules (shares/js/jvm) set module-module dependencies etc all manually in idea. (This also means is not really possible to use sbt in the ide to run your tests and such, but for that you have sbt anyways, it's not the nicest workflow to switch between console for sbt and ide for coding, but atleast it works)

The biggest hurdle to manually setup the ide and directory structure for me was adding the library dependencies, i didn't want to keep my external dependancies in sync manually between ide and sbt. In the end i used https://github.com/xerial/sbt-pack to package the sbt project(s), this creates a lib folder with all jars. Then in intellij add these directories to the module's depencies. One gotcha: sbt-pack isn't meant for this, apart from packaging all dependencies it also adds the current project as a jar, you'd want to (manually) remove this jar.

So step by step
  1. clone/copy the project to your filesystem in path/scalajs-spa-tutorial
  2. add sbt-pack to the project
  3. pack the project, you now have lib folders for later
  4. Open Idea, choose "create new project", set path/scalajs-spa-tutorial as the root
  5. in the ide create a new module shared, with content root path/scalajs-spa-tutorial/shared, manually mark the source/resource/testfolders. Add the pack/lib folder to the dependencies. remove the project jar from lib
  6. repeat for js
  7. repeat for jvm
  8. Everytime your dependencies changes, run pack again in sbt, and manually clean your pack/lib folder(s) of the respective projects jars
(Conceptually, i like to think of these cross projects as single projects, with multiple source folders. So instead of step 5/6/7 i'd create only 1 module, and dump the js source, jvm source, and shared source as source folders to the manually created ide module. same with thest and resource folders)


Op zondag 15 februari 2015 15:59:48 UTC+1 schreef Egon Nijns:

Otto Chrons

unread,
Feb 15, 2015, 12:33:55 PM2/15/15
to Egon Nijns, scal...@googlegroups.com
I'm using IDEA 14.0.3 myself and import works ok. I use "auto-import" and "download docs & sources" settings in import. Sometimes it's also necessary to invalidate caches and restart IDEA after changes in SBT build files. And in a few cases I had to remove the .idea directory and re-import the project to fix some issues.

--
You received this message because you are subscribed to a topic in the Google Groups "Scala.js" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-js/41nCyvZj7Oo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-js+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/scala-js/64eaa5b6-e0ea-40cb-8e29-59f05f572692%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Egon Nijns

unread,
Feb 15, 2015, 1:40:32 PM2/15/15
to Otto Chrons, scal...@googlegroups.com
I tried your suggestions, but no luck so far. Maybe I shouldn't try to use the EAP versions...
IntelliJ doesn't seem to find classes such as Seq and when I click 'refresh SBT projects' I'm also getting an error:
Inline afbeelding 1

Otto Chrons

unread,
Feb 15, 2015, 2:51:29 PM2/15/15
to Egon Nijns, scal...@googlegroups.com
What does the sbt2.log file tell you? I recall having similar error due to some dependency downloads failing with IDEA SBT. If I recall correctly, I had dependency bundles but not separate "jars", and for some reason IDEA SBT was not able to use the bundle.

- Otto

Otto Chrons

unread,
Feb 15, 2015, 5:55:35 PM2/15/15
to scal...@googlegroups.com
Another release with a Modal dialog and other nice things.
  • Simple jQuery integration added (Bootstrap Modal)
  • Modal example with a form
  • Refactored Bootstrap components a bit
  • Todos are now updated on the server

Egon Nijns

unread,
Feb 16, 2015, 2:52:07 AM2/16/15
to scal...@googlegroups.com, egon....@gmail.com
Thanks for your help - it appears to be https://youtrack.jetbrains.com/issue/SCL-8222.

Egon Nijns

unread,
Feb 16, 2015, 2:58:25 AM2/16/15
to scal...@googlegroups.com, egon....@gmail.com
If anyone runs into the same issue: the easy workaround is changing the sbt version in build.properties:
sbt.version=0.13.5

regards,
egon.

Otto Chrons

unread,
Feb 20, 2015, 4:54:21 PM2/20/15
to scal...@googlegroups.com
A new release with a Facebook Flux -like data flow framework (with a touch of Actors on the side) and some simple testing demonstrated.
  • Unidirectional data flow framework Ukko following Facebook Flux and actor architectures
  • Todo list implemented with the new data flow model
  • Main menu item Todo now shows count of open todos
  • Testing with uTest
All comments, bug reports and improvement suggestions are most welcome! Don't be shy! :)

- Otto

Otto Chrons

unread,
Feb 21, 2015, 8:48:46 AM2/21/15
to scal...@googlegroups.com
I got annoyed by the javascripty EventEmitter, so I replaced it with ScalaRx reactive variables and released a new version :)

- Otto

Otto Chrons

unread,
Feb 26, 2015, 4:58:17 PM2/26/15
to scal...@googlegroups.com
A new version is out! This was mainly a refactoring release, adding support for WebJars and LESS. Everything is a bit cleaner now :)

Check out the RxObserver trait if you are using Scala.rx with React.

- Otto

Otto Chrons

unread,
Mar 3, 2015, 2:17:49 PM3/3/15
to scal...@googlegroups.com
And another update to the tutorial. This time not many code changes but the build process includes packaging a production version using sbt-native-packager.
https://github.com/ochrons/scalajs-spa-tutorial#production-build

Also updated to scala.js 0.6.1 and scalajs-react 0.8.1

As usual, all comments and improvement suggestions are welcome!

- Otto

Otto Chrons

unread,
Mar 4, 2015, 5:08:02 PM3/4/15
to scal...@googlegroups.com
If you are interested in debugging and logging in Scala.js applications, the latest version is for you!


- Otto

Otto Chrons

unread,
Mar 10, 2015, 3:51:08 PM3/10/15
to scal...@googlegroups.com
Minor update:

* Upgraded many libraries to their latest versions
* Changed how the MainRouter is initialized and used to make it more convenient
* "release" command moved to root project

- Otto

Ben Hutchison

unread,
Mar 24, 2015, 5:57:16 PM3/24/15
to Otto Chrons, scal...@googlegroups.com
Hi Otto,

I have to say, this is an excellent, very substantial tutorial. Thanks for creating it!

The section on logging and debugging is pretty welcome, since these topics become increasingly important as  codebases grow larger. I had been wondering how other people approach logging; right now I make do with println but the day will come when that's not enough.

-Ben

--
You received this message because you are subscribed to the Google Groups "Scala.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-js+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/scala-js/020d70c3-c7a1-43ce-bbcc-465befc46928%40googlegroups.com.

Otto Chrons

unread,
Apr 2, 2015, 3:13:39 PM4/2/15
to scal...@googlegroups.com
A new version is out!

This time a major change is the inclusion of ScalaCSS to define styles. Note that the SPA Tutorial does not present a very good use case for ScalaCSS as it is mainly wrapping Bootstrap styles.

Documentation is now easier to read as it has been converted into a GitBook (available at http://ochrons.github.io/scalajs-spa-tutorial/)

- Otto
Reply all
Reply to author
Forward
0 new messages