LoginSignup
196
116

Vue3をアゲアゲ↑↑する記事

Last updated at Posted at 2023-08-26

はじめに

こんにちは、フロント歴7年目のエンジニアになります🙂

今回は日頃仕事でお世話になっているVue.jsに感謝の意を込めて、
Vueの素晴らしさを皆さんに少しでも感じて貰えたらと思い、この記事を投稿することにしました。

アゲアゲするとか言って

「どうせSFCが便利とか言いたいんでしょ?」
「script setupが凄く凄いとか言いたいんでしょ?」

・・・いえいえ、そんな当たり前のことを話したいわけではありません。
もっと深いところの説明だったりをですね、:sweat_smile:

「いやでも最近のVue3はReactに似ているから、それならReactで良くね?」

全く良くないです:rage:

はい、そういった人達にこそ見て欲しい内容となっております。
つまり私がVueが優れていると信じ使い続ける理由です。

この記事では、Vue.jsの書き方みたいなことは扱いません。
またVueの魅力をお伝えする都合、他のフレームワークを引き合いに出すことがありますが貶める意図は一切ありません。

それでは見てきましょう!

1. fine-grained Reactivityであること
2. out of boxで動作すること
3. computedやscoped cssがやはり魅力的なこと
4. エコシステムが十分成長したこと
5. 更なる進化を控えていること
6. 番外編:一方で・・

fine-grained Reactivityであること

この言葉が界隈で頻繁に聞かれるようになったのは、
SolidJsがその年のstate of jsで一位を取り、その存在が世に知られるようになってからだと思います。

スクリーンショット 2023-08-26 4.26.43.png

SolidJsは当初「Better React」などと呼ばれ、その類似性を主張した記事が後を絶たなかったのを覚えています。

今にして思えば、「シンタックスがReactにかなり近く、それでいてパフォーマンスが大幅に改善されたもの」という印象が一人歩きしていたように思います。

僭越ながら訂正させて頂くとSolidJsは
「シンタックスはReactにかなり近いものの、根底に流れる思想(リアクティビティ)はVueにかなり近いもの」です。

つまりそれこそがfine-grained Reactivity(きめ細かな反応性)です。
ではその定義は何でしょうか? Vueのドキュメントには以下のように記載されています。

基本的に、シグナルは Vue の ref と同じ種類のリアクティビティープリミティブです。これは、アクセス時の依存関係の追跡と、変更時の副作用のトリガーを提供する値コンテナーです。

シグナルとして認定されるために必要な特性ではありませんが、今日、この概念はきめ細かいサブスクリプションを通じて更新が実行されるレンダリングモデルと一緒に議論されることがよくあります。

特段定義としてあるわけでは無さそうですが、
ReactとVue/Solidで状態の変更をどのようにトリガーしているかを考えればそんなに難しい話ではありません。

Reactは皆さんご存知の通り、
状態が変わった時にコンポーネントごと再評価(以降再レンダリングと表現)することによってリアクティブを実現しています。

誤解を恐れず噛み砕いて書くと、Reactは
全部が全部再レンダリング対象のコードの中から、どれを再レンダリング対象から除外するか」という意識を常に持ちながら実装を進めていくことになります。

一方でVueとSolidにおいては、
一度しか読み込まれないコードの中から、どれを再レンダリング対象として追跡するか」となり全く正反対のモチベーションであることが分かると思います:grimacing:

後者の何が嬉しいかというと、
開発者がパフォーマンスを意識せずともフレームワーク側がそれを保証してくれるのです。

パフォーマンス改善のための特別なAPIは要りません。
これこそまさにイージーであり、シンプルです。

Reactの経験がある方で、初めてSolidJsのAPIを触ってみた方の中には、

「確かにJSXは使っているし、APIとしてもusecreateになって、statesignalになっただけ・・だけど何か違う。。」

と違和感を覚えた方は少なくないのではないでしょうか?

それは上記のようにメンタルモデルが全く異なるからで、
恐らくReactに慣れている人ほどこの違いは受け入れ難いものであると思います。

逆に違和感を感じずこっちの方が良い!と思った方は、
ぜひVue3の世界も覗いてみてください:sunglasses:

ここではコードを交えた解説はしませんが、
VueもSolidと同様setup関数は一度しか実行されないためAPIの動きもほとんど同じです。(APIの形が違うだけです)

createSignalref
createMemocomputed
createEffectwatchEffect

じゃあSvelteはどうなの?と思った方。
SolidJsの作者であるRyan氏がその辺りの違いをポストしているので見てみてください。

では次に進みます。

out of boxで動作すること

これに関してご存知ない方も多いかと思いますが、Vueの状態はVueの外でも動作します。

つまり状態だけ利用してVue自体は使わない
=createApp(App).mount('#app')を呼ばないということだって出来ます。

以下のコードはプレーンなjsの記述であり、通常のhtmlで読み込んでもちゃんと動きます

// vueのAPIだけimport
import { ref, watchEffect, computed } from "vue";

// 状態の定義
const user = ref();
const userName = computed(() => user.value?.name);

// 状態の監視
watchEffect(() => {
  console.log(userName.value); // 山田太郎
});

// ログイン時に呼ばれる関数
const login = () => {
  user.value = {
    name: "山田太郎",
  };
};

login();

「Vueの状態管理だけ使ってVue本体は使わない」というケースは実際にはほぼ無いと思いますが、
一方で「別のテンプレートエンジンに乗っかる形でフロントフレームワークを使う」というケースは割と多いのでは無いでしょうか・・?

私の周りでよくあるのが、
Laravelのbladeファイルに部分的にフロントコンポーネントを使用するパターンです:fearful:

でも安心してください!
そういう時こそ、このout of boxで動作する特徴がとても役に立ちます!

・・というのも完全なSPAであれば、
状態を全てフロントフレームワーク側で保持できるためそもそも問題にはならないのですが、
MPAの場合は通常、フレームワーク外でも複数のJSファイルが混在することになるため、
プレーンなJsファイル⇆フレームワーク間での状態の共有が課題となってきます。

端的に言うと、

こっちのJSファイルで今取得した値を、そっちのjsファイルやvueファイルでも検知して使いたい

と言うことです。:thinking:

この時にVue3の状態管理(CompositionAPI)をベースに構築していれば、
とりあえず再利用しそうなものはcomposableに置いて、
フレームワーク内でも外でも自由にimportして利用、更新・・ということが出来るわけですね。

「認証状態が変わったら〜」など、
プレーンなJS側でもwatch検知できるのは有り難いですね!

そしてそれが出来るのは、
Vueの状態管理が皆さん大好きな「Just JavaScript」だからです。

ただのJavaScriptなので、
Reactなどの他のフレームワークにも持っていけますし、
APIの形をSignalに変化させることだって出来ます。
すごく柔軟!汎用的!

話を少し戻して、先ほど話した例は
状態をcomposableの外に置いた場合になります。
この場合はどこで呼び出しても1つの共通の状態が取得できます。

import { ref, watchEffect, computed } from "vue";

const user = ref(); // どこで呼び出しても同じものが入っている
const useAuth = () => {
  const userName = computed(() => user.value?.name);
  const login = () => {
    user.value = {
      name: "山田太郎",
    };
  };
  return {
    user,
    userName,
    login,
  };
}

もし状態をcomposableの中に置けば、
呼び出した先のスコープ内で初期化された状態になる・・といった感じで使い分けが可能です。
控えめに言って最高ですね!:v:

import { ref, watchEffect, computed } from "vue";

const useAuth = () => {
  const user = ref(); // 呼び出し先ごとに独立して存在する
  const userName = computed(() => user.value?.name);
  const login = () => {
    user.value = {
      name: "山田太郎",
    };
  };
  return {
    user,
    userName,
    login,
  };
}

え・・・「.value」が気になる・・・?

これはリアクティブな変数かそうじゃないかを判断するために必要なものです。

まぁ慣れです慣れ。慣れたらむしろ必要だと感じます:slight_smile:

これに関しては恐らく先入観みたいなのが邪魔していると思うので、
私から別の先入観も埋め込んでおきます。

PreactQwikでも状態管理に.valueアクセスが使われていることはご存知の方いるかと思いますが、

実はあのflutterでも最近は.valueアクセスが使われています。

flutter_hooksと呼ばれる、
React hooksからインスパイアされた今主流と言って良い状態管理ライブラリがあるのですが、
そこではごく自然に.valueアクセスが採用されています。
(APIの動きとしてはReact寄りです、あくまでシンタックスの話です)

【参考】
https://qiita.com/takashimelon/items/471e94cac72434cd0f5c#flutter-hooks

実はVue3は出た当時から時代のかなり先を行っていたんですね。
どうです?少しは抵抗感が無くなってくれたら嬉しいです:innocent:

[追記]
out of boxで動作することの具体的な実装例として以下投稿しました、こちらもよければ見てみてください:point_down:
Vue3のすゝめ 〜外部テンプレートエンジン編〜

computedやscoped cssがやはり魅力的なこと

Vueの好きなところは沢山あるのですが、特にこの2つの特徴が個人的には外せません。

computedに関しては、
SolidJsでもcreateMemoとしてほぼ同じAPIを提供していたり、
Svelteでも$: () => {}で使えたりしますね。

refとwatchを組み合わせたようなAPIで、
開発に慣れている人ほどwatchを極力使わずにcomputedに依存対象を閉じ込める実装をしているのかなと思います。

そしてその作業が結構快感なんですよね!:relaxed:

・・・はい、次にscoped cssですが、個人的にはJSXがどうかと言うよりも
scoped cssがデフォルトで使えるか」と言うことがフレームワークの選定基準として強くあります。

最近はTailwindが流行っているので絶対必要と言うケースは少なくなってきているのかもしれませんが、
私は直接styleを書きたい派なのと、web制作寄りの人たちにとっても協業する上で必要な要素でしょう。

またVue3.2から、JSの変数をstyleブロックにバインドできるようになったのも凄いですよね!
こちらも使い方次第で色々と可能性が広がりそうです:relaxed:

<script setup>
import { ref, computed } from "vue";

const colors = {
  white: "#ffffff",
  red: "#ff0000",
};
const color = ref(colors.red);
const isDarkMode = computed(() => color.value === colors.white);
</script>

<template>
  <p class="text">文章</p>
</template>

<style scoped>
.text {
  color: v-bind("color");
  background-color: v-bind("isDarkMode ? '#000000' : colors.white");
}
</style>

エコシステムが十分成長したこと

まずは私が作ったクソコラの供養をさせてください。

FgpUTWKaEAAJK0b.png

Vue3過渡期を経験した人なら分かると思いますが、
当時は周辺ライブラリの状況が本当に悲惨でVueから他のフレームワークに脱した開発者も少なくありませんでした。

当の私もSvelteやSolidJsを渡り歩きましたが、
そこで感じたのは結局全てに満足するフレームワークなんてものはなく、
「ここは好きだけどここは嫌い」みたいなのばっかりだなー・・というだけのことでした。(当たり前ですね:sweat_smile:)

とはいえ色んなフレームワークに手を出してみることは、個人的には良いことだと思っています。
新しい発見もあるでしょうし、元々使っていたフレームワークにより詳しくなったなんてことも。

最終的に自分の手に馴染んで、自分の言葉で説明できるものを使うことが大事なんだと思います。

・・・説教臭くなってしまったので表題の件に戻りますが、

今Vue3で新規開発を始めるにあたり、
「エコシステムが足りなくて始められない!」と言うことはほとんどないでしょう。
それでいて技術選定に悩まなくて良い! というVue2時代からの良さは健在です。

UIライブラリの選択肢は随分と増えましたし(個人的にはElement Plus推し)、
VueのメタフレームワークであるNuxt3も利用者側の満足度は非常に高いです。

また開発する上でVueUseの存在は欠かせなく、
これは公式が提供している便利なcomposable集のようなものになりますが、
先ほど話したようにコンポーネント外でも使えるので非常に汎用性が高いです:flushed:

こういうこと出来ないかな?」と思ったら覗いてみてください、マジで大体あります

