管理画面作り
社内のCMS開発経験に基づいた話
NextJSを用いてCMS開発の例として、参考になれば幸いです。(2023-8)
Rendering方式
SPA+CSR
@see NextでのCMS作り所感
ストア(State管理)
管理画面でのState管理は結構シンプルで、場合によって、
QueryClientのCacheをうまく使えば、State管理必須ではありません。
コードの可読性、メンテナンス性やState管理ライブラリの学習コストを配慮し、
適切に入れましょう。
使ったもの:
↑に保存したデータとして:
- ログインしたユーザー情報
- 通信エラー
- 共通コンポーネントに関するデータ
それぞれの特徴
Context | Reactive Variables | Recoil | |
---|---|---|---|
概要 | Reactに内蔵、基本的な機能 | GraphQLを導入する上に、Apollo Clientに内蔵、基本的な機能 | 外部StateManagementライブラリ、機能多様 |
メリット | すぐ使える、ライブラリ不要 | 学習コスト低い、ApolloClientがProviderになり、APIの通信データとの連携しやすい。(自由に操るStateキャッシュというイメージ) | 特化したState管理の外部ライブラリなので、豊かな機能を持ち、関心分離しや、Store管理しやすい |
デメリット | 実質Propsの渡しと同じく、不要なRenderingが発生する | ApolloClientに依存するものの、可読性としてよろしくない。仕様によるQueryClinetの切り替えが困難 | 機能が多い一方、学習コスト高い |
個人なり結論 | ログインユーザー情報など、データの更新によって、ほぼ全てのコンテンツに影響渡すものに使用 | Apollo導入前提でちょっとしたデータの管理にふさわしい、わざわざライブラリ導入までしなくても済む | 複雑なState管理向け、特にComponentの裏側でのデータフローとロジックが重い場合 |
入力(フォーム)
管理画面でのデータ送信として、99%はフォーム経由で送信しているので、結構大事なパーツです。Formライブラリを入れることで、全局のStateと別にForm内に限ったState管理ができ、且つバリデーションの制定がしやすくなります。それに、簡単なUIを持ち、user interactionsができるFormライブラリも存在します。
使ったFormライブラリ:
- Formik
- React Hook Form
比較表:
Formik | React Hook Form | |
---|---|---|
Gzipped bundle size | 44.34KB | 12.12KB |
Dependencies | 7 | 0 |
GitHub stars | 31.6k | 32.2k |
Active maintenance | No | Yes |
Performance | Good | Good |
Documentation | Good | Good |
License | Apache License version 2.0 | MIT |
NPM weekly downloads | 2.1 Million | 2.7 Million |
Pricing | Free | Free |
Community support | Good | Good |
Open GitHub issues | 635 | 3 |
Closed GitHub issues | 1497 | 3528 |
構造:
-
schema機構
- 項目ごと作成
-
couponSchema
userSchema
とか -
APIの引数に合わせる VS 表示に合わせる
- 前者:データ処理が楽になる
- 後者:UI表示が楽になる
- 今まで前者を選んでた
-
- カスタマイズ属性であらゆることができる
- 各入力項目(inputField)ごと
{ name: "client_name", ***//APIと統一、送信時の引数名*** inputType: "TextField", *//描画するコンポネート* label: "クライアント名", //画面上表示する名称 required: "クライアント名は必須です", //必須項目かどうか validates: (v) => v.length <= 50 || "文字数は50文字以内にしてください", *//バリデールール* },
- 項目ごと作成
-
FormGenerator機構
- 各Formタイプの間Input,Confirm,Complete,Errorの切り替え(Store利用)
- 見た目(レーアウト)作り
- Submitイベント渡し
- Form初期値処理
- Schemaに記載したInput Filed情報でFormを生成する
-
inputGenerator機構
- 入力コンポネートmapping
入力Component:
-
汎用コンポネート
- 一般的なInput Field(Text、Number、CheckBox、Radio)
-
特殊コンポネート
- Schemaのある属性に基づく処理を行いたい
- 表示・非表示
- Remoteからのデータをプルダウンで表示
- 汎用コンポネートのカスタマイズ化や結合
- Schemaのある属性に基づく処理を行いたい
-
⚠️コンポネート作りにあたって
- 画像・フィイルアップロード
accept="image/png, image/jpeg, image/jpg”
-
<input>のaccept属性はディフォルトファイル種類しか設定できないため、拡張子チェックはバリデーションとして入れたほうが良さそう
-
同名ファイルの二度目アップロードは認識されないため、onClickに
e.currentTarget.value = ""
というクリア処理が必要。 -
API通信とState管理としてFileタイプは扱える
-
日時入力
- 開始日と終了日が一行表示する場合が多いため、開始日と終了日を**1つコンポネート(datePicker)**としてまとめて、上記のSchemaのInputTypeにおいて、開始日がdatePicker,終了日がInvisble(不可視)という扱いしている
通信(API)
GraphQL と REST ツパターンありますが、cmsにおいて特にパーフォマンスの優先順位そんな高くではないので、どっちを選んでも構いません、BE /BFFのメンバーに任せます。
※(FEのみんなさん、絶対GraphQLでしょう!!!!)
主な特徴↓
GraphQL | REST |
---|---|
一個のendpointで集約 | endpointで機能分け |
client駆動アーキテクチャ | server駆動アーキテクチャ |
type safe、typeドキュメント自動生成 | なし |
GraphQLパターン
ApolloClientを採用している
Apolloの特徴↓
メリット | デメリット |
---|---|
究極のGraphql Client、多機能 | 小規模のPJなら、要らない機能が多く入れられて、パフォマンスが落ちる |
アクティブなコミュニティ、利用者数多い | 多機能の一方、複雑な仕組みになり、学習コスト |
Local State管理(Cache+Reactive Var) | RESTAPIの対応もできるが機能はGraphqlより限られている |
RESTパターン
あらゆるqueryClient(ex ReactQuery or SWR) +Axios
query clientはCache機能やAPIの全般管理+エラーハンドリングを提供してくれる
エラーハンドリング
queryClient(or apolloClient)のAPIで全てのAPI通信エラーを監視し、処理を行う。
特別な処理が必要な場合、各コンポネート内で、エラーを受け取って処理する。
認証
上記のcmsは全てAzureAD利用したSAML認証を採用しており、
Azure経由ログインできたユーザーを自前で作ったDBに入れて管理する。
ユーザー情報として、名前、メールとロールだけになります。
FEにおいての実装はかなりシンプルであり、下記の三つになります。
-
ログイン
下記の処理でログインする。
※青いURLはAzure側で設定する必要がある。
-
ユーザー情報取得
ログインができたとしても、FEとしてユーザーの情報が一切知らないので、
ユーザー情報を取得するAPIを用意してもらう必要がある。
-
ログインガード処理
cmsに初アクセスする際にユーザー情報を取得しにいく
- 取得できない場合(406:未認証)に、ログインページに遷移させる。
or
- ロール(権限)不足の場合、適切なページに遷移させる。
その他に、
ページに長い滞在することもあるので、ユーザー情報取得APIだけではなく、
全てのAPIの認証エラーに対して、上記の青処理を行う。
※ HOC・Providerで処理を行っております。
⚠️注意点
認証エラーに対して、「エラーが起きたら処理する」ではなく、「ユーザー情報無事に取れたらページコンテンツを見せる」です
Discussion