テンプレートの設定
以下のガイドでは、Nodeblocksのフロントエンドフレームワークにおけるテンプレートの定義と設定方法について説明します。
テンプレートとは?
Nodeblocksのフロントエンドフレームワークは、アプリケーション全体にわたるビジネスロジックのさまざまな一般的なコンポーネントを表す標準化されたブロックを提供します。
これらのブロックは、Reactアプリケーション内でそのまま使用することができますが、フレームワークはこれらのブロックを標準化されたアプリケーション構造にまとめる方法も提供しています。この構造を「テンプレート」と呼びます。このテンプレートは、アプリケーションのライフサイクル、レイアウト、ナビゲーション、ルーティング、通知、ログ記録、エラーハンドリングなど、フロントエンドアプリケーションでよく見られる一般的な機能を提供することでアプリケーションを構造化します。
テンプレートはReactコンポーネントではなく、起動時にReactコンポーネントに変換される設定オプションのセットです。これにより、単なるJavaScriptオブジェクトとして簡単にカスタマイズおよび拡張できます。
テンプレート設定
以下は、簡単なテンプレート設定の例です。
import { api } from '@basaldev/blocks-frontend-sdk';
import {
loadDefaultTranslations,
loadTranslationsFromYaml,
Template,
TemplateOpts,
ToastsDisplay,
} from '@basaldev/blocks-frontend-framework';
import { merge } from 'lodash';
interface ExampleDependencies {
/** APIクライアント (実際のコードではロードされたクライアントに置き換える必要があります) */
exampleApiClient: api.ExampleClient;
/** ユーザーセッションを管理するためのサービス */
sessionService: session.SessionService;
}
export class ExampleTemplate implements Template {
opts: Required<TemplateOpts>;
dependencies: ExampleDependencies;
constructor(
opts: TemplateOpts,
dependencies: ExampleDependencies
) {
this.opts = merge<Required<TemplateOpts>, TemplateOpts>(
{
apiErrorHandler: // カスタムエラーハンドラー
appInitialization: [
// 初期化手順
],
appInitializationLoader: // ローディング用コンポーネント
appName: 'example-app',
blockPages: [
// このアプリケーションで表示するページのリスト
{
component: // このページのコンポーネント
name: 'arbitrary.name.for.page',
navigationOptions: {
// このページのナビゲーションオプション (ナビゲーションコンポーネントに渡される)
hideSideNavigation: true,
topBarType: 'noMenu',
},
pageTitle: (t) => 'test', // ページタイトルを設定するためのコールバック
parentBlockPath: 'parent.page', // 階層を設定するための親ページの名前
path: '/example-page', // このページのURLパス
},
...
],
error500Component: // クラッシュ時のエラーブロック
errorMessageI18nHandler: // エラーメッセージの翻訳関数
i18nOptions: {
resources: merge(
loadDefaultTranslations(),
loadTranslationsFromYaml(translationOverrides)
), // アプリケーションのテキストリソース
},
logger: new log.FrontendLogger({
appName: 'example-app',
env: import.meta.env.PROD ? 'production' : 'development',
}),
navigationComponent: // ナビゲーションブロック
notFound404Component: // 404エラーページが見つからない場合のエラーブロック
pageTitleConfiguration: {
appName: 'example-app',
}, // タイトル設定(ページタイトルの設定に使用される)
screenConfiguration: {
desktopCutoff: 950,
enabledSizes: {
bigDesktop: true,
desktop: true,
mobile: true
},
mobileCutoff: 640,
}, // 画面設定
theme: {
// テーマ設定
},
toastConfiguration: {
displayMs: 5000, // トーストメッセージを表示する時間
toastComponent: ToastsDisplay, // トーストを表示するためのコンポーネント
},
},
opts
);
this.dependencies = dependencies;
}
}
技術的には、テンプレートは Template
インターフェースを実装する任意のオブジェクトであればかまいませんが、上記のようにコンストラクタを使用することで、ビルド変数や他のソースからテンプレート設定に依存関係やオーバーライドを簡単に渡すことができます。
TemplateOpts
内の各オプションについて、使用法を説明していきます。
apiErrorHandler
APIリクエストが失敗したときに呼び出される関数です。APIクライアントからのエラーをキャッチし、ユーザーにエラーを表示する代わりに再試行をトリガーすることができます。
一般的には、デフォルトのハンドラを使用することをお勧めします。デフォルトのハンドラは、/refresh-access-token
エンドポイントの401エラーのみを最大2回まで再試行し、ユーザーのセッションが期限切れになった場合にアプリケーションがクラッシュしないようにします。(デフォルトハンドラには authApi
依存関係が必要です。)
appInitialization
アプリケーションが起動してユーザーがページにアクセスする前に実行される関数の配列です。これらの関数が成功しなければ、アプリケーションは表示されません。一般的には、次の関数を含むデフォルトの初期化手順を使用することをお勧めします。
initializeAutoRefreshToken
: この関数は、アプリケーションを使用している間にアクセストークンが期限切れないように、5分ごとに自動的にアクセストークンを更新するタイマーを開始します。
() => initializeAutoRefreshToken(dependencies.authApi, {
refreshIntervalMs: 5 * 60 * 1000,
})
initializeServiceVersionCheckers
: この関数は、APIサービスごとに/ping
チェックを実行し、サービスが稼働していることを確認します。また、バックエンドのバージョンが現在のフロントエンドのバージョンより新しいことを確認し、そうでない場合にはクラッシュします。これにより、古いバックエンドでフロントエンドが動作することを防ぎます。
() => initializeServiceVersionCheckers([
dependencies.authApi,
...
])
この関数は、配列内の各サービスにリクエストを送信するため、起動時間に影響を与える可能性があります。同様に、オフライン状態のサービスを動的に処理する必要があるアプリケーションでは、すべてのサービスがオンラインであることを必須にすべきではありません。本番アプリケーションでは、この初期化チェックを無効にすることを検討してください。
appInitializationLoader
アプリケーションが初期化中に表示されるコンポーネントです。このコンポーネントは、アプリケーションがまだロード中であることをユーザーに示すために、ローディングスピナーなどであるべきです。
appName
アプリケーションの名前です。ロガーや他の開発者向けの場所で、アプリケーションを識別するために使用されます。
blockPages
アプリケーションに表示されるページの配列です。各ページには次のプロパティがあります。
component
: このページに表示されるReactコンポーネントです。通常はブロックコンポーネントを使用しますが、必要に応じてカスタムコンポーネントを使用することもできます。name
: ページの任意の名前で、アプリケーション内の他の部分やブロック間でこのページを参照するために使用されます。navigationOptions
: ナビゲーションコンポーネントのオプションです。サイドナビゲーションを隠したり、トップバーのタイプを変更するなど、さまざまな設定が可能です。デフォルトのナビゲーションコンポーネント固有のオプションを指定できますが、任意のオプションをここで渡して、カスタムナビゲーションコンポーネントで必要に応じて処理することも可能です。pageTitle
: ページタイトルを設定するために呼び出されるコールバック関数です。この関数には翻訳関数が渡され、現在のテキスト設定に基づいてページタイトルを設定することができます。あるいは、fetch
とfallback
オプションを持つオブジェクトを渡して、サーバーからタイトルを動的に取得することも可能です。
{
...,
pageTitle: {
fallback: () => 'Fallback Title while loading or if fetch fails',
fetch: async (blockProps, _t, updatePageTitle) => {
const itemId = blockProps.params.itemId;
if (!itemId) {
return;
}
const item = await dependencies.exampleApi.getItem({
itemId,
});
if (item && item.name) {
updatePageTitle(item.name);
}
},
},
}
-
parentBlockPath
: このページの親ページの名前です。これは、ナビゲーションコンポーネント内でページの階層を設定するために使用されます。 -
path
: このページのURLパスです。このパスはすべてのページで一意である必要があります。ルーティングはReact Routerを使用して行われるため、このパスはReact Routerのパスマッチングと互換性がある必要があります。1ページのみが一致し、後のページが優先されます。最も具体的なページを最後にリストすることを確認してください。 -
validators
: このページが表示される前に呼び出される関数コンポーネントのキー付きオブジェクトです。これらは、ページが表示される前に実行されるメタ動作を可能にするReactコンポーネントラッパーとして構成されています。例えば、ユーザーがログインしているかどうかを確認し、ログインしていない場合はログインページにリダイレクトするために使用することができます。フロントエンドフレームワークは、一般的な使用ケースに対応するデフォルトのバリデーターをいくつか提供しています。
error500Component
アプリケーションがクラッシュしたときに表示されるコンポーネントです。このコンポーネントは、ユーザーにフレンドリーなエラーメッセージを表示し、ページを再読み込みするか、サポートに連絡できるようにします。
errorMessageI18nHandler
APIからのエラーメッセージを翻訳して、ユーザーに表示するフレンドリーメッセージに変換する翻訳関数です。デフォルトの errorMessageI18nHandler
は、APIから返されたエラーのコードに一致する翻訳キーを使用してエラーメッセージを翻訳します。翻訳が見つからない場合、トーストは表示されません。
i18nOptions
フロントエンドフレームワークは、国際化とテキスト管理にi18nextを使用しています。このオプションでは、アプリケーションに必要なi18nextライブラリを設定できます。resources
キーは、YAMLファイルや他のソースからロードされるアプリケーションの翻訳を含むオブジェクトである必要があります。
組織化されたワークフローとして、loadDefaultTranslations
関数を使用してフロントエンドフレームワークが提供するデフォルトの翻訳をロードし、アプリケーションの追加翻訳をオーバーライドYAMLからマージすることをお勧めします。
logger
アプリケーションからのメッセージを記録するために使用されるロガーです。ロガーは log.Logger
インターフェースを実装する必要があります。標準的な方法でメッセージをフォーマットする FrontendLogger
クラスを提供していますが、一般的には、Sentry や LogRocket などのツールを使用して、独自のロガー実装を提供することを期待しています。
navigationComponent
アプリケーションのナビゲーションを表示するために使用されるコンポーネントです。このコンポーネントはアプリのレイアウトを処理し、blockPages
配列で指定されたページを内部にレンダリングします。デフォルトのナビゲーションコンポーネントは、サイドバー、トップバー、およびページコンテンツを持つ標準的なビューです。
ナビゲーションコンポーネントのカスタマイズ方法については、カスタムナビゲーションの作成に関するガイドをご覧ください。
notFound404Component
blockPages
内に存在しないページにユーザーがアクセスしたときに表示されるコンポーネントです。このコンポーネントは、ユーザーにフレンドリーなエラーメッセージを表示し、有効なページに戻れるようにします。
pageTitleConfiguration
ページタイトルを設定するための設定です。この設定は、ナビゲーションコンポーネントがブラウザタブ内のページタイトルを設定するために使用されます。appName
キーはタイトル内にアプリケーション名を設定するために使用され、ページタイトルはこの名前に追加されます。
screenConfiguration
アプリケーションが対応する画面サイズの設定です。現在、フロントエンドフレームワークは3つの画面サイズをサポートしています:bigDesktop
、desktop
、および mobile
。必要に応じてこれらのサイズを有効または無効にし、各サイズのカットオフポイントを設定できます。
無効にされたサイズはアプリケーションによってレンダリングされず、アプリケーションは最後に有効化されたサイズのままになります。例えば、bigDesktop
が無効化されている場合、画面が desktopCutoff
値を超えてもアプリケーションは desktop
サイズのままとなります。
theme
アプリケーションのテーマ設定です。これにより、アプリケーションのデザインシステムで使用されるテーマの上書きや設定が可能です。
参照:テーマのカスタマイズ
toastConfiguration
ユーザーに表示されるトーストメッセージの設定です。displayMs
キーはトーストが表示されてから消えるまでの時間(ミリ秒)を指定し、toastComponent
キーはトーストメッセージを表示するために使用されるコンポーネントを指定します。デフォルトのコンポーネントは、画面上部にメッセージをポップアップで表示する標準的なトーストコンポーネントです。
依存関係
フロントエンドフレームワークのコアコンセプトの1つは、サービスやクライアントをアプリケーション内のさまざまなブロックやコンポーネントに提供するための依存関係注入の使用です。テンプレートコンストラクタに渡される dependencies
オブジェクトには、テンプレートが使用するサービスやクライアントが含まれている必要があります。これらの依存関係は、アプリケーションで使用されるブロック、ユーティリティ、コンポーネントに順次渡されます。
テンプレートが機能するために必須の依存関係は sessionService
のみです。このサービスはアプリケーションのユーザーセッションを管理するために使用されます。このサービスはフロントエンドSDKで提供される session.SessionService
インターフェースを実装している必要があります。
フロントエンドフレームワークのセッション管理の詳細については、セッション管理をご覧ください。
この依存関係以外にも、アプリケーションで使用されるブロックやコンポーネントによって必要とされる依存関係を指定する必要があります。例えば、アプリケーションがプロダクトリストブロックを使用する場合、catalogApi
や api.CatalogApi
インターフェース上の必要なメソッドを実装する他のAPIクライアントを渡す必要があります。
createApp
を使用してテンプレートを作成する
テンプレート設定を作成したら、createApp
関数を使用して、それをReactコンポーネントに変換し、React経由でレンダリングできるようにします。
const sessionService = new session.LocalStorageSessionService();
const exampleApi = new api.ExampleApi(
'https://<example-api-url>',
sessionService
);
const template = new ExampleTemplate(
{},
{
exampleApi,
sessionService,
...
}
);
const appInitializer = createAppInitializer({ template });
const App = createApp({ appInitializer, template });
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
上記では2つのステップがあることに注目してください:createAppInitializer
と createApp
です。createAppInitializer
関数は、アプリケーションの最初の起動時に実行される初期化関数を作成するために使用され、createApp
関数はテンプレートをレンダリングするReactコンポーネントを作成します。
createApp
によって作成された App
は、アプリケーションのルートにレンダリングできますが、必要に応じて他のコンポーネント内にレンダリングすることも可能です。
テンプレートを使用しないでブロックを使用する
テンプレートはアプリケーションを構造化する強力な方法ですが、フロントエンドフレームワークを使用するために必須ではありません。テンプレートを使用せずにブロックを直接Reactアプリケーションで使用することもできます。
ブロックを直接使用する方法については、テンプレートを使用しないでブロックを使用するをご覧ください。