vue/dist/vue.esm.js を使いたくない
Vueの入門者が最初に躓きがちな問題として、「自分の環境でVue公式のサンプル通りにコンポーネントを書いてみても動かない!」ということがあると思う。
大抵はVueのimportの書き方が問題になる。この解決策として、「import Vue from 'vue'
ではなくimport Vue from 'vue/dist/vue.esm.js'
を使いましょう」という方法が紹介されていることが多いと思う。
これは、import Vue from 'vue'
と書いたときに読み込まれる「ランタイム限定ビルド(vue.runtime.esm.js)」ではなく、「完全ビルド(vue.esm.js)」を使うようにする書き方なのだけど、なるべくランタイム限定ビルドを使ったほうが良いですよーというのが公式のおすすめ。
ランタイム限定ビルドは完全ビルドに比べおよそ 30% 軽量なため、利用できるときにはこれを利用したほうが良いでしょう。
結構な差で軽量。そんなにランタイム限定ビルドのほうが軽量と言われたらそっちを使いたくなる。
なぜvue/dist/vue.esm.jsが必要なのか。
Vueでel
オプションを使ったときや、template
オプションに直接HTMLのテンプレートを渡す場合は実行時にコンパイラが必要になるので、完全ビルドを使わざるを得なくなってしまう。
なので、ランタイム限定ビルドを使用するためには、コンパイラが必要ないコードにする必要がある。
このあたりに関しては、この記事がめっちゃ詳しい。
Vue2.x系のハマりどころ templateとコンパイラを完全解説するよ
vue/dist/vue.esm.jsを使わない方法
templateオプションでcreateElementを使って頑張ったりJSXを渡ったりしたりvue-template-loaderを使ったりすればよいかもしれないが、別のパッケージを入れたり面倒。なるべく今までと同じように書きたい。
単一コンポーネント(.vue)に書いたテンプレートに関しては、ビルド時にコンパイルされるため、実行時に完全ビルドは必要なくなる。なので、elオプションもtemplateオプションも使わずに、全部コンポーネントに書いてしまう方法がある。
もちろん、単一コンポーネントをビルドできるようにしておく必要はある。
例えば、数字をクリックするとカウントアップするVueアプリのコードがこれ。
<div id="app"><span @click="increment">{{count}}</span></div>
import Vue from 'vue/dist/vue.esm.js'
document.addEventListener('DOMContentLoaded', () => {
new Vue({
el: '#app',
data: {
count: 0
},
methods: {
increment () {
this.count++
}
}
})
})
このコードでは、html側にテンプレートが書かれているので、実行時コンパイルのために完全ビルドが必要になる。
このhtmlのテンプレートを単一コンポーネント側に持っていき、script部分はコンポーネントそのままではなくVue.extend
を使用してVueのサブクラスコンストラクタを作成する。これならhtmlテンプレートが単一コンポーネント内に収まるため、ビルド時にコンパイルされ実行時コンパイルは不要になる。
次のようにする。
<div id="app"></div>
import App from '../app.vue'
document.addEventListener('DOMContentLoaded', () => {
const app = new App
app.$mount('#app')
})
<template>
<span @click='increment'>{{count}}</span>
</template>
<script>
import Vue from 'vue'
export default Vue.extend({
data: () => {
return {
count: 0
}
},
methods: {
increment () {
this.count++
}
}
})
</script>
重要なのは、$mount
を使ってちゃんとマウントしてあげること。
elオプションを使わない場合は、自分で任意のタイミングで$mount
する必要がある。
これで完全ビルドを使う必要がなくなり、めでたしめでたし。