BlocksとComponentsの違い:ブランド変更に強い設計
ShipAny Nextの設計を解説。翻訳とコンテンツをつなぐ置き換え可能なBlocksと、propsで受け取った内容を描画する再利用可能なComponentsの役割を紹介します。
どのテンプレートも「簡単にカスタマイズできる」とうたいますが、見出しを1つ変えるために十数個のファイルをgrepで探し回ることもあります。ShipAny Nextは、次のルールでこの問題を避けています。
翻訳を読み込むファイルはblock。すべてのコンテンツをpropsで受け取るファイルはcomponentです。
Blocksは置き換えを前提とする
Blocksはsrc/blocks/に置かれる、設定なしで使えるページセクションです。<Hero />、<Pricing />、<Footer />などが該当します。それぞれがi18nメッセージを読み込み、コンテンツの設定を組み立て、コンポーネントに渡します。これらはデモ用の素材であり、実際のプロジェクトを始めるときには削除して、独自のものを書きます。
// src/blocks/header.tsx — a block: reads i18n, wires a component
export async function Header() {
const t = await getTranslations('landing');
const navLinks = [{ href: '/#features', label: t('nav.features') }];
return <SiteHeader navLinks={navLinks} />;
}
Componentsは使い続けられる
Componentsはsrc/components/に置かれ、翻訳を読み込むことはありません。SiteHeader、PricingTable、AppSidebarなど、すべてのコンテンツをpropsで受け取ります。アプリ名、掲載文言、ロケールを知る必要がありません。だからこそ、ブランドを変更しても使い続けられます。
分離することの意味
ブランドを変更するときや、テンプレートから新しいプロジェクトを始めるときは、次のように対応します。
- 残す:
src/components/*— UIの土台です。 - 書き換える:
src/blocks/*— コンテンツをつなぐ部分です。 - 書き換える:Blocksに渡す翻訳のJSONファイルです。
ページファイル自体は小さなままです。page.tsxの役割は、Blocksを積み重ねてページを構成することだけです。ランディングページ全体を変更する場合でも、編集するのはBlocksとJSONであり、基本部品には手を加えません。この分離は見た目の整理ではありません。他者のデザイン上の判断に合わせて格闘することなく、伝えたい内容を書き換えるだけでカスタマイズできるようにするためのものです。