🌐

Vite + Vue3 + TypeScriptの開発体験

2022/01/23に公開

プロジェクトでVue3のアプリケーションを作るかも、、となったので、Vite + Vue3 + TypeScriptで小ネタアプリケーションを書き、フィーリングを掴むことにしました。

https://bagle.vercel.app/

https://twitter.com/hctaw_srp/status/1485032776776953856

Vite

「ゔぃーと」と読むらしいです。20年リリースのフロントエンドのビルドツール。Vueの父が作りましたが、Vueに止まらず、ReactやPreact、Vanilla JS、lit、Svelteのプロジェクトもサポートしたツールです。

ドキュメント曰く

https://ja.vitejs.dev/guide/#概要

  • Rollup.jsをベースにしたビルドコマンドを提供。
  • ES modules等、モダンブラウザのパワーを活かして、Devサーバーがサクサクと動く。
  • Vueに止まらず、React・Preact・Vanilla JS・lit・Svelteプロジェクトのテンプレート提供。

あたりが持ち味。

Vue3

こちらも20年リリース。私はVue2ととても仲良しだった訳では無い(React・Next.jsで書きがち)のですが、イメージとしては、書きっぷりがスッキリ、かつラフになってきて、かつTypeScriptもサポートと、グッと開発体験を上げてきた、ぐらいなイメージでアプリケーション作りに突入。

https://v3.ja.vuejs.org/guide/migration/introduction.html#注目すべき新機能

TypeScript

AltJS。型やインターフェース、ジェネリック等が効くJavaScript。ここはReactでアプリケーションを書く時からの付き合いなので、今回のキャッチアップの中にはあんまり入らずでした。

とりあえず書くことにした

Viteでプロジェクトテンプレートを作成

ドキュメントに沿って、スタートします。

https://ja.vitejs.dev/guide/#最初の-vite-プロジェクトを生成する

$ npm init vite@latest

ここからは、表示されるガイドラインに沿って、アプリケーションテンプレートを作ります。今回のテンプレートは vue-ts で実行。

.
|-- README.md
|-- index.html
|-- package.json
|-- public
|   `-- favicon.ico
|-- src
|   |-- App.vue
|   |-- assets
|   |   `-- logo.png
|   |-- components
|   |   `-- HelloWorld.vue
|   |-- env.d.ts
|   `-- main.ts
|-- tsconfig.json
`-- vite.config.t

こんなテンプレートが一瞬で出来上がるので、立ち上げ自体もプロジェクトディレクトリ上で npm i をしてから、npm run dev で出来る環境になっています。

テンプレート構成について

https://ja.vitejs.dev/guide/#index-html-とプロジェクトルート

Viteは vite コマンドを動作する際、エントリーポイントを index.html に置きます。そのため、デフォルトでは index.html がプロジェクトルート直下に配置されています。

Vite は index.html をソースコードとして、またモジュールグラフの一部として扱います。JavaScript のソースコードを参照している <script type="module" src="..."> を解決します。インラインの <script type="module"> や <link href> で参照される CSS も Vite 固有の機能を利用できます。さらに、index.html 内の URL は自動的にリベースされるため、特別な %PUBLIC_URL% プレースホルダは必要ありません。

静的な http サーバと同様に、Vite には、ファイルの提供元となる「ルートディレクトリ」の概念があります。ドキュメントの残りの部分では <root> として示されています。ソースコード内の絶対 URL は、プロジェクトルートをベースとして使って解決されるため、通常の静的ファイルサーバを使用しているかのようにコードを記述できます(より強力な方法を除く)。Vite はルート外のファイルシステムの場所に解決される依存関係を処理することもできるため、モノレポベースの構成でも使用できます。

index.html` を起点に、様々なスクリプトを必要な分だけimportしていく様な挙動をしていく様ですね。他のビルドツールの場合はDevサーバー起動の場合、ページ遷移等のイベント毎にリソースをビルドしてから表示をするので、これに比べてサクサクになる、との理解です。

デフォルトの index.html では、Vueアプリケーション側のエントリーポイントである main.ts とつながっているので、HTMLではメタ情報メンテナンスに尽力して、実ページ等は src 配下のVueリソース群を作り込んでいく様な形になります。

npm run dev する

高速だ!と言われるDevサーバー起動は、大体1秒(1200msぐらい)で完了しました。リソースを足した後でも、立ち上げるのに大体1500ms程。

https://ja.vitejs.dev/guide/why.html#遅いサーバ起動

