vue-templatify という Browserify プラグインを作った

2016/2/1 追記: 単一ファイルコンポーネントでも、JSとテンプレートを分けて書くこと自体はできるので(refs: https://jp.vuejs.org/v2/guide/single-file-components.html#関心の分離について)、このプラグインは基本的に不要かもしれません。


作った。

github.com

Vue.js を使っていて、vueify や vue-loader で .vue を書くのは大げさだけど、コンポーネントを作って、JSとテンプレートを分けて管理したい、ということがあります。コードだと以下のようなイメージです。

<!-- app.html -->
<div class="app">
  <p>{{ text }}</p>
  <button type="button" @click="log">Log</button>
</div>
// app.js
import template from './app.html'

export default {
  template
  data () {
    return {
      text: 'Example text'
    }
  },
  methods: {
    log () {
      console.log('output log')
    }
  }
}

Vue.js 1.x までは、Browserify を使っている場合 partialify や stringify 等のプラグインでこれが実現できていましたが、Vue.js 2.x ではこのままでは動きません。

動かない理由、2.xのビルドプロセスと2種類のビルド

以下の2つが動かない理由です。

つまり、単純にvar Vue = require('vue')import Vue from 'vue'で Vue.js をインポートして、template オプションにテンプレート文字列を渡した場合は、テンプレートのコンパイルが実行されないまま、ブラウザで動作させることになり、エラーになってしまいます。 vueify や vue-loader を利用している場合は、バンドルの過程で、テンプレートを render関数 にコンパイルしているため、問題ありません。 ( Vue.js 2.x のレンダリングプロセスについては、kazuponさんのスライドが分かりやすいのでおすすめです。Vue.js 2.0 Server Side Rendering // Speaker Deck )

この問題を解決するには、2つ方法があります。

前者は公式のドキュメントで方法が紹介されています( https://jp.vuejs.org/v2/guide/installation.html#スタンドアロン-vs-ランタイム限定ビルド )。後者は、あくまでランタイム限定ビルドを使う道です。微々たるものかもしれませんが、コンパイルロジックが無い分ファイルサイズが小さいのでロード時間と、render関数 へのコンパイル時間が削減できます。

(前置きが長いね…)

vue-templatify

Webpackではテンプレートを render関数 にコンパイルするプラグインvue-template-loaderを @ktsn さんが作られていましたが、Browserify にはなかったので今回開発しました。ホットモジュールリプレースメントにも対応しているので、テンプレートを編集したら、ページのリロード無しで自動的に内容が更新されます。

GitHub - kitak/vue-templatify: Browserify transform for Vue.js 2.0 template

プラグインを利用した場合、JSのコードは以下のように変更する必要があります。テンプレートは、「コンポーネントのオプションを受け取って、render関数 をマージした新しいオプションを返す関数」に変換されます。

// app.js
import withRender from './app.html'

export default withRender({
  data () {
    return {
      text: 'Example text'
    }
  },
  methods: {
    log () {
      console.log('output log')
    }
  }
})