Matt RaibleMatt Raible is a Web Developer and Java Champion. Connect with him on LinkedIn.

The Angular Mini-Book The Angular Mini-Book is a guide to getting started with Angular. You'll learn how to develop a bare-bones application, test it, and deploy it. Then you'll move on to adding Bootstrap, Angular Material, continuous integration, and authentication.

Spring Boot is a popular framework for building REST APIs. You'll learn how to integrate Angular with Spring Boot and use security best practices like HTTPS and a content security policy.

For book updates, follow @angular_book on Twitter.

The JHipster Mini-Book The JHipster Mini-Book is a guide to getting started with hip technologies today: Angular, Bootstrap, and Spring Boot. All of these frameworks are wrapped up in an easy-to-use project called JHipster.

This book shows you how to build an app with JHipster, and guides you through the plethora of tools, techniques and options you can use. Furthermore, it explains the UI and API building blocks so you understand the underpinnings of your great application.

For book updates, follow @jhipster-book on Twitter.

10+ YEARS


Over 10 years ago, I wrote my first blog post. Since then, I've authored books, had kids, traveled the world, found Trish and blogged about it all.

Integrating Scalate and Jade with Play 1.2.3

At the beginning of this year, I decided I wanted to learn Scala. Since I'm a Web Frameworks Aficionado, I figured the best way to do that would be to learn Lift. I entered these two items on my todo list and let them lie for a couple months. After attending TSSJS 2011 and having a conversation with James Strachan, I added a couple more technologies to my learning list. James had great things to say about both CoffeeScript and Jade and I decided to learn those as well.

In May, Devoxx announced their Call For Papers and I started reminiscing about how awesome last year's trip was. I decided I'd try to get accepted again and started brainstorming about talks I'd like to give. I came up with "Comparing Scala Web Frameworks" and "HTML5 with Play Scala, CoffeeScript and Jade". The reason I chose Play over Lift for the latter talk is because I think it fits a lot more with the MVC mindset I have and the easy-to-learn nature of web frameworks I enjoy using. Both topics sounded very interesting to me, and I figured they'd also inspire me to learn the technologies in a brute-force fashion; where I was under a time constraint and would be embarrassed in front of a large audience if I didn't succeed.

In mid-July, I got an email from Stephan inviting me to speak again at the 10th edition of Devoxx. I smile splashed across my face and I quickly realized I had a lot to learn. Since I was still in vacation mode after summer vacation in Montana, I decided to wait until I returned from Cape Cod to start studying. While on my 2nd summer vacation, I received an email from Devoxx stating that they'd like me present "HTML5 with Play/Scala, CoffeeScript and Jade".

To learn all these technologies, I decided on an In Anger approach - where I would study minimally and learn mostly by doing. I ordered CoffeeScript on August 8th and Programming in Scala, 2nd Edition the following week (August 17th). I started reading both books while traveling the following week (I found CoffeeScript and Scala to be very similar, so I don't know if I'd recommend learning them at the same time). That same week, I started integrating Scalate (Jade) into a new Play Scala application.

Scalate advertises on their homepage that it works with Play via the play-scalate module. They neglect to mention that this module hasn't been updated in over a year or what version of Play it works with. I tried to use the scalate-0.7.2 version and quickly ran into issues. I posted a message to the Scalate Google Group explaining my compilation issues and stacktraces. The response? Crickets.

Next, I tried posting to the Play Google Group and got a much better response. Here's what they said:

Looking at the Scalate module code, I don't think it can work as is with Play Scala 0.9.1. The latest version is more than 1 year old, and we have made a lot of changes in the API.
...
The integration of Scalate is pretty difficult if you plan to get the same kind of experience than the native Play scala template regarding auto-reload and error reports.

You can try to port the module to 0.9.1, basically all it has to do is to provide a plugin that detect changes to scaml file, and recompile them. No special integration with the Play API is needed.

After learning that play-scalate was out-of-date, I contacted the project owner via GitHub and tried to get everything working with Play 1.2.3 and Scalate 1.5.1. I updated the dependencies in the project, fixed compilation issues and tried to build. No dice:

build: 
    [mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] Compiling 7 source files to /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] error: class file needed by Binding is missing. 
   [scalac] reference type Serializable of package scala refers to nonexisting symbol. 
   [scalac] one error found

I posted this error to the Play Group, discovered it was caused by Scalate 1.5.1 requiring Scala 2.9. I downgraded to Scalate 2.4.1 and got another nice cryptic error:

