CTOの名人です。
今回はNuxt×TypeScript周辺に絞って、おすすめライブラリを並べていきます。TypeScriptを駆使してオンライン教育を革新していくメンバーを募集していますので、気になった方は応募してください!
composition-api系
Vue3から追加されたcomposition-apiは、個人的にはゲームチェンジャーになると言っていいほど革新的なものだと思っています(もちろんReact Hooksも)。
こんな記事も書いています。
簡単に言えば状態管理ごと処理を特定の関数に切り出すという設計思想です。非同期通信を多用するフロントエンドにおいては、非同期処理を行っている間、ローディングを出したり、エラーが返ってきたらエラー文言を出すと言った非同期処理と関連する状態の管理が煩雑になりがちです。そもそも非同期通信を実行する関数自体が、[通信結果のデータ、通信状態、エラー、その他状態]をセットで返してくれたら、関数の呼び出し側はそれらをViewにバインドするだけで済むやん!という発想が優れていると思っています。
@nuxtjs/composition-api
https://github.com/nuxt-community/composition-api
Nuxt.jsでcomposition-apiを繋ぎこむためのプラグインです。
defineComponentやsetupといったcomposition-apiの機能が使えるのはもちろん、useContextというフックでContextオブジェクトを取れるといったNuxt独自の機能も備えており便利です。公式のプラグインということもあり、Nuxt3になったときもそこまで酷いデグレはしないんじゃないかなと期待しています。
const context = useContext() // context.app.$pluginNameが使える
2021年2月下旬時点では、依存している@vue/composition-apiは1.0.0-rc系なので、そろそろ安定しつつあるのではないかと思います。
"@vue/composition-api": "1.0.0-rc.1",
vueuse
続いては、Vueuseというライブラリです。その名の通り、Vueを使ったuseHoge()のカスタムフックを集めています。
https://github.com/vueuse/vueuse
ちょっとなんでもかんでもuseHoge()にしたらいいってもんじゃないよってくらい色々なフックが集まっているのですが、以下の関数は便利かなと思います。
https://vueuse.org/core/useMouse/
useMouseはマウスの位置を返すフックです。
https://vueuse.org/core/useWindowScroll/
スクロール位置を示すフックです。現実的には、現在どっち向きにスクロールしているかを取りたいときがあったので、以下のように内製でuseScrollを拡張したものを作りました。isUpとかisDownで向きがわかります。
import { useWindowScroll } from '@vueuse/core'
import {
reactive,
toRefs,
watch,
} from '@nuxtjs/composition-api'
export const useScroll = () => {
const { x, y } = process.browser ? useWindowScroll() : { ...toRefs(reactive({x: 0, y: 0})) }
const state = reactive<{
isUp: boolean,
isDown: boolean
}>({
isUp: false,
isDown: false,
})
watch(y, (newY, oldY) => {
if (newY > oldY) {
state.isUp = false
state.isDown = true
return
}
if (newY < oldY) {
state.isUp = true
state.isDown = false
}
})
return {
x,
y,
...toRefs(state),
}
}
SWRV
続いてはSWRVです。これはフロントでStale-while-revalidateしてくれるAPIクライアントライブラリです。弊社のマナリンクではほとんど使うべき場面が見つかっていないので、軽い紹介まで。
Stale-while-revalidateが肝とはいえ、単にAPI通信を実行して、errorやisValidatingといったステートを一緒に返してくれるという点だけでも利用価値はありそうです。Stale-while-revalidate自体も、本質的には呼び出し側がStale-while-revalidateやってるな〜って理解しながら呼び出すのは不便なので、脳死でStale-while-revalidateさせるように考えて組めばいいのかもしれません。
const { data, error, isValidating, mutate } = useSWRV(key, fetcher, options)
開発補助系
schema-dts(SEO対策系)
https://github.com/google/schema-dts
SEO対策でよく行われる構造化マークアップを型安全にするライブラリです。Googleがメンテナンスしており、退屈になりがちなSEO対策のDXを向上させてくれます。
JSON-LDを生成する以下のライブラリも便利です。
https://github.com/ymmooot/nuxt-jsonld
個人的には、型安全なパンくずリストについての研究を進めたいと思っていて、固まったらnuxt-typesafe-breadcrumbsといった命名でnpm公開しようかなと思っています。
ts-auto-mock
これ結構すごいです。
型定義から、モックデータを自動生成するファクトリのようなライブラリです。
import { createMock } from 'ts-auto-mock';
interface Person {
id: string;
getName(): string;
details: {
phone: number
}
}
const mock = createMock<Person>();
mock.id // ""
mock.getName() // ""
mock.details // "{ phone: 0 }"
テストコードを書くときにとても便利です。大きめの型でも簡単にダミーデータを用意できます。
aspida
何百回と言っていますが、TypeScriptでREST APIを叩くならaspidaというライブラリがおすすめなのでぜひ使ってください。これがあるので1年半前の自分がTS対応に踏み切れました。
最近注目のライブラリ
VeeValidate
フォームのライブラリですが、最新のV4ではVue3の記法を採用しており、勝手に注目しています。現在僕はVuelidateを使っていますが、NuxtのVue3対応を待って、こちらのVeeValidateに移行しようと思っています。
useFieldといったフックがあることで、ロジックとUIを切り離せるのが嬉しいです。Vuetifyとかは、UIとロジックが密結合しちゃうので、ロックイン度合いが高すぎるように思っています。
ts-auto-guard
まだ常用していないのですが、Type guardを自動生成するCLIツールで、結構便利そうです。なにかとタイプガード使いますからね。
そもそもどうしてNuxt×TypeScriptをやっているのか
ちょっとだけ技術選定的な話もしたいなと思います。
まず、スタートアップではMPAでガツンとモノリシックで構成する企業も多いと思いますが、なぜSPAを採用したのか、です。
オンライン指導をマナリンク上で完結させるWebアプリケーションおよびスマホアプリを開発していくにあたっては、中長期的にはリッチなSPAをベースに先生向け、ご家庭向けの管理画面を構築していきます。
現時点ですでに、Web上でリアルタイムチャットができる機能を構築しています。
シンプルなチャットとはいえ、テキスト、画像、ファイル送信に対応し、また先生がご家庭ごとにメモを残せたり、生徒の学年や志望校を見ながらチャットできるようなUIを開発しています。もちろん決済機能もあるため、先生が日々の売上を管理する機能なども備えています。
今後、指導日を管理できるカレンダー機能や宿題や学習状況をすり合わせしていくようなUIを作っていく予定です。要は、かなり次々に画面上で操作していくUIになると見込んでいます。これらの画面をMPAで作ると、なにか操作するたびに都度リロードを挟まないといけなかったりします。致命的ではないにせよちょっともっさりしそうです。
また、実装工数においても、jQueryでリアルタイムチャットを構成するとなると、現在においては明らかにSPAのほうが楽だと感じていますし、JSのエコシステムがSPAを興隆させる方向に向いているので、リッチなUIを作り込んでいくのであればSPAのほうが望ましいと思います。
マナリンクもはるか昔はLaravelのMPAでしたが、こうなっていくことがなんとなく見えていたので、1年半ほど掛けて、フロントを全部Nuxtにリプレイスした経験があります。今のところ、その判断自体は間違っていなかったと思っています。
SPAのなかでも、NuxtとNextが2大勢力的な感じですが、当時の自分がVueしか触れなかったのでNuxtを選定したのが正直なところです。ただ、今の僕の実力を持ってマナリンクをスクラップアンドビルドするのであれば、もしかするとNext.jsを選ぶかもしれません。Reactを使ったほうが、マナリンクのアプリがReact Native製のため相性がより良いからです。加えて、ISRを使うとSEOが重要な一覧系のページでも表示パフォーマンスを出すことができ、UXとパフォーマンスの両立が図れます(※2年ほど前のNext.jsは今ほど成熟していなかったと思うので、当時にタイムスリップした、という想定にするとNuxtかも)。
また、TypeScriptをやっている理由ですが、もはや素のJSで書くのは安全ではないと言い切れるからです。加えてTypeScriptはエコシステムの巻き込み方がうまく、既存のJSライブラリにあとから型をつけることができる点などが優秀です。Conditioinal Typesなどを使い込んでいくと、型定義のレベルでそれなりのプログラミングができるくらい型の表現力が豊かで、多種多様なデータを扱うフロントエンドに相性がいいです。僕はPHPやRuby出身のWebエンジニアですが、LL言語中心で育ってきたエンジニアにジェネリクス等を含めた型の概念を教育するという意味でも素晴らしい功績を果たしている気がしますw
よく言われるVueとTSの相性ですが、Reactなどと比べてしまうともちろん良くないです。しかし、批判するほど悪くないと思います。それは、ReactよりHTMLやCSSに対してフレンドリーなVueの思想があるからある意味当然なことです。技術を批判するときはトレードオフを考慮しないといけないな、とよく思います。あえていうと、composition-apiのRefやReactiveの使いどころの違いとか、JS内ではいちいち.valueを付けないといけないといったあたりが、React Hooksと比べるとちょっと書きにくいな、とは思います。
今回は以上となります。
TypeScriptを駆使してオンライン教育を革新していくメンバーを募集していますので、気になった方はぜひぜひ応募してください!
株式会社NoSchoolでは一緒に働く仲間を募集しています