vtex-io-render-runtime-and-blocks について
VTEX IO のストアフロント開発者向けに、コンポーネントを Store Framework のブロックとして登録する方法を案内するスキルです。インターフェース宣言、React マッピング、構成ルール、メジャーバージョンによる解決を扱い、ブロック欠落の問題を調べられます。
主な機能
- 01interfaces.json でのブロック宣言
- 02ブロックと React コンポーネントの対応付け
- 03構成方式と許可する子ブロックの指定
- 04アプリのメジャーバージョンに基づく解決確認
- 05ランタイム登録とコンポーネント実装の分離
活用シーン
- 01React コンポーネントの Store Framework への公開
- 02テーマから参照するブロックの設定
- 03Missing block 解決エラーの調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vtex/ skills --skill vtex-io-render-runtime-and-blocksインストール後、Claude Code で/vtex-io-render-runtime-and-blocksを入力して読み込まれたか確認します。
詳細
レンダリングランタイムとブロック登録
このスキルを使用する場面
VTEX IO ストアフロントのコンポーネントを、ブロックとして Store Framework に公開する必要がある場合にこのスキルを使用します。
store/interfaces.jsonへのコンポーネントの登録- ブロック名と React コンポーネントのマッピング
- ブロックの構成と許可される子要素の定義
- コンポーネントがテーマ JSON に正しく接続されているかの確認
次の場合はこのスキルを使用しないでください。
- ショッパー向けコンポーネントの内部実装
- 管理インターフェース
- バックエンドサービスやルートの設計
- ポリシーのモデリング
判断ルール
- Store Framework に表示されるすべてのブロックは、
store/interfaces.jsonに登録する必要があります。 - ブロック名、コンポーネントのマッピング、構成は明示してください。
store/interfaces.jsonのキーとして使われるブロック ID(例:product-reviews)は、ストアフロントのテーマがstore/*.jsonのblocks内で参照する ID と同じです。componentフィールドは、ProductReviewsのようなreact/配下の React エントリー名、またはアプリの構成が階層的な場合はproduct/ProductReviewsのようなネストされたパスにマッピングしてください。- ブロックに明示的な子要素モデルが必要な場合は、意図をもって
compositionを使用してください。childrenは、コンポーネントがprops.childrenを通じてネストされたブロックをレンダリングすることを意味し、blocksは、Store Framework が制御する名前付きブロックスロットをブロックが公開することを意味します。 compositionは省略可能です。多くのシンプルなブロックでは、componentと、必要に応じてallowedを宣言すれば十分です。- ブロック ID のスコープは、宣言元アプリの MAJOR バージョンです。
vtex.pages-graphqlは、ワークスペースに実際にインストールされているメジャーバージョンに対して、acme-related-productsなどのブロック参照を[email protected]:acme-related-productsとして解決します。ID が同じでも、0.xで宣言されたブロックと5.xで宣言されたブロックは別のブロックです。 store/blocks.jsonを通じてブロック ID を参照するコンシューマーテーマからブロックが参照できるのは、宣言元アプリが依存関係のバージョン範囲と一致するメジャーバージョンでインストールされている場合のみです。不一致があると、リゾルバーでMissing block [email protected]:block-idエラーが発生し、ページが正常に動作しなくなります。- このスキルはレンダリング/ランタイムの契約に使用し、コンポーネントの実装自体にはストアフロント/管理向けスキルを使用してください。
厳守すべき制約
制約:ストアフロントのブロックは interfaces.json で宣言する必要があります
Store Framework で使用する React コンポーネントには、対応する interfaces.json エントリーを必ず用意してください。
重要な理由
インターフェースの宣言がなければ、テーマ JSON からコンポーネントを参照できません。
検出方法
ストアフロントの React コンポーネントをブロックとして使用する予定なのに、対応するインターフェースエントリーがない場合は、作業を中断して、まずエントリーを追加してください。
正しい例
{
"product-reviews": {
"component": "ProductReviews"
}
}
誤った例
// react/ProductReviews.tsx exists with no interfaces.json mapping
制約:コンポーネントのマッピングは実在する React エントリーファイルに解決される必要があります
interfaces.json の component フィールドは、実際にエクスポートされている React エントリーファイルに必ずマッピングしてください。
重要な理由
マッピングが壊れていると、ブロックの契約と実装との接続が気づかれないまま失われます。
検出方法
インターフェースが、対応する React エントリーファイルのないコンポーネント名を参照している場合は、作業を中断してマッピングを修正してください。
正しい例
{
"product-reviews": {
"component": "ProductReviews"
}
}
誤った例
{
"product-reviews": {
"component": "MissingComponent"
}
}
制約:ブロック ID は、宣言元アプリのインストール済みメジャーバージョンで解決できる必要があります
テーマアプリの store/blocks.json から参照されるブロック ID は、コンシューマーの依存範囲とメジャーバージョンが一致するインストール済みアプリの interfaces.json エントリーに解決できなければなりません。レンダリング時のリゾルバーは、ブロック ID 単体ではなく、[email protected]:block-id をキーにします。
重要な理由
vtex.pages-graphql は、ブロックの検索時に宣言元アプリのメジャーバージョンを使用します。[email protected] に存在するブロックは、ブロック ID が同じでも、[email protected] に解決するコンシューマーからは参照できません。不一致があると GraphQL 層で Missing block エラーが返され、ページはデフォルトコンテンツにフォールバックするか、完全に失敗します。
検出
コンシューマーテーマがブロック ID を参照していて、宣言元アプリのインストール済みメジャーバージョンがコンシューマーの依存範囲と一致しない場合は、処理を停止し、依存範囲を合わせるか、ブロック宣言を正しいメジャーバージョンに移動してください。
正しい例
// consumer theme manifest.json
{ "dependencies": { "acme.product-widgets": "0.x" } }
// [email protected] ships store/interfaces.json with:
{ "acme-related-products": { "component": "RelatedProducts" } }
// consumer theme store/blocks.json
{ "store.product": { "children": ["acme-related-products"] } }
誤った例
// consumer theme depends on [email protected]
// but the block "acme-related-products" was added in @5.x and never backported
{ "store.product": { "children": ["acme-related-products"] } }
リゾルバーは Missing block [email protected]:acme-related-products を返します。
制約:ブロックのコンポジションは意図的に定義する必要があります
コンポジションと許可される子ブロックは、コンポーネントの実際のレイアウトおよびランタイムでの想定に一致していなければなりません。
重要な理由
コンポジションのコントラクトが正しくないと、テーマでの利用が壊れやすく、わかりにくくなります。
検出
allowed または composition が、コンポーネントが子要素を受け取る方法を反映していない場合は、処理を停止し、ブロックのコントラクトを修正してください。
正しい例
{
"product-reviews": {
"component": "ProductReviews",
"composition": "children",
"allowed": ["product-review-item"]
}
}
誤った例
{
"product-reviews": {
"component": "ProductReviews",
"composition": "blocks",
"allowed": []
}
}
推奨パターン
interfaces.json でブロックのコントラクトを明示し、ブロックの実装に関する事項をレンダリングランタイムの登録から分離してください。
ブロックの最小限のライフサイクル:
// store/interfaces.json
{
"product-reviews": {
"component": "ProductReviews",
"composition": "children",
"allowed": ["product-review-item"]
},
"product-review-item": {
"component": "ProductReviewItem"
}
}
// store/home.json
{
"store.home": {
"blocks": ["product-reviews"]
}
}
// react/ProductReviews.tsx
export default function ProductReviews() {
return <div>...</div>
}
この配線により、ブロック名がテーマから参照可能になり、実際の React エントリーにマッピングされ、レンダリングランタイムの境界でコンポジションルールが明示されます。
よくある失敗
- ストアフロントコンポーネントをブロックとして登録し忘れる。
- ブロック名を、存在しない React エントリーファイルにマッピングする。
- 誤ったコンポジションモデルを使用する。
5.x系統に新しいブロックを追加し、0.xに依存するコンシューマーからも参照できると思い込む。ブロックの可視性は、宣言元アプリのインストール済みメジャーバージョンの範囲内に限られます。- すでにそのブロックを参照しているコンシューマーテーマと調整せずにブロック ID の名前を変更する。この変更は、保存済みコンテンツに対する破壊的変更に相当します。
レビューチェックリスト
- ブロックは
interfaces.jsonで宣言されていますか? - コンポーネントのマッピングは正しく解決されますか?
- コンポジションと許可される子要素は意図的に定義されていますか?
- ランタイムの登録はコンポーネントの内部実装から明確に分離されていますか?
- 宣言元アプリは、すべてのコンシューマーの依存範囲と一致するメジャーバージョンでインストールされていますか?
関連スキル
vtex-io-storefront-theme-app— コンシューマーテーマでこれらのブロックをページやルートに組み込む方法が質問の内容である場合に使用します。vtex-io-storefront-theme-versioning— ブロックを宣言するアプリのメジャーバージョン変更が、保存済みコンテンツでそれらのブロックをすでに参照しているマーチャントに及ぼす影響が質問の内容である場合に使用します。
参考資料
- Store Framework - ブロックとテーマのコンテキスト
- Interfaces —
interfaces.jsonがブロック ID を React コンポーネントにマッピングする方法と、ブロック ID がアプリのメジャーバージョンごとに名前空間化される方法。