こんにちは!テラーノベルでiOS/Android/Webとフロントエンド周りを担当している @kazutoyoです!
3月に縦型のショートドラマサービス「テラードラマ」を公開しました!
テラードラマは、Web/iOS/Androidのプラットフォームで展開しており、React Nativeで開発しています。
今回はそのテラードラマにおける、React NativeとNext.jsの活用についてお話します。
今回のテラードラマは、モバイルアプリ(iOS/Android)とWebで展開し、機能的にもほぼ同等で提供する必要がありました。
開発するエンジニアも少人数のため、基本的にはクロスプラットフォームで開発ができることが望ましかったです。
さらに、Webに関してはSEOなども意識して、各ページをサーバーサイドレンダリングする必要がありました。
これらの要件を満たす技術スタックとして、React Nativeで開発し、WebをNext.jsでサーバーサイドレンダリングを行うというのが最も良い選択肢だと考えました。
プロジェクト構成は、次のようなMonorepo構成となっています。packages/app/
以下にWebとモバイルアプリで表示する画面を実装し、それをReact Native (apps/expo
)とNext.js(apps/next
)のスクリーンからimportすることで、実装を共通化しています。
Monorepoのディレクトリの構成は次のように行っています。
📦
├─ apps
│ ├─ expo // Expo(React Native)アプリケーション
│ └─ next // Next.jsアプリケーション
├─ packages
│ ├─ app // 各画面や、アプリケーションのロジックなどの実装
│ ├─ api-clients // APIサーバーを呼び出すAPIクライアント
│ ├─ eslint-config // ESLintのルール
│ ├─ components // 画面内で利用するコンポーネント。基本的にロジックや状態を持たないような粒度のもの
│ └─ utilities // ユーティリティ群
└─ modules // Expo Modulesでネイティブの実装を行っているもの
また、テラードラマでは主に次のようなフレームワーク/ライブラリなどを利用しました。
-
Expo SDK 52
- React Nativeのフレームワーク。モバイル用のターゲットに使用
- 一部動作に問題があったため、New Archは無効化している
-
Next.js
- WebでSSRなどを行うためのフレームワーク。Webプラットフォームで使用
-
Turborepo
- Monorepoの管理ツール
-
Tamagui
- Web/React Nativeに対応しているスタイリングとUIコンポーネントライブラリ
-
Expo Router
- React NativeでNext.jsのファイルベースシステムルーティングを行うためのライブラリ
-
Solito
- Next.jsとExpo Routerをナビゲーションを共通化するためのライブラリ
- 実行環境がReact NativeかNext.jsを意識することなく画面遷移をすることができる
- Next.jsとExpo Routerをナビゲーションを共通化するためのライブラリ
-
Storybook
- UIコンポーネントの確認、テスト
-
Firebase (invertase/react-native-firebase)
- Auth/Crashlytics/RemoteConfigなど使用
-
HotUpdater
- クリティカルな不具合に対応するため、OTAアップデートができるように導入
Tamagui スタイリング/UIコンポーネント
今回Tamaguiを選択しました。
次のような条件でいくつか探し、現在のチームで最も適していたのがTamaguiでした。
- WebとNativeの両方に対応していること
- TamaguiはWebへの最適化も行っており、Webでもパフォーマンスが良い
- レスポンシブ機能と、開発工数の削減のためUIコンポーネントも提供されているものを使いたい
- TamaguiはUIコンポーネントの品質もよく出来ていると感じた
- これまでチームでChakra UIやNativeBaseを利用しているので、同じような書き心地がよい
- 多少の違いはあるが、ほぼ変わらない
最近ではNativeWindの勢いもあるので、Tailwindでのスタイリングに慣れている方ならNativeWind+React Native Reusablesも良い選択肢かなと思います。
以前書いた比較記事はこちら
Tamaguiのスタイリング
画面サイズやプラットフォームごとにUIを出し分けたい場合、Tamaguiの $platform-ios
や $sm
のようなプロパティを使うことで、それぞれの環境での指定が可能です。
例えば以下のように実装することが出来ます。
XStack
w="100%"
justifyContent="center"
$platform-web={{
overflow: 'hidden',
}}
$platform-native={{
overflow: 'scroll',
}}
$sm={{
background: 'red',
}}
$gtMd={{
background: 'blue',
}}
{...props}
/>
動画プレイヤー周りの実装や、いくつかのサードパーティSDK、NativeのAPIを呼び出す必要があるものをExpo Modules APIで作成しました。
Expo Modules APIを使うことで、型安全にReact NativeとNative(Web)の層の呼び出しを行うことができ、簡単に各プラットフォームのAPIを呼び出すライブラリが作成できました。
またExpo Modulesを作成する際にContinuous Native Generation (CNG)への対応も行い、今後のExpoへのアップデートを行いやすくするように心がけました。
詳細はこちらの記事をご参照ください。
モバイルアプリをReact Nativeで、WebはNext.js上で動かすことで、iOS/Android/Webの3つのプラットフォームに対応することが出来ました。
体感的に7割はモバイルとWebでコードが共通化出来ているので、かなり開発効率がよく実現できたと感じております。
特にExpo ModulesなどのNative実装以外は全てTypeScriptで実装されているため、少人数でiOS/Android/Webを開発する際の言語のスイッチングコストが減り、ロジックの共通化など大きなメリットがありました。
また、StorybookでのUIコンポーネントの活用やReact NativeのHot Reload機能によって、SwiftUIやJetpack Composeなどネイティブでの開発より高速に開発ができたかなと思います。
Webに関しても、当初懸念していた複雑な設定なしにSSRが問題なく動作したのは、嬉しい驚きでした。
ただ、現状少しずつWebとAppで提供する機能の差分やUIの違いなどが出てきているため、今回のように packages/app/
以下を共通化して画面内で分岐を行うのではなく、ロジックなどを共通化して、Webとアプリでそれぞれを画面単位で実装するように変更しようと考えています。
現在、Expo RouterでRSCやSSRなどの対応が進められていますが、上で述べたようにWebとモバイルの実装を後から分離したいと思ったとき、今回のようにReact Nativeと合わせてNext.jsを利用するのが良いのかなと思います。
それでは良いReact Native開発ライフを!
一緒にテラーノベル/テラードラマを開発してくれる方も募集中です!🤝
こちらの記事はReact Native Meetup #21 ft. menu.incの内容をまとめたものです
Views: 0