LoginSignup
4
2

More than 3 years have passed since last update.

Rails + Nuxt + GraphQLでSSR対応のSPAを作る場合の俺的ベストプラクティス

Last updated at Posted at 2019-05-09

個別のライブラリについての記事はたくさんありますが、
どれをどう組み合わせれば楽に作れるか?の情報がなかったので、書きました。
それぞれについての詳しい情報はぐぐってください。

この記事で紹介するライブラリを組み合わせると以下のことができます。

実現できること

  • SSR対応のSPA
  • 各ページ一回のリクエストで描画に必要なデータをすべてもってこれる
  • N + 1問題を防げる
  • つなぎこみのコードが少なくて済む(サーバーのコントローラーやクライアントのストア)

ライブラリ

  • rails
  • graphql-ruby
  • graphql-batch
  • search_object
  • search_object_graphql
  • nuxt
  • vuex-orm
  • vuex-orm graphql plugin
  • isomorphic-fetch

graphql

railsなのでIDのタイプはBigIntにしようとしたが、
idがstringになってしまうので
Floatにした。53bitまで

graphql batch

graphqlのtypeは遅延評価で書いていく。
N + 1問題を防げる。
単純な関連だけではなく、computedなカラム(ユーザーが持つ記事の数など)も高速にserializeできる

search_object + search_object graphql plugin

フィルタ付きのgraphql resolverをかんたんに書ける。
でもちょっとしか使っていないので、こいつが本当に良いのかはあまり良くわかっていない。

クライアント側のデータ管理

各ページのasyncDataで、そのページに必要なデータをすべて取得する。
GraphQLで関連を一気に取得して少ない回数で取得する。

vuex orm

マジで快適。
いちいち検索するコードとかを書く必要がなくなる。

モデルにcomputedなカラムもかんたんに追加できる。
いちいちモデルをimportするのが面倒なので

this.$store.models.User

みたいに$storeにmodelsを無理やりはやした。

railsはincludesしなくても必要になればロードしてくれるが、こいつはwith(includes相当のもの)をつけないと、nullになるので要注意。小一時間ハマった

もう一個のハマりポイントは、
モデルにはやしたインスタンスメソッドがタイミング次第で呼べないことがある。

  • ブラウザリロード直後 -> ちゃんと表示される (SSR)
  • ブラウザリロードして少し後 -> 表示が崩れる (インスタンスメソッドを呼べてない)
  • リロードせずに遷移 -> ちゃんと表示される (インスタンスメソッドを呼べている)

vuex ormのfindとかはstoreのデータを返しているだけ。
返すときにdecorateしたりとかはしないらしい。

vuex ormを改良するか、インスタンスメソッドではなくstaticメソッドで、
Model.myComputedColumn(instance)とするかが良いと思う。

多分ここでは?
https://github.com/vuex-orm/vuex-orm/blob/eab95aabe805b39244ac8ca7eb2096330cd56ab7/src/query/Query.ts#L558

eager loadのカラムが一つもないと、生データが返ってしまう。

仮説

  • リロード直後はSSRで渡されたplain objectがstoreに入っている
  • vuex orm初期化時にはhydrateされない
  • 更新時にhydrateされる
  • 遷移時には更新されるのでhydrateされてplain objectからモデルに変換されるから、遷移時には正しく表示される
  • findでも関連がある場合に限りhydrateされる <- こいつを強制すれば良い

-> なおった
https://github.com/contribu/vuex-orm/compare/master...feature/fix_hydrate

あと、これって二重にhydrateされていないか?
動作に問題はないと思うが、
hydrateIfNeeded的な仕組みにすればすっきりすると思う

vuex orm graphql plugin

取得系はマジで快適

  • 取得クエリがかんたん (vuex ormのモデル定義からクエリ生成)
  • ネストしたモデルを自動的にvuex ormに書き込んでくれる

Eager loadは工夫する必要がある。
railsのincludesみたいに、取得するときにどの関連を含めるか含めないかを調整できれば良いが、その機能は無くて固定。
だから、取得前にモデルのeagerLoadを書き換えて、取得後に戻すやり方にした。

vuex orm graphql pluginのmutationは、InputTypeが元のモデルのタイプと一致することを要求するので、使いづらい。
ここは自前でmutationとのつなぎこみを書いていく。

vuex orm graphql pluginの代替や、vuex orm graphqlでうまくやる方法を知っていたら教えてください。

isomorphic-fetchを使うとSSRできる。

サーバーのエラー処理

rescue_fromでActiveRecordのエラーなどをGraphQL::ExecutionErrorに変換していく。詳細はぐぐって

サーバーのgraphqlのテスト

request specとして書いていく。graphqlは生で書く
(こんな感じになる https://selleo.com/blog/testing-graphql-mutations-in-ruby-on-rails-with-rspec)
と思ったが、クエリーを作るのが意外と面倒。

以下のやり方が良さそう。
https://medium.com/@RJrobinson/testing-graphql-ruby-mutations-with-rspec-f5c7d02b1e58
ベタ書き版: https://graphql-ruby.org/schema/testing.html

もっと良いやり方があったら教えてください

4
2
0

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
4
2