もふもふ技術部

IT技術系mofmofメディア

RedwoodJSに入門してみた(第5回: 実際に使ってみて感じたこと)

この記事について

この記事は、全5回の第5回です。 RedwoodJSに入門してみた(第1回: アプリ作成〜モデル作成)

RedwoodJSに入門してみた(第2回: CRUD作成 API編)

RedwoodJSに入門してみた(第3回: CRUD作成 WEB編)

RedwoodJSに入門してみた(第4回: dbAuthによる認証)

RedwoodJSに入門してみた(第5回: 実際に触ってみて感じたこと)

今回はここまでRedwoodを使ってみて感じたことをまとめてみる。

RedwoodJSの良いと思ったところ

ほぼTypeScriptのみで書ける

フロントエンドとバックエンドの両方でTypeScriptの恩恵を受けられるは大きい

Rails, GraphQL (GraphQL Ruby), React + TypeScriptの構成で開発するときなど、変数名一つにしても、バックエンドはRubyだからスネークケースにして、フロントエンドはTypeScriptだからキャメルケースにするというようなコンテキストスイッチが発生していて、細かいことだが、それがないのはやっぱり良いなと思った。

GraphQLが使える

単純にこの構成が好きっていう話なのだが、やっぱりGraphQLは良いなと思った。

フロントで型の恩恵を受けられるし、リソースをまたいでクエリを定義できる。Rails + GraphQLでの開発でも感じたけど、開発体験がすごく良い。

気をつけないとN+1が発生しやすいが、PrismaではDataLoaderが組み込まれているため、そこのデメリットが軽減されるというのも有り難い(もちろん、Queryの定義によってはN+1が発生する)

Generatorコマンドでテストファイルも生成される

RedwoodのGeneratorは基本的に、任意のファイルと同時にテストファイルも生成してくれるようになっている。

例えばyarn rw g cell fooを実行するとFooCell.tsxとは別にFooCell.mock.ts, FooCell.stories.tsx, FooCell.tst.tsxも生成される。

テストコードを書く障壁が少しでも減らされているのは有り難い。

組み込みのRouterが良い

完全に個人的な好みの問題なのだがRedwoodのRouterは、よしなにやってくれる部分とこちらで設定が必要な部分のバランスが丁度いい。後述するpageのインポートには物申したい部分はあるものの、SetやPrivateを使ったコンポーネント定義の見通しの良さ、loading時のレンダリングやpathの定義方法など、機能としても必要十分だと感じた。

RedwoodJSの少し気になったところ

version upの頻度について

良いところにも悪いところにもなりうる点だけど、1.0が今年の4月にリリースされて一年も経っていないが、もう3.6がリリースされている。

メジャーアップデートを恐れずに機能追加していくというような内容をどこかの記事で書いてたので、まだまだ改善されていくんだろうなという期待感があると同時に、互換性がない変更が多いとバージョンアップするの大変そうだなとも思う。

Cellの仕様

Apollo ClientのuseQueryが返す{ data, loading, error }的なやつを1ファイル内で決まったコンポーネント名で名前付きエクスポートして、そのファイルをインポートするという仕様が、どうも慣れない。

ファイルごとインポートする必要があるので名前付きインポートはできず、Cellの呼び出し時はエディタの補完が効かない(なぜか効くときもあるけど、効かないときのほうが多い)

Cellをインポートする場面は結構多いのでなんとかならないものか…(もしくは何らかの設定で解決できるのかも?)

ReactのSuspenseと同じように、loadingの状態がデータを表示するコンポーネントに入ってこないというのは嬉しいけど、個人的にはモヤる仕様。

Routes.tsxでのPageのインポート

Routes.tsxにおいて、インポート文が増えないように、RedwoodがアレコレやっているのでPageをインポートせずに呼び出せて、かつ、エディタでもエラーが出ないようにグローバル変数にしてくれている。

便利そうに感じるのだが、Pageコンポーネントの配置によっては分かりづらい命名になってしまう。(例えば、web/src/pages/Post/PostPage/PostPage.tsxにあるコンポーネントPostPostPageになる)

