Vue.js を ASP.NET Core でプログレッシブに使う (Non-SPA編)

この記事は Vue.js #3 Advent Calendar 2018 の17日目の記事です。

昨今のフロントエンド界隈では、なんでもSPAのアーキテクチャを前提として語られる雰囲気を感じますが、Non-SPAなサーバーサイドのMVCフレームワーク(LaravelやRails、ASP.NET Coreなど)をメインに使いつつ、Vue.js などのJavaScriptライブラリを使って画面に味付けをしたいというニーズも相変わらず存在します。また、あえてそう設計すべきアプリケーションも多くあるでしょう。

ここで、 Vue.jsの公式サイト(日本語版) の冒頭に書かれている文章を紹介します。

…Vue は少しずつ適用していけるように設計されています。中核となるライブラリは view 層だけに焦点を当てています。そのため、使い始めるのも、他のライブラリや既存のプロジェクトに統合するのも、とても簡単です。…

Vue.js は プログレッシブフレームワーク です。サーバサイドのMVCフレームワークと組み合わせて使うことももちろん可能です。むしろそこから気軽に始められるところが最大のメリットのひとつと言っても良いくらいです。そこで、このエントリーでは、Vue.js を MVCフレームワークの一つである ASP.NET Core と組み合わせて使い始める方法を紹介したいと思います。

(参考) ASP.NET Core

ASP.NET Core は、OSSのWebアプリケーションフレームワークです。前身の ASP.NET とは根本から違うので、比較的新しいフレームワークといってもいいかもしれません。ASP.NET Core はクロスプラットフォームで動きます。Mac の VSCode で開発して Linux で運用するのも全く問題ありません。しかし、何故か日本では、 Windows でしか動かないとか、 Visual Studio でしか開発できないという思い込みが蔓延している傾向が強く、非常に残念です。

また、ASP.NET Core は静的型付けかつコンパイル型のC#で書くので非常に開発効率が良くパフォーマンスが良いです。最新の TechEmpower Framework Benchmarks でも6位に入っていました(Laravelは289位で、Railsは279位)。

jQuery+BootstrapからVue.js+Bulmaへ

ASP.NET Core の標準的なテンプレートのフロントエンド部分は、残念ながらいまだに jQuery + Bootstrap で構成されてしまっています。この構成では最近のモダンなフロントエンド技術のメリットを享受できません。ここはサクッと Vue.js + Bulma に置き換えていきます。

なお、MVCとして ASP.NET Core を構成する場合(Web APIのみで構成することも可能)、フロントエンドの構成がSPAではないこと、ビルドやバンドリングなども ASP.NET Core の流儀に従うべきなので、 Vue.jsの導入に npm や Vue CLI は使いません。CDNから導入します。言い換えると、npm や webpack 等についての知識や環境構築は不要です。Vue.js のみ使えるようになればOKなので、バックエンド系の開発者やデザイナーにも優しい構成と言えます。これを許容できるのも、プログレッシブフレームワークである Vue.js ならではです。

まず、 _Layout.cshtml でjQuery関連のタグを全て削除し、Vue.js をバージョン指定でCDNから読み込みます。その際、 ASP.NET Core Razor の <environment> タグヘルパーの環境切り替え機能を使い、開発用のVueと本番用のVueを切り替えるようにCDNを設定しておきます(Bulmaでも同様)。なお、本番側は integrity の設定も入れておいたほうが安全でしょう。

<environment include="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.js"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.min.js"
integrity="sha256-ui3vFTgbIIvd9ePh+wF+ju05O3jympV4FyFlpNMV2cw=" crossorigin="anonymous"></script>
</environment>

テンプレートで定義されるHTMLは、 Bootstrap ベースで書かれているので、 Bulma ベースに修正します。Bulma: an alternative to Bootstrap を参考にすると、簡単に置き換えができます。以下はナビゲーションをBulmaベースに書き換えた例です。

<header>
<nav class="navbar is-light" role="navigation" aria-label="main navigation">
<div class="container">
<div class="navbar-brand">
<a class="navbar-item" asp-area="" asp-controller="Home" asp-action="Index">
<label class="label is-large">MvcBulmaVue</label>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu">
<div class="navbar-start">
<a class="navbar-item" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
<a class="navbar-item" asp-area="" asp-controller="Products" asp-action="Index">Products</a>
</div>
</div>
</div>
</nav>
</header>

Bulmaは CSS のみを利用しているので、Vue.js はもちろんのこと、 Razor ようなテンプレートエンジンとも非常に相性が良いですね。

レンダリングを Vue.js ベースに変更する

scaffolding機能で出力されるHTMLは ASP.NET Core のレンダリングエンジンである Razor ベースで書かれているので、ここではより柔軟にビューを表現できる Vue.js でのレンダリングに書き換えてみます。

まず、出力されたビューに紐付いているModelデータを Vueインスタンス で扱えるようにしておきます。RazorのHTMLでは、Laravel の Blade と同じように、Scriptタグ内で \@Json.Serialize(Model) を使ってデータを読み込めます。axios 等を使ったデータ取得は必要ありません。

<script>
var vm = new Vue({
el: '#app',
data: {
items: @Json.Serialize(Model) // RazorのModelをVueインスタンスで扱えるようにする
}
});
</script>

自動出力されたHTMLには Razor のレンダリング用タグが埋め込まれますが、これを一気に Vue.js ベースに置き換えてしまいます。

<table class="table is-hoverable">
<thead>
<tr>
<th>ProductName</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="item in items">
<td>{{ item.productName }}</td>
<td>{{ item.price }}</td>
<td>
<a asp-action="Edit" asp-route-id="item.id">Edit</a> |
<a asp-action="Details" asp-route-id="item.id">Details</a>
</td>
</tr>
</tbody>
</table>

Razor特有のタグがなくなり、リストレンダリングでもHTMLが非常にスッキリします。この方法を使えばビューのレンダリング部分に関しては、ほとんど Vue.js の流儀で書けるようになります。画面はこんな感じになります。Bulma のおかげでいい感じにモダンな雰囲気が出ますね。

Vue.js + Bulma でのレンダリング例

ひとつ課題があるとすれば、scaffolding機能で出力されるクライアントバリデーションがjQuery依存のため、別途タグヘルパーの拡張などが必要となる点くらいですが、このあたりは @shibayan に相談すればさくっとカスタマイズができると信じています。

このように、サーバサイドMVCフレームワークを中心に使う環境であっても、十分に Vue.js の恩恵を受ける方法が存在します。ちなみに、SPAベースの Vue.js と ASP.NET Core を組み合わせたいという場合は、 Node.js Tools for Visual Studio を使用して Vue.js アプリを作成する という公式ドキュメントに従って構成すれば npm や Vue CLI を使ったいつものスタックで幸せになるという道もあります。

Vue.js はプログレッシブフレームワークです。Vue.js を使うことだけが目的にならないよう、アプリケーション毎に最適なアーキテクチャのスタイルで楽しく使っていきたいですね。