Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Vue.jsとBlazorでWebアプリを作ってみた比較

僕は1か月ちょっとの間Vue.jsとBlazor(Wasm)双方でMHWIルーレットを作っていました。
(モンスターハンターワールド:アイスボーン用に装備とかクエストを自動で決めるツール)

Vue.jsとBlazorの書き心地って似てるよねってことでそれぞれ作ってみてその比較を書き留めます。

実装

Vue.js
Blazor
ソースコード

環境

Vue.js

  • @vue/cli 4.1.2
    • Babel
    • TypeScript
    • Router
    • Vuex

Blazor

  • Blazor WebAssembly 3.2.0 preview1

メリット・デメリット

◎>〇>△>× の順で良い。

Vue.js

評価 内容
ロードが高速。
ビルドファイルの容量が小さめ(MHWIルーレットVE 1.43MB)(しかし、ネイティブよりは容量が大分多い)
style scopedの利用可。
TypeScriptを簡単に導入できる(vue-cliにて選択するだけ)。
vue-property-decoratorも個人的に結構好き。
Vue Routerの設定が少し煩雑。
各種ファイル読み込みでimport文が多くなりがち。
状態管理ライブラリ(Vuex)が公式で提供されている。
画面上の要素は適切に更新されるので気を使う必要がない。
html上の改行や空白が削除される。

Blazor

評価 内容
× ロードが遅い。
× ビルドファイルの容量が大きい(MHWIルーレットBR 4.91MB)
× フレームワークとしてコンポーネントへのCSSのインポート方法が(おそらく)用意されていない。
html5の仕様としてbodyの中に埋め込むことを許可されたりされなかったりしているみたいだけど、おおよそのブラウザがbody内styleを認識できるので妥協した。お行儀良くないし、推奨もされないだろう。
(大体)C#のみで処理を書くことができる。
× DOM APIの操作にはJavaScriptに頼らなくてはならない。
また、JSRuntime.InvokeAsyncで扱えるのが関数/メソッドのみなので、プロパティやフィールドへのアクセスができない。推奨されないが必要とあればevalとかしてお茶を濁す。一応綺麗にjsにアクセスする方法もある。個別にjsファイル用意してindex.htmlに埋め込むのも面倒だと思う。
ルーターの設定が対象ページの冒頭に1行追記するだけで良いので簡単。
プロジェクト丸ごとインポートしてくれるので名前空間を分けない限りは呼び出し時の定義が不要。
状態管理ライブラリが用意されていない。ただし、ライブラリの追加なしで似たような書き方は可能。
画面上の要素を変更した時、StateHasChangedを呼び出して手動で画面を更新する必要がある。
html上の改行や空白が削除されない。

機能的には全体的にVue.jsが勝っているなぁという印象でした。

ディレクトリ構成

それぞれ初期化した時に作られるディレクトリ構成について。

Vue.js

├─public
└─src
    ├─assets
    ├─components
    ├─router
    ├─store
    └─views

Blazor

├─Pages
├─Shared
└─wwwroot

ディレクトリの役割

項目 Vue.js Blazor
静的ファイル(index.html,CSS) /public /wwwroot
動的に読み込む静的ファイル /src/assets /wwwroot
ページファイル /src/views /Pages
コンポーネントファイル /src/components /Shares
Vuex等状態管理 /src/store 任意
ルーターの設定 /src/router なし

今回のMHWIルーレットでは一部ディレクトリ構成を下記のように追加しています。

項目 Vue.js Blazor
動的に読み込む静的ファイル /wwwroot/Assets
Vuex等状態管理 /Store
その他汎用スクリプト(.ts/.cs) /src/lib /Lib

設定ファイル

Vue

│  babel.config.js
│  package.json
│  tsconfig.json
│  vue.config.js
│  
└─src
    │  main.ts
    │  shims-tsx.d.ts
    │  shims-vue.d.ts
    │  
    └─router
            index.ts

/babel.config.js

Babelの設定ファイル。

/package.json

プロジェクトの設定ファイル。

/tsconfig.json

TypeScriptの設定ファイル。

/vue.config.js

ドメイン直下以外のパスに配置するとき以外は必要なファイルです。
記入したパス向けにビルドを行います。

/src/main.ts

エントリーポイント。
App.vueとVue Routerを起動している様子。
テンプレート作成時にルーターを設定していれば改めて触る必要はないです。

/src/shims-tsx.d.ts, /src/shims-vue.d.ts

多分TypeScriptの型を定義しているファイル。

/router/index.ts

ルーターで切り替えるページ数が増えるたびに追記する必要があります。
ページに割り当てたいコンポーネントをパスとともに記述します。

Blazor

│  base.patch
│  mh-lret.csproj
│  Program.cs
│  _Imports.razor

/base.patch

ドメイン直下以外のパスに配置するとき以外は/wwwroot/index.htmlのbase要素のパスを変更する必要があります。
それを自動化するために作ったpatchファイルです。

/mh-lret.csproj

プロジェクトの設定ファイルです。

/Program.cs

エントリーポイント。
App.razorを起動しているみたいです。
サービスを追加する場合はここに追記します。

今回は状態管理用のクラスを追加するため追記しています。

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped<AppState>(); //<-追加

await builder.Build().RunAsync();

参考1 参考2

/_Imports.razor

razorファイルで常に参照できる名前空間を追記します。

index.html

アプリを反映するための基本htmlファイルです。
アプリ起動に失敗した場合の処理はデフォルトで大体ここに書かれています。
head要素はここにしか書けないので結構重要そう。
Blazor的にはC#から呼び出せるjsファイルを配置できる唯一のファイルです。
Blazorはロードが凄く長いのでスプラッシュ画面を用意したりしました。

Vue.js

/public/index.html
<!DOCTYPE html>
<html lang=ja>

<head>
    <title>MHWIルーレットVE</title>
</head>

<body>
    <noscript>
    <strong>We're sorry but ve doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
</html>

Blazor

/wwwroot/index.html
<!DOCTYPE html>
<html lang=ja>

<head>
    <base href="/" />
    <title>MHWIルーレットBR</title>
</head>

<body>
    <app>Loading...</app>
    <div id="blazor-error-ui" style=display:none>
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>

</html>

App Component/ルーター

基準となるコンポーネントファイルとルーターについて。

Vue.js

最初に呼び出されるコンポーネントファイルはApp.vueとなります。
ルーターを使用する場合はルーター用のリンク(router-link)とページコンポーネントが表示される場所(router-view)を記載します。
ルーターのパス構成は/src/router/index.tsから行う必要があります。

App.vue
<template>
<main v-cloak>
    <router-view/>
    <div id=nav>
        <router-link to="/readme/">ルーレットについて</router-link>
        <router-link to="/">MHWI</router-link>
        <a href="/lret/mhwi-br/">(BR)</a>
    </div>
</main>
</template>

Blazor

最初に呼び出されるコンポーネントファイルはApp.razorとなります。
デフォルトではルーターの設定だけが書かれており、レイアウトに関する情報は全てMainLayout.razorに書かれています。
ルーターを使用する場合はルーター用のリンク(NavLink)とページコンポーネントが表示される場所(@Body)を記載します。

MainLayout.razor
@inherits LayoutComponentBase

<main>
    @Body
    <div id=nav>
        <NavLink href="./readme/" Match="NavLinkMatch.All">ルーレットについて</NavLink>
        <NavLink href="./" Match="NavLinkMatch.All">MHWI</NavLink>
        <a href="/lret/mhwi-ve/">(VE)</a>
    </div>
</main>

文法の比較

記事を分離しました。
つづきはこちらへ。

yosgspec
JavaScript(Node.js,TypeScript),VB.NET,C#,CommonLisp,HSP,Python3,D,C++,VBA 等。 適当な言語マニアです。最近オブジェクト指向を覚えてから下手に多用することが多くなった。 その他に若干読み書きできる言語: Ruby,Lua,Java,Tcl,Scala,Scheme,Clojure,Go,Perl,Matlab,R 他
http://yosgspec.blog103.fc2.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away