そこまでするんだったらインポート文があっても良いのでは?と感じた。

もちろんPostPageと入力すれば補完でインポート文も追記されるのだが、Postまで入力した段階でサジェストにPostXxxがたくさん湧いてくるので少し混乱する。

慣れたら、特に気にならなくなる点かも知れないが、ちょっと気になった

Queryの型が自動生成されないことがある

サーバーを立ち上げていて、Cellファイル内のQUERYを編集したらgraphql.d.tsが新しい内容で自動生成されると思うが、手動でyarn rw g typesを実行しないと生成されない事象が頻繁に発生した。自分の認識違いがあるのかもしれないが、同じファイル内でQUERYのやmutationの定義 → 手動でyarn rw g typesを実行 → また先程のファイルに戻って、生成された型をインポート、というように同一ファイルの編集中にコマンドの実行を挟まなければいけないのが、少し面倒に感じた。

型定義の読み込みがうまく行かないときがある

Fooモデルを作成してyarn rw prisma migrate dev実行後、

src/lib/dbからdbをインポートしdb.fooとすると、プロパティ'foo'は型'PrismaClient<{ log: LogDefinition[]; }, never, false>'に存在しません。ts(2339)というようなエラーが表示される。Prismaの型定義には追加されているが、エディタがキャッシュを読み込んでしまっているようで、node_modules/.prisma/client/index.d.tsを開くと読み込み直してくれるのか、エディタが型を認識してくれるようになる。自分の環境要因かもしれないけど、ちょっとめんどい

rw setup i18nが TypeScript に対応していない

細かい上に、今後改修されるかもしれない話…。

i18nの設定をやってくれるコマンドyarn rw setup i18nというのがあって、これを実行するとreact-i18nextとその関連パッケージのインストール、初期設定ファイルの自動生成までやってくれるのだが、その設定ファイルがTypeScriptプロジェクトでも.jsファイルで作成されてしまう。

その他の自動生成されるファイルについても手作業で更新が必要なものが多く、コマンドの恩恵が弱め。

Railsと比べてどうなのか

そもそも素のRailsとRedwoodは、意識しているところは感じるものの、割と別物だった。

バックエンドで型チェックができる

Rails + RBSとかでも可能なのかもしれないが、まだまだRailsに対応しきれていない。チェックのために型定義ファイルを手動で作らないといけない場合もある。その点、Redwoodでは、DBのSchemaからほとんどの型定義を生成してくれる。エディタの補完なども効くので型があると開発体験も良いなと感じる。

PrismaActiveRecord

ここは単純にDBの操作が置き換わっているというより、概念としても違うものだと感じた。なので、どちらが良いとは一概には言えないのだが、やっぱりActiveRecordは便利だったのだと実感した。DBのテーブルに合わせてクラスが生成されていることが偉大。

これに対して、RedwoodでもRedwoodRecordという概念がある。

RedwoodRecordは、その名の通りRedwood版のActiveRecordで、クラスにバリデーションを定義できたり、ActiveRecordと似たような書き方でレコードの操作が行える。さらに、今後はafterCreateなどのコールバックも追加される予定らしい。

ただ個人的には、DBに関連する操作はService層に集約させるのが良いと思うので、そもそもRedwoodRecordはRedwoodのフレームワーク設計に適さないのではないかと考えている…。

https://redwoodjs.com/docs/redwoodrecord

まとめ

全5回でRedwoodについて書いていったが、割とプロダクション運用を考えられるのではないかと感じた。

前述のi18nのgenerateコマンドで設定されるパッケージがreact-i18nextだったり、今回の記事では取り上げていないが、Redwoodに組み込まれているFormがreact-hook-formの薄いラッパーだったり、基本的にはnpmパッケージなどの既存のエコシステムに任せることで、Redwood独自の書き方をしなければならない部分を極力減らしている点も好感が持てたし、今後の伸びしろも十分にあるフレームワークだと感じた。