ここにも書いてあるのですが、依存を精査の上、リソースを生成していた従来のビルドツールに対して、Viteはリクエストに応じたリソース提供をするため、アプリケーションサイズが大きくなっても、「必要分だけリソースを渡す」との役目に徹して、高速さがキープされる具合ですね。

https://ja.vitejs.dev/guide/why.html#遅い更新速度

ちなみにホットリロードもとても速い。

Vite では、HMR をネイティブ ESM 上で行います。ファイルが編集されたとき、Vite は編集されたモジュールと最も近い HMR boundary 間のチェーンを厳密に無効化することで(大抵はモジュール本体だけです)、HMR による更新はアプリケーションのサイズに関係なく一貫して高速で実行されます。

待ちのストレスがたちまちに無くなり、とても良いなー、となりました。

Vue3を書く

Vue3でアプリケーションを書きます。Vue2を大して覚えていないので、ギリギリ覚えている箇所だけを取り上げつつ、インパクトが大きかった点を書き落とします。

<script setup>

https://v3.ja.vuejs.org/api/sfc-script-setup.html#基本の構文

Vue3の目玉と言われたComposition APIで使える記法。単一ファイルコンポーネントとComposition APIを利用するならば「オススメ」として、本体からも推されています。

  • ボイラープレートが少なくて、より簡潔なコード
  • 純粋な TypeScript を使ってプロパティと発行されたイベントを宣言する機能
  • 実行時のパフォーマンスの向上(テンプレートは中間プロキシなしに同じスコープ内のレンダリング関数にコンパイルされます)
  • IDE で型推論のパフォーマンス向上(言語サーバがコードから型を抽出する作業が減ります)

<script setup> で書かれた内容は、Composition APIの setup() と同等として実行されます。宣言した変数は <template> で参照可、何より元々にあったボイラープレートがスッキリ無くなり、めちゃくちゃ普通のJavaScript(TypeScript)の様に処理が書けます。

<script> とも併用が出来るので、<script setup> に固執しなくとも、各種シーンに対応が効きそうです。ドキュメントでは inheritAttrs が例に挙がっていますね。

コンポーネントへのデータバインドが楽に

Vueは、親画面とコンポーネント間の propsemit が面倒だったイメージが大きかったのですが、<script setup> を利用している場合、 v-model さえ渡してしまえば、暗黙でバインドされる様になっていました。

レンダリング用だけのコンポーネントを作る機会があったので、下記はそれを転用した props の例です。emitdefineEmit で、型定義をしながら実装可能です。

  • コンポーネント
src/components/SampleComponent.vue
<script setup lang="ts">
defineProps<{
  hoge: string
}>
</script>

<template>
  <div>
    <p>{{ hoge }}</p>
  </div>
</template>
  • コンポーネント登録
src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import SampleComponent from './components/SampleComponents.vue'

createApp(App).component('SampleComponent', SampleComponent).mount("#app");
  • コンポーネント利用
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';

const hoge = ref('');
</script>

<template>
  <div>
    <input v-model="hoge" placeholder="書いてくれ!" />
    <SampleComponent :hoge="hoge" />
  </div>
</template>

<template> でルートノードが不要に

(惰性で書いてから気付いたのですが)、ルートノードが不要になりました。

<template>
  <div>
    <p>hoge</p>
    <p>fuga</p>
  </div>
</template>

<template>
  <p>hoge</p>
  <p>fuga</p>
</template>

ネストが減ってうれしいですね。

まとめ

ドキュメントをちゃんと読みつつ進めないと、、の様なハマりポイントはあったものの、Vite + Vue3 + TypeScriptはとても快適でした。Viteは速い上、Vue3もComposition APIのおかげで、「あれ、どういう構文でプロパティとか書かないとダメだったんだっけ、、」の様な、ボイラープレートを思い出せず辛い、の様なシーンも無くなりました。うれしいですねー。

フレームワークとしての思想の差はあれど、書き味としては、JavaScriptをゴリゴリ書くことで解決出来るシーンが増えたからか、Reactと近くなってきた様なイメージです。紆余曲折を経て、今は、JSXとして全てを関数として取り回しが出来て、hook等うれしいサポートもあるReactの方が好みではあるのですが、Vue3もここまで来ると、書き味としてはもうほとんど好みの問題に収まる気がしてきた、、

ともあれ、Viteも入れてうれしい構成を検討出来るオプションが広がったので、とりあえず私としては、今年は惰性でNext.js!みたいな感じより、もうちょっと幅を広げて色々チャレンジしてみるかー、との結論に落ち着きました。

Discussion