Vue.js始めるおれおれアドベントカレンダー2016 – 7日目
色々やろうとしたらやっぱりファイルの管理とかが手間なので、ぼちぼちツールを導入します。
なにそれ
Browserify transform for Vue.js components, with scoped CSS and component hot-reloading.
(Broserifyを使って)Vueのコンパイル的なアレをしてくれるツールです。対象のファイルはJSではなく、HTMLテンプレートとJSの両方を含む *.vue
という拡張子のファイルだそうだ。
hot-reloading は自分の環境だと特にそれっぽい動きはしてくれてない。ウェブブラウザが別マシンだから?
ところでこういうのをコンパイルと呼んで良いんだろうか。
試行錯誤の記録
色々エラー出たりしたので置いておきます。
まず今まで使ってたひとつしかないJSファイルを単純にvueifyに突っ込んだら、ちゃんと動いてくれた。変換なしで通してくれたみたい。
続いてVueとVuexを require()
で読み込むようにしたら、エラー。
Error: [vuex] must call Vue.use(Vuex) before creating a store instance.
あ、まあそうですね。さくっと Vue.use(Vuex)
を追加。
で次。
[Vue warn]: Failed to mount component: template or render function not defined.
(found in root instance)
んーコンポーネントの template
をHTMLに書いてちゃ駄目か。そりゃそうだ。
でJS側に持ってきても駄目だった。あれ? あーそうか本体(コンポーネントにしてない部分)もこっちに持ってこないとか。どうやら main.app
から全体を司る App
を render()
で出力するのが定石らしい。(合ってる?)
でやったら、何故か画面が空っぽになる、何も出てこない……。と思ったら return
してなかった。ああーそっか!
よしまあじゃあ一度全部消して、READMEの例の通りにやってみよう。
Error: Parsing file /path/to/you/work/dir/App.vue: 'import' and 'export' may only appear at the top level (23:0)
えー。
export default {}
を module.exports = {}
にしたら解決。よくわかってない。
ともかくこれで動いた!
ただ、最終的な出力ファイルの位置でエラーが出てくるのでわかりづらい。browserifyの方のオプションで --debug
を与えるとソースマップを付けてくれるんだけど、うーんわかりづらい。
まとめ
環境
こんな感じになりました。
{ "scripts": { "start": "npm run vue-watch", "vue-build": "browserify -t vueify -e src/main.js -o out/app.js ", "vue-watch": "chokidar src/* -c 'npm run vue-build'" }, "dependencies": { "browserify": "^13.1.1", "chokidar-cli": "^1.2.0", "vue": "^2.1.4", "vueify": "^9.3.0", "vuex": "^2.0.0" }, }
src/
に元のファイルを、out/
に出力ファイルを置くものとします。npm run vue-build
でビルドします。npm run vue-watch
でファイル監視してビルドします。chokidar
はファイル監視してコマンド実行するやつです。べんり!
Hello World!
- src/main.js
const Vue = require('vue'); const Vuex = require('vuex'); // 今回使ってないけど Vue.use(Vuex); const App = require('./App.vue'); new Vue({ el: '#app', render: function(createElement) { return createElement(App); }, });
- src/App.vue
<style> h1 { font-style: italic; } </style> <template> <div class="container"> <h1>{{message}}</h1> </div> </template> <script> module.exports = { data: function() { return { message: 'Hello World!', }, }, }; </script>
はあー、なるほどこんな感じですか!
コンポーネント
別のファイルにして require()
する感じ。無理やり感あるけど分割して、ついでにVuexも突っ込みます。
- App.js
<template> <div class="container"> <my-title></my-title> </div> </template> <script> var MyTitle = require('./MyTitle.vue'); module.exports = { components: { MyTitle: MyTitle, }, }; </script>
- MyTitle.js
<template> <h1>{{title}}</h1> </template> <script> var store = require('./store.js'); module.exports = { data: function() { return store.state; }, }; </script>
- store.js
const Vuex = require('vuex'); module.exports = new Vuex.Store({ state: { title: 'Hello World!', }, });
見た目はさっきと一緒。
よくわからないこと
store.state
を直接 data
に指定しない?
data: store.state
と書いたらこんなん言われた。
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
毎回 function()
書いて return
しないといけない?
export default
を使うには?
これも未来JavaScriptの機能だよね。 import
するやつ。例の通りに書いたのに駄目だった。コンパイル時にエラーになる。どうしたら良かったんだろうか。バベる? いつ?
hot-reloading
使えたら便利そうだけど。
lint
そろそろVue的な書き方に合わせたい。セミコロン欲しい派だけど、しばらく書いてれば慣れるだろう……。
おしまい
ビルドなしで強力なのが導入できて便利~というのがVueの最初の印象だったんだけど、結局ビルドするようになりました。まあ「ちゃんと」やろうとしたらそうなるよね。例えjQueryでも。とはいえ簡単だし、jQueryでちゃんと整えるよりやっぱり簡単じゃないだろうか。