Brainsware Blog

(In other news: App development, UX design, business: we're writing about the entire development of Sealas)

Vue.js + Coffeescript + Browserify + Grunt

by daniel on

The Vue.js documentation seems very unclear when it comes to explaining how to properly execute a switch from the runtime compilation of templates (with type="x-template") to precompiled templates in .vue files.

Since I want to do Vue the proper way, I figured I'll switch to precompiled templates, which turned out to be a bigger pain that I initially thought.

Update: I posted an example repository using this stack on github: https://github.com/DKhalil/coffeescript-vue-browserify-grunt

After a lot of googling and documentation reading and screaming at the screen, I've figured out a way that accomodates this setup: the production version of vue2 without the included template compiler, building with grunt and browserify, and having my script in coffee.

Grunt + Browserify

Right, so the build setup first. You're gonna need the following packages installed:

  • grunt-browserify
  • vueify to compile .vue component files
  • coffeeify to compile .coffee files
browserify:
  client:
    options:
      browserifyOptions:
        extensions: [ '.coffee' ]
        debug: true
      transform: [ 'vueify', 'coffeeify' ]
    src: [ 'src/main.coffee' ]
    dest: 'htdocs/app.js'

extensions needs to be in browserifyOptions, as it's not in the regular options, and adds '.coffee' as a resolvable extension for module imports, so you can do require './coolcomponent' for coolcomponent.coffee

debug adds source maps, which helps with debugging.

Vue.js with template compiler

vue/dist/vue.js includes the template compiler in the build, so me trying to switch off of that, and produce a 'pure' build, was when the trouble started.

The original setup

I started out with Vue components built like that:

module.exports = Vue.component 'coolcomponent',
  template: '#cool-template'

The templates themselves were included in the HTML templates, with x-template tags:

{% verbatim %}
<script type="text/x-template" id="cool-template">
  <div><!-- ... --></div>
</script>
{% endverbatim %}

The {% verbatim %} tags are for Twig, which I use to output my templates and are necessary in this case, because the Vue.js markup is the same as twig's/mustache's.

The base was included like this:

<div id="app">
  <transition name="fade">
    <router-view></router-view>
  </transition>
</div>

And mounted in main.coffee:

app = new Vue(
  ).$mount('#app')

Switching to the production build of Vue.js

[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available.
Either pre-compile the templates into render functions, or use the compiler-included build.

That's the nice error message I got at the beginning there. One of the things not mentioned in the docs is this: if you want to use the pre-compiled templates from vueify, you have to pass them to a render function:

app = new Vue(
  el: '#app'

  render: (h) -> h require('./app.vue')
)

with app.vue now including

<template>
  <transition name="fade">
    <router-view></router-view>
  </transition>
</template>

<script>module.exports = {}</script>

This is now a fully functional vue component, which doesn't spit out the nice error. module.exports needs to be there so the component is built correctly, even if it's empty.

Coffee components

The last step now is the rest of the components. I put the template in coolcomponent.vue:

<template>
<!-- ... -->
</template>

<script src="./coolcomponent.coffee" lang="coffee"></script>

The lang="coffee" part is important, so coffeeify gets included in the compilation process here. Now you can include the component with require 'coolcomponent.vue' which now looks like this:

module.exports = Vue.component 'coolcomponent',
  # no more template: '...' here
  ...

I sent a pull request to the vue.js documentation to clear that up. Apart from that, I hope this will help some people who have similar issues with Vue.

Share this Post: