Nuxt + Composition APIを実用するための判断基準

NuxtとComposition APIの組合わせ

Vueはバージョンが2と3の狭間で新規のプロダクトを作る時にどういう選択をとればよいのか迷いますね。

特にSSRが必要でNuxtを使うような場合にこれまで通り2系のOptions APIを使うのか3系に先取って公開されているComposition APIを使うのか

将来的なアップデートを考慮するとComposition APIを使ってVue3がリリースされたら対応できるようにしたいと気分になりますよね。
ですがその一方でまだまだNuxtは正式にComposition APIに対応されている状態とは言えません。

そんな迷走してしまいそうな時期にNuxtでComposition APIとどう付き合うかSSRに重きを置いて書いてみたいと思います。

バージョンは記事公開時点の最新とします。

  • @vue/composition-api:0.6.7
  • nuxt:2.13.0

Nuxt + Composition APIはSSR可能か

Nuxtを使うことで初期のセットアップが非常に簡単でスピーディーだったり、ある程度の規約があるのでチーム開発に向いている、というメリットがあります。

ですがNuxtを採用するプロジェクトでの一番の期待はSSRではないでしょうか。

単にVueとExpressのようなNode.jsのフレームワークと組み合わせて自分で構築する、といった手間がなくNuxtを使えば簡単にSSRを実現することができます。

ちゃんとSSRできるならNuxt + Composition APIの組み合わせは1つの選択肢になりうるだろうと思っています。

asyncDataの対応状況は?

NuxtでSSRする時に使うメソッドでasyncDataがあります。 下記のようにasyncDataでreturnしたデータをテンプレートで使うことができ、SSRされるというものです。

<template>
<div>{{ msg }}</div>
</template>
<script>
export default {
asyncData() {
return {
msg: 'Hello World'
}
}
}
</script>

Nuxtを使ったことがある人であれば誰もが使ったことのある仕組みではないでしょうか。

asyncData内ではthisにアクセス可能なので、Vuexを使えるように設定している場合はthis.$storeのようにストアにアクセスすることも可能です。

まずComposition APIでasyncDataを使ってもSSRできるかどうかは、可能です。

しかし制限もあります。
Composition APIではthisにアクセスすることができるのはsetupのみです。

<script>
import { defineComponent } from '@vue/composition-api'
export default defineComponent({
 asyncData() {
   return {
msg: 'Hello World'
}
 }
setup() {}
})
</script>

asyncDataでreturnしたデータにtemplateでアクセスすることは可能でSSRもされます。
ですがthisにアクセスしてもundefinedであるためストアにアクセスすることができません。

NuxtではAPIを呼んで$storeに値をアクセスするのにfetchを使う作法はありますが、Composition APIでfetchを定義すると

Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option.

という警告が表示されてしまいます。
また警告がでなくてもthisはやはりundefinedであるためこれまで通りのVuexの使い方では使えません。

Vuexのバージョン4系

Vuexは3系までのようにthis.$storeのようなアクセス方法ではなく、Composition APIで使えるようになる最新バージョンのベータ版が公開されています。

https://github.com/vuejs/vuex/releases/tag/4.0.0-beta.2

const store = useStore()

のように定義したstoreに関数でアクセスできるようになる3系までとは違った仕様になるようです。

ドキュメントはまだ正式に公開されてるわけではなく、やはりベータ版なので実用はまだ様子を見たほうがいいとは思っています。

Vuex4系のようにthisでアクセスしないようなstoreの仕組みを自分で実装することができれば、storeが必要なプロダクトでもNuxt + Composition APIでSSRは可能そうです。

piniaというComposition APIで使えるstoreを実装するためのライブラリもあるようですが、Nuxtとの相性は不明です。

今度機会があれば試してみようとは思います。

https://github.com/posva/pinia

NuxtでComposition APIを採用しても良い場合

現状ではまだComposition APIでの対応が後追いになっているNuxtですが、どういう状況で組み合わせてよいかな?と考えた時・・。

作成するプロダクトに対して責任を自社(もしくは個人)で完結できるのかです。

やはりまだサポートが追いついておらず、不明瞭な部分も存在する状態で受注案件のような顧客の依頼で開発するような場合には使わないほうが無難だろうと思います。

実装を進めて行く中で予期せぬバグを踏んだり、ライブラリ自体に対応を入れないとどうにもならない、となってしまった場合に困るからです。

そのような状態になってしまった場合、「Composition APIが・・」や「Nuxtが・・」なんてことは通用しません。

Composition APIを使うことでVue3への移行はスムーズに行くかもしれません。
ですが受注案件においては安定したプロダクトを提供する価値が高いですし、Vue3がリリースされても顧客からバージョンアップしましょう!となる案件は少ないように思います。

開発を追いかけてアップデートするための覚悟

受注案件ではComposition APIを使わない方が良さそうというのは書いた通りですが、責任が持てれば使うのはアリか?というと規模だったり覚悟によるという印象です。

というのもやはりまだまだ策定中の仕様も多く、例えばNuxtで1番影響を受けるSSRするためのasyncDataも今後どうなるかわからないという不安があります。

asyncDataを使わずSSRする仕組みも議論されています。

現在はひとまずasyncDataで動かせていてもバージョンアップした時のために、どういう風になっていくのか情報をキャッチアップしていかないといけません。

5ページにも満たないような小規模のプロダクトであれば、最悪仕様が変更になっても対応できそうですが中・大規模ともなるとやっぱりまだ使うのは早かった・・と後悔する可能性もあります。

そこまでのリスクを背負ってでもNuxtとComposition APIの組み合わせて使う意味はあるか?というのはよく検討したがほうが良さそうです。

まとめ

Vueのバージョン3がリリース前の今、NuxtとComposition APIの組み合わせに対してSSRに重きをおいてどう付き合うかを考えてみました。

これまで書いてきた通り今のところ積極的に使うメリットは低いように感じています。
あくまで使ってみたいという興味本位レベルなら・・。

近年ではVueを使うならとりあえずNuxtを使う、くらいの雰囲気さえ感じますがバージョン移行で安定するまでは時期尚早。
またTypeScriptを使うのが当たり前のようになってきている昨今で、不安定な状態でさらに型までつけるのは相当厳しいですね。

もしVueというしばりがなく個人もしくはチームで、コードに関わる人全員がReactも触れるのであればあえてVueを採用しないのも選択肢だと思います。