🧗🏼‍♂️

新サービスをNuxt3+ApolloServerで開発してみた

2023/03/07に公開

こんにちは。株式会社ペライチのフロントエンドエンジニアの荒瀬です。

2023 年 1 月末に弊社の新サービス、ペライチなんでもマーケットがリリースされました。

https://mkt.peraichi.com/

こちらのペライチなんでもマーケットは、新たな試みとして既存のペライチのアーキテクチャとは異なる構成でフロントエンドを開発しています。

Nuxt3 を採用したので、その過程や開発してみての所感などを簡単ではありますがフロントエンドを中心にまとめてみました。

構成

  • Nuxt3
  • Apollo Server
  • AWS App Runner
  • (Backend は Rails)

GraphQL クライアントである Apollo は Nuxt3 の外に出してサーバーごと分けています。
この2つの本番環境の構築、デプロイは AWS App Runner で行っています。

APIゲートウェイパターンとしてのApollo Server

Nuxt3 だけでもいわゆる BFF パターンの構築は実現が可能です。
マイクロサービス化している各 API とのやりとりのために、リクエストモジュールが欲しくなりますが Nuxt コミュニティからもさまざまなものが提供されています。

中でも GraphQL クライアントのApolloは RC 版リリースからすぐ Nuxt3 に対応されていたモジュールの 1 つで、簡単に組込み、開発できます。

開発当初はこの方向で検討していました。しかし、ペライチでは各機能のマイクロサービス化を進めており、それは現在も進行中です。

フロントエンドも CakePHP の view だったり、はたまた別サービスの別の Nuxt 環境もあったりします。
ペライチのバックエンドサービスも今後分割されていくことを鑑みて、API エンドポイントが増えて複雑になっていくことが想定されるため、API ゲートウェイに一本化する方針となりました。

このことにより、Apollo Server を採用し、 GraphQL サーバーを新たに用意することで API ゲートウェイの役割を担う構成となりました。

マイクロサービスと結合している部分を徐々に剥がし、フロントエンドのアプリケーションからはマイクロサービスの API を極力気にかけないことを目指しました。 GraphQL でフロントエンドに都合の良いようにデータのやりとりができることを期待できるような構成としました。

Nuxt3で開発してみて

環境構築、設定がめちゃくちゃ簡潔になった

開発環境の構築については Nuxt2 からラクではあったのですが、 Nuxt3 は以下のようなことも気にすることがなくなりました。

  • Auto-imports による plugin, middleware などの読み込み
  • tsconfig の設定
  • ビルドツールの設定

Nuxt3 の目玉機能でもある Auto-imports は、コンポーネントやカスタム関数だけでなく、plugin, middleware 等も自動でインポートしてくれます。

たとえば、Nuxt2 までは nuxt.config.js に 1 つ 1 つ指定する必要があった plugin ですが、Nuxt3 からは不要となっています。

// Nuxt2
export default {
  plugins: [
    '~/plugins/hoge.ts',
    '~/plugins/fuga.ts',
    '~/plugins/piyo.ts',
    ...
  ],
}

// Nuxt3
export default defineNuxtConfig({})

もちろん、vue3 の API や、 Nuxt3 の提供してくれる関数などもすべて自動でインポートしてくれています。

TypeScript が標準サポートされたことにより、自動インポート(+自動型推論)でコードが簡略化されすぎても混乱することがないのは触ってみて実感できました。

ビルドツールもデフォルトでは vite となっており、開発環境の立ち上げがものすごく速いです!

細かくは触れませんが、他にも Nuxt3 の新機能はすばらしいものが多く、 Nuxt2 の開発体験におけるストレスはかなりなくなっていると感じました。

RC版での開発

新サービスリリースに向けて本格的な開発に着手する前の時点では、Nuxt3 はまだ v3.0.0-rc.4 でした。
当時の選択肢としては 2 つありました。

  • Nuxt2 で開発開始。タイミングを見計らって Nuxt Bridge → Nuxt3 と順にアップグレードしていく。
  • Nuxt3 rc で開発開始。正式リリースされ次第、Nuxt3 安定版へアップデートする。

選択肢はありつつも、Nuxt2 → Nuxt Bridge への移行は容易でなく中々重そうな印象だったので、前者は最初から消極的ではありました。

Release Candidate(リリース候補)版での開発を始めるにあたって多少の不安はありました。しかし、ペライチなんでもマーケットのリリーススケジュールと Nuxt3 のロードマップを見比べて、 Nuxt3 の正式リリースが先にくることが期待できそうでした。こういった経緯で、思い切って Nuxt3 から開発を開始することに決めました。

実はペライチなんでもマーケットは β 版を 12 月末にリリースしていて、 Nuxt3 の正式リリースは 2023 年 11 月 16 日。約 1 ヵ月前にバージョンアップを行うという、振り返ると結構なムチャをしたなぁと反省はあります。

当時の Nuxt3 のロードマップによると、正式リリースは2023 Summerとなってました。が、気付いたら2023 Autumnにしれっと変わっていた時は結構焦りました😇
(2023 MidSummerともなっていたらしい)

ペライチでのプロジェクト開始と Nuxt 自体の過渡期が被っていたのもありますが、
このあたりはきちんと考慮しておくべきでした。

