Onward and upward

5 June 2018

Vue.js with Playframework

by @tanin

We’ve finally extracted out our Vue.js plugin for Playframework, sbt-vuefy, and shared it with the world.

It has been quite an effort to make Vue.js work seamlessly well with Playframework. This is especially true when we want to avoid using Single-page application (SPA).

At GIVE.asia, we’ve decided to go with Server-side rendering, the traditional way, as opposed to Client-side rendering or SPA. Because our site isn’t highly interactive, and, with SPA, some website’s fundamentals (e.g. SEO, Routing) become complex and require a lot more Javascript code.

We’ve chosen Vue.js because we like Vue’s Single File Components, especially how we can encapsulate behaviour and appearance in a custom tag.

You might think “Well, other JS frameworks support componentization too”. And that’s true. While React.js seems somewhat equivalent to Vue.js, JSX isn’t aesthetically pleasing. This reddit comment explains the difference between Vue.js and React.js very well. Polymer.js 2.0, which we initially used, just wasn’t good. But more on that later in a separate blog post…

The plugin integrates Vue compilation into Playframework using sbt-web’s syncIncremental; this means every time the code is changed, the code will be re-compiled. The plugin also tracks dependencies within a component (e.g. import OurButton from './common/our-button.vue' here), and the recompilation will happen only on necessary files.

The data is sent to Javascript code by writing JSON onto the generated HTML. Here’s an example of index.scala.html using app/assets/vue/components/greeting-form.vue:

@(greeting: String)

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src='@routes.Assets.versioned("vue/components/greeting-form.js")'></script>

<script>
  function parse(s) {
    return JSON.parse(decodeURIComponent(escape(atob(s))));
  }
</script>

<div id="app"></div>
<script>
  var app = new Vue({
    el: '#app',
    render: function(html) {
      return html(GreetingForm.default, {
        props: {
          greeting: parse("@libraries.Base64.encodeString(greeting)")
        }
      });
    }
  })
</script>

There are three things to pay attention to in the code above:

A complete example is here

We have been using sbt-vuefy on GIVE.asia for some time now, and it has been working well. Check out sbt-vuefy if it might work for you, and please let us (@tanin) know if you encounter any problem or have any suggestion!