はじめに .env.example
を .env
にコピーし、管理者からトークンを受け取って貼り付けてください。
以下で開発サーバーが立ち上がります。URL は https://localhost:3000 です。
npm ci .
npm run dev
ローカルで Static Site Geneation(以下、SSG) して確認する際は、以下でサーバーが立ち上がります。URL は開発サーバと同じ https://localhost:3000 です。
npm run build
npm run start
次に バックエンド をクローンし、以下で開発サーバーを立ち上げます。URLは https://localhost:5432 です。
npm ci .
npm run dev
バックエンドのセットアップが完了すると、クライアントサイドで CMS の内容を取得する箇所が動作します。
バックエンドの開発方法についてここでは触れませんが、開発する場合は適宜 バックエンドのREADME を参照してください。
Vite・Preact・Vike によって SSG した出力を Cloudflare Pages で公開しています。
以下ディレクトリの構造と簡単な説明です。
.
├── README.md
├── dist # ビルドの出力
├── public # 静的ファイル(<url>/<ファイル名>で公開されます)
└── src
├── components # UIコンポーネント
├── hooks # Hooks
├── libs # Hooksに分類されないロジックや辞書など
├── pages # ページコンポーネント
├── renderer # Vike 向けファイル
├── styles # スタイル
├── types # 型
└── vite-env.d.ts
Vike で SSG する際の決まりごとをいくつか説明します。
以下 /src/renderer
の構造です。
.
├── +config.h.ts
├── +onRenderClient.tsx
└── +onRenderHtml.tsx
config.h.ts
は Vike 内の値をアプリケーションで参照するためのものです。
onRenderHtml
はサーバーサイドで実行され、onRenderClient
はクライアントサイドで実行されます。
前者で Server Side Rendering(以下、SSR) し、後者で hydrate
しています。どちらも PageContext
を読み取れるので、コンテキストの内容を初期値として SSR や hydrate したい場合はここで行ってください。
vite build
でこれらの内容が実行され、HTML ファイルとして /dist/client
に書き出されます。
/src/pages
配下にディレクトリを作成し、このディレクトリ配下に +Page.tsx
を配置すると、ディレクトリ名に応じた HTML が生成されます。
例えば /src/pages/foo/+Page.tsx
は /foo/index.html
になります。
@
から始まるディレクトリ名にすると動的に HTML を生成できます。
この際、+Page.tsx
と同階層に +onBeforePrerenderStart.ts
を配置し、以下のような onBeforePrerenderStart
関数で HTML ファイル名に対応する配列を返してください。
export async function onBeforePrerenderStart() {
const res = await fetch("https://example.com");
const data = await data.json();
return data.slugs.map((slug) => `/posts/${slug}`); // e.g. /posts/foo.html /posts/bar.html
}
+Page.tsx
と同階層に +data.ts
を配置し、このファイルに以下のような data
関数を記述すると、サーバーサイドでデータフェッチが実行されます。
import { render } from "vike/abort";
export async function data(pageContext: PageContext) {
const res = await fetch("https://example.com");
const data = await data.json();
return {
title: data.title || "",
description: data.description || "",
};
}
return
した内容は PageContext["data"]
として値が保持されます。+Page.tsx
側で usePageContext
を用いて取得できます。
import { usePageContext } from "~/hooks/usePageContext";
export function Page() {
const context = usePageContext();
return (
<>
<h1>{context.data.title}</h1>
</>
);
}
return
する内容を増減させる場合、/src/types/vike.ts
内の PageContext["data"]
を拡張してください。
declare global {
export namespace Vike {
export interface PageContext {
/** 以下を拡張しましょう */
data?: {
title?: string;
description?: string;
ogImageUrl?: string;
isPrivate?: boolean;
};
// ~~~
}
}
}
エラー時は vike/abort
の render
関数で、ステータスコードとその理由を throw してください。このエラーは /src/pages/_error
で補足されます。
import { render } from "vike/abort";
export async function data(pageContext: PageContext) {
try {
const res = await fetch("https://example.com");
} catch (e) {
throw render(500, `Something went wrong. Detail: ${e.message}`);
}
const data = await data.json();
return {
title: data.title || "",
description: data.description || "",
};
}
このディレクトリには、Clean Architectureの一部を表現したディレクトリが含まれています。
.
├── entities # 表示のための型定義
├── presenters # 表示のためのクラス
├── repositories # データをAPIや外部から取得する関数
└── usecases # ユースケースごとに分かれた関数
データ取得のフローは以下になります。
graph LR
UI[UI]
API[API]
Repository[Repository]
Presenter[Presenter]
Usecase[Usecase]
API -->|Data| Repository
Repository -->|Data| Presenter
Presenter -->|Data| Usecase
Usecase -->|Data| UI
データ更新は現状発生していないので、特にフローはありません。
実装は各ディレクトリ内のファイルを参考にしてください。
Contentful でコンテンツを編集した後のデプロイを GUI で完結させるかつ、誤って公開することを避けるため、GitHub Actions を使用します。
Actions の Continuous Delivery ワークフロー から、 Run Workflow
ボタンを押下します。
ブランチを main
にセットし、ポップアップ内の Run Workflow
を押下すると Cloudflare Pages にデプロイされます。