せらぴんブログ

サークル「せらぴん」のうのはな透です。やっぱり眼鏡っ娘が好き!!

Vueいじってみた

せらぴん

jp.vuejs.org

今更ながら「Vue.jsを使いたい」という欲求を満たすため、自分のサイトをゴリゴリ改造しました。
従来mithril.js(in livescript)だったものを、Vue.js+Vue-router(in javascript)に変更してます。
以下、備忘録。

開発の流れ/詰まった点

Vue-router

最初はメインのページをindex.htmlにゴリゴリ書いていったんだが、
うちのサイトはメインページの他に本用のページがある。
この2種類のページを使い分けるために、メインページが一段落ついてからVue-routerを用いてSPA化に着手した。

Introduction · vue-router

Vue-routerはrouter-viewタグ以下にページ個別の内容を記述する。
その”ページ個別の内容”は、通常コンポーネントとして提供する。
つまり、現状からSPA化するためには、下記のようなフローを辿ることになる。

  • index.htmlは、router-viewを書くだけの質素なページにする
  • (今までindex.htmlに書いていた)メインページの部分をコンポーネント化する
  • 本用のページを新たにコンポーネントとして作成する

単一ファイルコンポーネント

コンポーネント — Vue.js
Vueのコンポーネントは気の遠くなるくらい多機能だけど、ここではごく基本的な機能のみを利用する。
問題は、コンポーネント化するためにはtemplateにJSの文字列リテラルとして持たせないといけない点。
できれば、リテラルでなく純粋なhtmlとして記述したい。
その欲求を解決してくれるのが単一ファイルコンポーネントである。
これは、例えばhome.vueというファイルを作って、そこのtemplateタグ内にコンポーネント化したいhtmlを記述するというものである。
単一ファイルコンポーネントであれば、ほぼ純粋なhtmlとしてページを記述できる。

単一ファイルコンポーネント — Vue.js
vue.jsのcomponentをwebpackで.vueにして単一ファイルコンポーネントにする - Qiita

ここでの注意点は2つ。
templateタグ直下の要素は必ず1個のみにするという点*1と、
単一ファイルコンポーネントを使うためには、.vueファイルのコンパイルが必要であるという点だ。

Webpack

vueファイルはそのままでは使えない。コンパイルしてJS(VDOM)化しないといけない。
モジュールバンドラが必要になる。
私はモジュールバンドラといえばbrowserifyしか知らなかったのだが、
Webで調べたところ、WebpackというものがVueとよく併用されているようなので、そちらを利用してみることにした。

webpack
webpack 入門 (v3系 対応) - Qiita

vueファイルのコンパイルには、通常の設定に加えて、vue-loaderを使うよう設定する必要がある。
vue-loaderはnpmでインストールする。

Vue.jsを使った大規模開発に必要なもの - Qiita
Introduction · vue-loader

また、vue-template-complierもあわせてインストールする必要がある。

vue-template-compiler

このあたりは、vue-cliをインストールしている場合は一緒にインストールされている……と思う*2

ページが切り替わらない(1)

本用のページは一つ前のページと一つ後ろのページにそれぞれ遷移できる。
最初、ページを切り替えようとすると白いページに遷移してしまうことがあった。

理由は単純で、aタグを使っていたから。
Vue-routerでの遷移はrouter-linkタグを使う必要がある。
遷移先もhrefでなくtoで指定する必要があるため注意。

以下蛇足

ちなみにaタグで単純に遷移できない理由は、SPAではルートが"/"でなく"/#/"や"/?/"などになり、ルートの変換が必要になるためである。
aタグで"/"を直接変更してしまったら、シングルページでなくなってしまうのでSPAでなくなってしまう。よくよく考えてみると自明の理であった。

ページが切り替わらない(2)

上記問題が解決したあとも、ページを切り替えようとするとURLは変更されるのにページの内容は変更されないことがあった。
これについては、下記ページが詳しい。

[vue-router] パラメーター違いのページリンクをクリックしても更新されない時は ? - atuweb : つながりを作るWebプログラマ

以下蛇足

公式のページにも「$routeをwatchしろ」と書いてはいるのだが、
watchで何をすればいいかはいまいちピンときてなかった。
上記ページのようにwatchメソッド内でto.params.idを引数としてdataの各変数を更新してしまうのが直感的でわかりやすい。
その場合、更新用メソッドが必要になる。初期読み込み時に更新用メソッドを読み込むためには、createdプロパティを利用する。

gulpとwebpack

今までgulpを使っていたので、引き続きメインのタスクランナーにはgulpを利用しwebpackはモジュールバンドラに徹してもらうことにする。
gulpとwebpackの連携については、下記ページが詳しい。

Gulpで始めるwebpack 3入門 - Qiita

以下蛇足

webpackを導入した際、webpackの実行でエラーが発生していた。
"=>"*3を認識していなかったようなので、決断的npmバージョンアップを実行。
(io.js 2.0.2→v8.9.4にバージョンアップ。かなり浦島太郎状態である……)
ところがバージョンアップ後、gulpの途中でよく止まるようになってしまった。

Installing node.js get error - after npm install - cannot find module internal/util/types (Windows 10 64bit) · Issue #19032 · npm/npm · GitHub

issueのページを見てもピンとこなかったので、古いnodeモジュールをすべて削除。
gulpfileを頼りに、必要最低限のモジュールを入れ直す羽目になった……。

デプロイ

とりあえず諸々整理して、npm startを実行すれば静的サーバが立ち上がるように設定し終わったので、ここでherokuにデプロイ。
しかしデプロイ後、アプリケーションエラーが発生するようになってしまった。

原因は、npm startで利用している一部のモジュールをdevDependenciesとしてインストールしていたため。
静的ファイルはすべてnpm startで生成していたため、heroku上でも同じモジュールが使えないといけないのだが、どうやらherokuではdepencenciesはインストールしてもdevDependenciesはインストールしてくれないようだ。
お行儀がいいとはいえないが、すべてdepencenciesに突っ込むことで解決した。

Vueの感想

  • VDOMをhtmlとして書けるのが嬉しい。それでいてコンパイルするから最終的にはVDOMとして動作しているのが面白い
  • 最初の動機は「vue.js+vue-loader.jsだけ使えばnpm非依存で作れるのでは……?」だったが、終わってみればnpmからは逃れられそうになかった
  • vueファイル内ではpugやstylusも使えるようなので、そっちも使ってみたい
  • 「『htmlとして書けるのが嬉しい』のにpug使うの?」って言われるかもしれないけど、JSのリテラルでない点が重要なのでhtml or pugはそこまで重要ではない。むしろvueファイルごとに使い分けられるので、そういう楽しみもある(と思う)
  • テンプレートは奥が深そう(親子関係とか)なので、もう少し勉強が必要そう
  • アニメーションさせたい
  • 既存のruby製サイト(Sinatraなど)に組み込めれば強そうなので、研究したい

以上。

*1:ただしv-if/v-elseを用いて”結果的に要素1個のみになる状況”にしても、許容される

*2:私はvue.jsをダウンロードして利用していたので、vue-cliはインストールしていない

*3:アロー関数( https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/arrow_functions