build: 
    [mkdir] Created dir: /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] Compiling 7 source files to /Users/mraible/dev/play-scalate/tmp/classes 
   [scalac] error: class file needed by ScalaController is missing. 
   [scalac] reference value dispatch of package <root> refers to nonexisting symbol. 
   [scalac] one error found

Apparently, this was caused by another Scala versioning issue and I was offered a much simpler solution for integrating Scalate. Below are the steps I performed to integrate Scalate 1.4.1 with Play 1.2.3.

  1. Updated dependencies.yml to references Scala and Scalate dependencies.
    require:
        - play
        - play -> scala 0.9.1
        - org.fusesource.scalate -> scalate-core 1.4.1:
            transitive: false
        - org.fusesource.scalate -> scalate-util 1.4.1:
            transitive: false
    
  2. Added Scalate configuration elements to application.conf.
    scalate=jade
    jvm.memory=-Xmx256M
    
  3. Created a ScalateTemplate class to contain the Scalate Engine and render the template.
    package controllers
    
    import play.Play
    
    object ScalateTemplate {
    
      import org.fusesource.scalate._
      import org.fusesource.scalate.util._
    
      lazy val scalateEngine = {
        val engine = new TemplateEngine
        engine.resourceLoader = new FileResourceLoader(Some(Play.getFile("/app/views")))
        engine.classpath = Play.getFile("/tmp/classes").getAbsolutePath
        engine.workingDirectory = Play.getFile("tmp")
        engine.combinedClassPath = true
        engine.classLoader = Play.classloader
        engine
      }
    
      case class Template(name: String) {
        val scalateType = "." + Play.configuration.get("scalate");
    
        def render(args: (Symbol, Any)*) = {
          scalateEngine.layout(name + scalateType, args.map {
            case (k, v) => k.name -> v
          } toMap)
        }
      }
    
      def apply(template: String) = Template(template)
    }
    
  4. Created a Scalate trait to override the render() method in Play's Controller class.
    package controllers
    
    import play.mvc.Http
    
    trait Scalate {
    
      def render(args: (Symbol, Any)*) = {
        def defaultTemplate = Http.Request.current().action.replace(".", "/")
        ScalateTemplate(defaultTemplate).render(args: _*);
      }
    }
    
  5. Created an Application.scala controller with a default index method.
    package controllers
    
    import play.mvc._
    import models._
    
    object Application extends Controller with Scalate {
    
      def index = {
        render('user -> User("Raible"))
      }
    }
    
    The models/User.scala class is very simple:
    package models
    
    case class User(name:String)
    
  6. Lastly, I created an index.jade file in views/Application.
    -@ var user: models.User
    p Hi #{user.name},
    - for(i <- 1 to 3)
      p= i
    p See, I can count!
    

After getting all this working, I decided it was time to get it into production. As luck would have it, Heroku had just announced Play support a few days earlier. I heard through the grapevine that Play Scala would work, so I gave it a try. It was amazingly easy. All I had to do was create an account, create a "Procfile" in my application's root directory and run a heroku command followed by a git push. It all looked great until Play tried to compile my Jade templates as Groovy templates:

Cannot start in PROD mode with errors 
Template compilation error (In /app/views/Application/index.jade around line 2) 
The template /app/views/Application/index.jade does not compile : #{user.name} is not closed. 
play.exceptions.TemplateCompilationException: #{user.name} is not closed. 
       at play.templates.TemplateCompiler.generate(TemplateCompiler.java:102) 
       at play.templates.TemplateCompiler.compile(TemplateCompiler.java:15) 
       at play.templates.GroovyTemplateCompiler.compile(GroovyTemplateCompiler.java:4 1)

The solution from Guillaume was simple enough and I renamed my "views" directory to "templates" and updated ScalateTemplate.scala accordingly. You can see the deployed application at http://play-more.herokuapp.com.

The next steps in my Play Scala adventure will be trying to get the CoffeeScript module to work. I also hope to integrate HTML5 Boilerplate with Jade and Scalate Layouts. I'll be doing this with the mindset that HTML and JavaScript aren't that bad. I expect a lot from CoffeeScript and Jade and hope I enjoy them as much as Strachan. ;-)

In the meantime, here's some interesting links I've seen recently encountered that discuss Scala and/or Play. I dig the passion and activity that exists in these communities.

Posted in Java at Sep 07 2011, 01:21:41 PM MDT 10 Comments