またEvan氏がViteを開発した功績も大きく、
Vueは今後ずっとファーストクラスのサポートを受け続けられることが保証されています。なので安心して使ってください。

「でもVue3って破壊的な変更が多いんでしょ・・・?心配」

それなりにありますし、実際Vue2からの移行は辛いところがあります。

ただ誤解しないで頂きたいのは
Vue3に関する悪評のほとんどはVue2からの移行に関するものであり、
Vue3自体は非常に使い勝手が良く優れたフレームワークであるということです。

勿論パフォーマンス面でも優れています。

見てわかる通り現時点でもかなり優秀なのですが、
後述するVaporモードによって更にパフォーマンスが改善されることが期待されています。

更なる進化を控えていること

こちらは最新のVueの動向を追っている方はご存知かと思いますが、
SolidJsにインスパイアされて考えられた代替コンパイル戦略で、
Vue3.4もう少し先からコンポーネント単位で仮想DOMを使う/使わないを切り替えられるようになります。

これによりVueも、SvelteやSolidといった
仮想DOMを扱わないモダンフレームワークの仲間入りですね:blush:
(トレンド的な意味で)

Evan氏の原文そのまま貼ってきます。

Vapor Mode
Vapor Mode is an alternative compilation strategy that we have been experimenting with, inspired by Solid. Given the same Vue SFC, Vapor Mode compiles it into JavaScript output that is more performant, uses less memory, and requires less runtime support code compared to the current Virtual DOM based output. It is still in early phase, but here are some high level points:

Vapor Mode is intended for use cases where performance is the primary concern. It is opt-in and does not affect existing codebases.

At the very least, you will be able to embed a Vapor component subtree into any existing Vue 3 app. Ideally, we hope to achieve granular opt-in at the component level, which means freely mixing Vapor and non-Vapor components in the same app.

Building an app with only Vapor components allows you to drop the Virtual DOM runtime from the bundle, significantly reducing the baseline runtime size.

In order to achieve the best performance, Vapor Mode will only support a subset of Vue features. In particular, Vapor Mode components will only support Composition API and <script setup>. However, this supported subset will work exactly the same between Vapor and non-Vapor components.

逆にVaporモードを使用しない(仮想DOMのままの方が良い)ケースなどあれば聞いてみたいですが、その辺りはいずれ分かってくることでしょう。
気になる方はこちらの動画の22分頃から最新の状況を聞けます。

番外編:一方で・・

これはVueに限ったことではないですが、

コンポーネントやcomposableの設計など、
使い方は分かったけど切り分け方が難しい」と考える開発者の方は少なくないのではないかなと思います。

少なくともVue2開発に慣れていた私でも、
Vue3に入門した時はcomposableの適切な切り分け方が分からず、
こういった日本コミュニティの皆様にお世話になったりしたものです:sweat_smile:

最後に話したいこととして、
1つが公式フレームワーク側で何かしらのガイドラインのようなものを出してくれると有り難いな〜・・ということです。

開発に慣れていればフレームワーク問わず同じような設計でやっていけますが、
新しい概念を取り入れた直後はやっぱり分からないもので最初のうちは特にソースが汚くもなります。

もし規模やサービスに応じたcomponent/composable設計の指針となるものがあれば、基盤設計から始められる開発者も増えていくのかなと思いました。

そして2つ目がもっと大事なことですが、

公式見て分からなければコミュニティに頼ろう!


ということです。

DxJ7jBbUcAAJt9T.jpg

なんせそのフレームワークの専門家が揃っていて、
都合が良いことに困っていることほど解決したい性分の人が多く、
しかも無料で聞けちゃいます!

追記:Vue3のドキュメント学習済みAIもあるので、分からないことがあればまずはこちらに聞いてみるのが良いかも:sunny:

Vueは特にコミュニティの力が大きいです。
というより企業に属さずコミュニティの力だけでココまで来たので、
コミュニティこそVueの本体です!(?)

・・・はい、長くなりましたが最後にコンポーネント設計に困っている人の一助になれば良いなと思い、個人的にしっくり来ているコンポーネント設計貼って終わりとします。

皆さん、新規開発はぜひVue3を採用してみてください!以上!

196
116
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
196
116