本記事は ドワンゴ Advent Calendar 2024 の25日目の記事です🎄
はじめに
こんにちは。Webフロントエンドチームの山口です。
この度、鋭意開発しておりました、ZEN大学のWebシラバスを公開しました(以降シラバスと表記)。
公開後、多くのポジティブなご反応を頂いており、大変嬉しい限りです。
さて、本記事ではシラバスの技術面に焦点を当て、全体のアーキテクチャとWebフロントエンドの技術構成についてご紹介します。ぜひお付き合いください。
シラバスについて
2025年4月開学の「ZEN大学」の履修科目の概要や科目情報を、誰でも簡単に検索・閲覧できるWebサイトです。 在学生や大学関係者への情報提供はもちろん、入学を検討している学生やその保護者に向けて、ZEN大学の魅力を伝える広報的な役割も担っています。
履修パターンや分野などの多様な条件で科目を検索できるため、自分に合った科目を簡単に見つけることができます。 また、新たな科目との出会いを促す機能として、各科目にはタグや関連科目が設定されています。これにより、履修選択の幅が広がり、個々の目標に合った履修計画を立てやすくなっています。より詳しくは、ぜひお手元でご覧になってみてください。
アーキテクチャ
上図をご覧ください。順を追ってご説明します。
まず、大学の入稿担当者が、Jenkinsの入稿ジョブを通じてシラバス用の入稿データをS3に保存します。入稿データには2種類あり、テキストデータ(CSV)と画像データが存在します。
入稿後、Transformerと呼ばれるデータ変換層によって、入稿データをWebに適したフォーマットへと変換します。(CSV → JSON, 画像 → WebP)。*1
そして、変換後の入稿データをもとにアプリケーションをビルドし、成果物(HTML, CSS, JS, etc...)をS3へ保存、CloudFrontを通じて配信し、最終的にシラバスがWebブラウザ上に表示されます。
そのほか、科目の検索機能のために、検索用のAPIを別途立てています。
検索時はHTTPリクエストをAPIへ送信し、APIはS3上の入稿データ(JSON)をデータソースとして、検索結果を返す構成となっています。
技術構成
Next.js(App Router)
前提として、シラバスには以下の特性があります。
- 静的コンテンツが主。科目の検索機能など、一部に動的コンテンツも存在する
- データ(科目, 教員, タグ, etc...)の更新頻度は低く、ユーザー固有のデータもないため、必要なデータはビルド時点でわかっている
- SEOとパフォーマンスが大事
これらの特性を踏まえ、シラバスではレンダリング手法としてSG(Static Generation)を選択し、その手段として Next.js(App Router)を採用しています。
静的コンテンツは Server Components、動的コンテンツは Client Components としてビルド時にプリレンダリング、Static Exports で静的アセットを出力し、S3に保存、CloudFrontから配信しています。
Panda CSS
Next.js(App Router)では、CSS Modules、Tailwind CSS、CSS in JS など、多様なスタイリング手段をサポートしていますが、シラバスでは Zero Runtime CSS in JS である Panda CSS を採用しています。
Server Components / Client Components をサポートしていることはもちろん、デザイントークン と レスポンシブデザイン をデフォルトでサポートしています。
シラバスでは、カラー、タイポグラフィ、スペーシングなど、デザイントークンを定義しており、デザイントークンベースでUIコンポーネントを開発しています。加えて、レスポンシブデザインの要求もあることから、それらが簡単かつ便利に扱える点は魅力でした。
また、教育事業のWebフロントエンドチームでは CSS in JS の採用が多く、扱いに慣れているメンバーも多いことから、Tailwind CSS などと比較して、キャッチアップコストを抑える目的もあります。
そのほか vanilla-extract なども候補にありましたが、Server Components のサポートに関して、当時 Issue(*2)が報告されていたことなどを含め、採用を見送っています。
今回は Delivery(納期)が重要なプロジェクトであることを踏まえ、極力リスクや開発コストを抑える方向の判断をしていますが、そうでなければ別の選択もあり得たかもしれません。
Radix UI(Primitives)
シラバスでは独自のデザイン要件があることから、スタイルを含まない、いわゆるヘッドレスなUIライブラリを選択しています。UIライブラリにスタイルが含まれている場合、スタイルの上書きやカスタマイズが必要になり、その分の手間と複雑さが発生することを避けるためです。
また、アクセシビリティに正しく配慮したコンポーネントを一から自前で開発するのは大変なため、最低ラインはライブラリに頼りたい...といった動機もあります。
2024年6月のリリースでは、Radix UI(Primitives)の全コンポーネントがRSC互換となりました。
そのほか、提供されているコンポーネントの数と種類、コンポーネント単位で必要なものだけを導入できる点などを含めて検討し、Radix UI(Primitives)を採用しています。
GitHub Actions
基本的なCI/CDの用途はもちろんですが、そのほか、GitHub Pages と組み合わせ、PRごとに独立した動作確認環境を立てる仕組み(ワークフロー)を構築しています。
PRの作成時、またはブランチに変更が加えられたタイミングでワーフクローをトリガーし、ブランチの内容をもとにアプリケーションとStorybookをビルド、成果物をGitHub Pagesにデプロイし、それぞれのURLをPRにコメントとして通知する仕組みです。
URLにはPR番号を含めており、PRごとに独立した環境となっています。最終的にPRをクローズしたタイミングで環境を破棄しています。
PRのレビュー時などにローカルで環境を立ち上げる手間が省けるほか、ローカルに閉じていない環境であるため、URLをデザイナーなどの他チームに共有し、開発中の機能やコンポーネントを確認してもらうといった使い方をしています。
その他
あまり特筆する点がないものについては、簡単に列挙する程度に留めます。
おわりに
さて、ZEN大学のWebシラバスを支える技術と題して、全体のアーキテクチャとWebフロントエンドの技術構成についてご紹介しました。
プロダクトやチームの特性、その時々の状況などにより、適した技術は異なるものですが、少しでもご参考になる部分がありましたら幸いです。
本記事では、バックエンド領域について深く触れませんでしたが、データ変換層(Transformer)に関する記事を過去に公開しています。もしご興味あればご覧ください。
We are Hiring
株式会社ドワンゴの教育事業では、一緒に未来の当たり前の教育をつくるメンバーを募集しています。カジュアル面談も行っています。お気軽にご連絡ください!
開発チームの取り組み、教育事業の今後については、他の記事や採用資料をご覧ください。
*1:シラバスでは画像を多用していることから、WebPを使用してサイズを軽量化する。遅延読み込み(Lazy Loading)を活用するなどの最適化をしています。なお、Next.jsでは、画像最適化の機能を備えた next/image が提供されています。ただし Static Exports 環境下では、そのまま next/image の最適化機能を使用することはできません。この場合、custom image loader を定義する、next/image ではなく自前で最適化するなどの選択肢があります。Next.jsのリポジトリ上でも議論されていますので、ご興味あればご覧になってみてください。
*2:https://github.com/vanilla-extract-css/vanilla-extract/issues/929