GraphQLクライアントの選定

Apollo を独立させたので、 Nuxt 内でも GraphQL クライアントが必要となりました。

Nuxt Apolloを導入することも考えていました。しかし、必要としているものは GraphQL で通信できるとてもシンプルな機能です。Nuxt Apollo では少しオーバースペックで使用しない機能も組み込むことでビルド後のファイル容量を上げてしまうことを懸念して選択肢から外しました。

そこで、シンプルに使えて Nuxt3 に対応している nuxt-graphql-client を導入することとなりました。

https://nuxt-graphql-client.web.app/

nuxt-graphql-client は、Nuxt v3.0.0-rc.4 の時点で公開されていたのも喜ばしいことでした。

Nuxt3 のuseAsyncDataをラップしたuseAsyncGqlというカスタム関数を提供してくれていて、
コンポーネントの読み込みに必要なデータを非同期に取得してくれます。

<script lang="ts" setup>
const { data } = await useAsyncGql('launches', { limit: 5 })
</script>

<template>
  <div>
    <p v-for="(entry, i) of data?.launches" :key="entry.id">
      name: {{ entry.name }}
    </p>
  </div>
</template>

また、読み込ませた schema ファイルから TypeScript の型定義ファイルを自動で出力してくれて、これらも自動インポートされるため、レスポンスデータも型推論されるようになるのも便利です。

SSRとCSRをページによって切り替える

ペライチなんでもマーケットでは、エンドユーザー用のサイトと募集者の管理画面を配信していて、それぞれでドメインが異なります。

エンドユーザー側の画面は SSR を、管理者側の画面を CSR で動作させる必要が出てきたのですが、 Nuxt3 ではルートによってレンダリングモードを切り替えられるようになりました!

https://nuxt.com/docs/guide/concepts/rendering#coming-in-nuxt-3

現時点では、まだパブリックベータ版の機能となっています。
今後、仕様の変更がある可能性はあります。

ハイブリッドレンダリングと呼ばれるレンダリングモードの切り替えは、ルートごとに異なるキャッシュを許可し、サーバーが特定の URL で新しいリクエストに応答する方法を決定しています。

詳しくはこちらを参照ください。
https://nitro.unjs.io/config/#routerules

nitro 側でもまだ実験的な機能となっているようですね。

この機能がリリースされたのは rc.12 ですので、正式リリース目前の段階でした。
ペライチなんでもマーケットでは、いったんこの機能の使用を見送り、layout コンポーネントを使い分けて CSR する画面を指定するようにしています。

いろいろと省略していますがイメージはこのような感じです。

// CSRしたい画面のlayout
<script lang="ts" setup>
const isAuthorized = ref(false)

onMounted(() => {
  ... // 認証処理など
  isAuthorized.value = true
})
</script>

<template>
  <div v-if="isAuthorized">
    <slot />
  </div>
  <div v-else>
    <Loading />
  </div>
</template>

SSR 時は Loading コンポーネントだけをレンダリングさせて、クライアントサイドで認証などの処理が終わってから slot 以下のページコンポーネントを描画させています。

RC 版から開発していたこともあり、この方法で SSR と CSR をする画面を切り分けていました。
無理矢理感は否めないので、ハイブリッドレンダリングを行うように取り組んでいる最中です。

UIフレームワークについて

モーダルやナビゲーションなどの汎用的なコンポーネントを提供している UI フレームワークの導入も検討していました。しかし、RC 版の段階で Nuxt3 の対応がされているものがかなり少なかったのと、対応時期も不明確であったため、このあたりは自前で用意する必要がありました。

Nuxt3 の正式リリース前後では多くの UI フレームワークが Nuxt3 に対応してきているので、今となっては選択肢は多くありそうです。

結局、 TailwindCSS のみを採用して、コンポーネントを作成・管理することとなりました。しかし、あくまでペライチなんでもマーケットの Nuxt 内に配置しているので、ペライチ全体でコンポーネントを共有するという課題が生まれてしまいました。このあたりは今後取り組んでいきたいことの 1 つではあります。

まとめ

ペライチではアーキテクチャを改善している最中ではありますが、新たな試みとして Nuxt3 + ApolloServer (+ App Runner) で新サービスを開発しました。

Nuxt3 も正式リリースされたばかりで、新機能を最大限活かせていないというのも正直あります。
まだまだ改善する点も多いですが、今後もペライチのフロントエンド開発がどう変わっていったかを発信していきたいです。

採用情報

現在エンジニア募集しています!

▼ 採用ページ
https://recruit.peraichi.co.jp/

▼ 選考をご希望の方はこちら(募集職種一覧)
https://hrmos.co/pages/peraichi/jobs?category=1629135637016141824&utm_source=techblog&utm_medium=referral&utm_campaign=article-01gtbkn860grrhat1bxe37ea69

▼ まずはカジュアル面談をご希望の方はこちら
https://hrmos.co/pages/peraichi/jobs/0000029?utm_source=techblog&utm_medium=referral&utm_campaign=article-01gtbkn860grrhat1bxe37ea69

募集中の職種についてご興味がある方は、お気軽にお申し込みください(CTO がお会いします)

ペライチ

Discussion