weaverse-integration について
既存の Hydrogen プロジェクトに Weaverse を導入する開発者向けのスキルです。既存の規約を保ちながら、プロジェクト分析、SDK 設定、コンポーネント変換、ルート移行、検証を段階的に進めます。
主な機能
- 01Hydrogen のバージョンと構成の分析
- 02Weaverse SDK と環境変数の設定
- 03コンポーネントを編集可能なセクションに変換
- 04セクション登録とルート移行
- 05ページの段階的な移行
活用シーン
- 01既存の Hydrogen ストアに Weaverse を導入
- 02販促バナーなどを編集可能なセクションに変換
- 03ホームページや商品ページで段階的に Weaverse を有効化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ weaverse/ shopify-hydrogen-skills --skill weaverse-integrationインストール後、Claude Code で/weaverse-integrationを入力して読み込まれたか確認します。
詳細
Weaverse の統合 — 既存の Hydrogen プロジェクト
目的: 現在 Weaverse を使用していない Hydrogen プロジェクトに Weaverse を統合します。このスキルでは、分析 → SDK のセットアップ → コンポーネントの変換 → ルートの移行 → 検証という全工程を案内します。
重要な原則: 既存のプロジェクトを尊重してください。コーディングスタイル、パターン、規約に合わせます。すでに機能しているものは再構成せず、Weaverse で拡張してください。
ライブドキュメント
このスキルのフォルダーから、次のコマンドを実行してください。ヘルパーは兄弟フォルダーにある
shopify-hydrogen スキルに含まれているため、パック全体がインストールされていれば
../shopify-hydrogen/scripts/ が存在します。
このスキルを単独でインストールした場合、そのフォルダーは存在せず、次のコマンドは
MODULE_NOT_FOUND で失敗します。ヘルパーを一度追加してください:
npx skills add Weaverse/shopify-hydrogen-skills --skill shopify-hydrogen
このスキルには references/ ディレクトリがないため、以下のフェーズがオフラインで参照できる唯一のガイダンスです。ライブドキュメントのコマンドは任意の補足です。
# Always fetch latest docs before making decisions
node ../shopify-hydrogen/scripts/search_weaverse_docs.mjs "existing hydrogen integration"
node ../shopify-hydrogen/scripts/get_weaverse_page.mjs "migration-advanced/existing-hydrogen-integration"
node ../shopify-hydrogen/scripts/search_shopify_docs.mjs "createHydrogenContext"
フェーズ 1:既存のプロジェクトを分析する
コードに手を加える前に、プロジェクトの現在の状態を読み取り、記録してください。
1.1 フレームワークのバージョンを検出する
# Check package.json
cat package.json | grep -E '"react-router"|"@remix-run"|"@shopify/hydrogen"|"@weaverse"'
| 確認できる内容 | インストールする Weaverse のバージョン |
|---|---|
react-router + @shopify/[email protected]+ | @weaverse/hydrogen@latest(v5、React Router v7) |
@remix-run/react | @weaverse/hydrogen@4(v4、Remix) |
プロジェクトが Remix(2025.5.0 より前)を使用している場合:
- まず React Router v7 に移行してから Weaverse v5 を統合するか、ユーザーに確認します
- または、現在の Remix セットアップに Weaverse v4 を統合します
- v7 への移行を推奨してください。こちらが今後の方向性です
1.2 コードベースを一覧化する
次のファイルを読み、パターンを記録します:
| ファイル | 確認する内容 |
|---|---|
package.json | 依存関係、スクリプト、パッケージマネージャー(npm/yarn/pnpm/bun) |
app/root.tsx | レイアウト構造、プロバイダー、グローバルスタイル |
app/entry.server.tsx | CSP のセットアップ、レンダリング方法 |
server.ts(または server/index.ts) | コンテキストの作成、ミドルウェア |
app/routes/** | ルート構造、ローダーパターン、命名規則 |
app/components/** | コンポーネントのパターン、props、スタイリング方法 |
app/sections/** | セクションが存在する場合は、その構成 |
app/styles/** または tailwind.config.* | スタイリング方法(Tailwind、CSS Modules、styled-components など) |
vite.config.ts | ビルドプラグイン、エイリアス |
.env または .env.example | 既存の環境変数(シークレットは読まないでください) |
tsconfig.json | パスエイリアス、厳密性の設定 |
1.3 コーディング規約を記録する
次のパターンを記録し、維持してください:
- コンポーネントのスタイル: 関数宣言、アロー関数、
forwardRefのどれを使用しているか - エクスポートのスタイル:
export default、名前付きエクスポート、export letのどれを使用しているか - スタイリング: Tailwind クラス、CSS Modules、styled-components、インラインスタイル
- 状態管理: フック、コンテキスト、ストア
- データ取得: ローダーパターン、GraphQL クエリの構造、エラー処理
- ファイル名: kebab-case、PascalCase、camelCase
- インポートのスタイル: 絶対パス(
~/)と相対パス、名前空間インポートとデフォルトインポート - TypeScript: 厳密性、interface と type、ジェネリクスの使用方法
- コメント: ドキュメントの詳しさ、JSDoc の使用状況
⚠️ 重要: 変換後の Weaverse コンポーネントは、必ずこれらの規約に合わせてください。プロジェクトが
function宣言を使用している場合は、const X = () =>を使わないでください。Tailwind を使用している場合は、CSS Modules を導入しないでください。
1.4 変換可能なコンポーネントを特定する
Weaverse のセクションとして適したコンポーネントを探します:
適した候補:
- ヒーローバナー/スライダー
- 注目コレクション/商品グリッド
- お客様の声/レビュー
- ニュースレター登録
- プロモーションバナー
- カスタムコンテンツセクション(画像+テキスト、動画など)
- フッターセクション(ニュースレター、ソーシャルリンク)
- コンテンツを編集できるナビゲーションコンポーネント
対象外(変換しない):
- レイアウトの基本要素(Button、Input、Modal。共有コンポーネントとして維持します)
- ルートレベルのラッパー
- カート/チェックアウトのロジックを担うコンポーネント
- 分析/トラッキングのコンポーネント
- サーバーユーティリティ
フェーズ 2:Weaverse SDK のインストールと設定
2.1 パッケージのインストール
# Use whatever package manager the project already uses
# React Router v7 (Hydrogen 2025.5.0+)
npm install @weaverse/hydrogen@latest
# Remix (legacy)
npm install @weaverse/hydrogen@4
2.2 環境変数
.env に追加します。
WEAVERSE_PROJECT_ID="provided-by-user"
WEAVERSE_API_KEY="provided-by-user"
.env.example にも追加し(実際の値は入れず)、TypeScript の環境変数の型を更新します。
// Add to the Env type in env.d.ts or wherever the project defines it
WEAVERSE_PROJECT_ID: string;
WEAVERSE_API_KEY: string;
WEAVERSE_HOST?: string;
2.3 app/weaverse/ ディレクトリの作成
以下の 5 つのファイルを作成します。プロジェクトで既に使われているコードスタイル(エクスポート、命名規則、引用符、セミコロン)に合わせてください。
app/weaverse/schema.server.ts — テーマスキーマ
import type { HydrogenThemeSchema } from "@weaverse/hydrogen";
import pkg from "../../package.json";
export let themeSchema: HydrogenThemeSchema = {
info: {
version: pkg.version,
author: "Your Store Name",
name: "Your Theme Name",
},
settings: [
// Start minimal — add more as you convert components
{
group: "Colors",
inputs: [
{
type: "color",
name: "colorPrimary",
label: "Primary Color",
defaultValue: "#000000",
},
{
type: "color",
name: "colorBackground",
label: "Background Color",
defaultValue: "#ffffff",
},
{
type: "color",
name: "colorText",
label: "Text Color",
defaultValue: "#1a1a1a",
},
],
},
{
group: "Typography",
inputs: [
{
type: "range",
name: "headingBaseSize",
label: "Heading Base Size",
configs: { min: 14, max: 32, step: 1, unit: "px" },
defaultValue: 28,
},
{
type: "range",
name: "bodyBaseSize",
label: "Body Base Size",
configs: { min: 12, max: 20, step: 1, unit: "px" },
defaultValue: 16,
},
],
},
],
};
app/weaverse/style.tsx — グローバルスタイル
プロジェクトの既存のグローバルスタイル(CSS ファイル、Tailwind の設定、ルートレイアウト)を確認し、既存の設定に統合できる CSS 変数を作成します。
import { useThemeSettings } from "@weaverse/hydrogen";
export function GlobalStyle() {
let settings = useThemeSettings();
if (!settings) return null;
return (
<style
id="weaverse-global-style"
key="weaverse-global-style"
suppressHydrationWarning
dangerouslySetInnerHTML={{
__html: `
:root {
--color-primary: ${settings.colorPrimary};
--color-bg: ${settings.colorBackground};
--color-text: ${settings.colorText};
--heading-base: ${settings.headingBaseSize}px;
--body-base: ${settings.bodyBaseSize}px;
}
`,
}}
/>
);
}
app/weaverse/components.ts — コンポーネントレジストリ
import type { HydrogenComponent } from "@weaverse/hydrogen";
// Import converted sections here — start empty, add as you convert
// MUST use namespace imports: import * as X, NOT import X from
export let components: HydrogenComponent[] = [
// Sections will be added during Phase 3
];
app/weaverse/index.tsx — WeaverseContent
import { WeaverseHydrogenRoot } from "@weaverse/hydrogen";
import { components } from "./components";
export function WeaverseContent() {
return (
<WeaverseHydrogenRoot
components={components}
errorComponent={GenericError}
/>
);
}
プロジェクトに既存のエラーコンポーネントがあれば使用し、なければ最小限の GenericError を作成します。
app/weaverse/csp.ts — コンテンツセキュリティポリシー
export function getWeaverseCsp(request: Request, context: any) {
let url = new URL(request.url);
let weaverseHost = context.env?.WEAVERSE_HOST || "https://weaverse.io";
let isDesignMode = url.searchParams.get("weaverse_design_mode") === "true";
let weaverseHosts = [
new URL(weaverseHost).host,
"weaverse.io",
"*.weaverse.io",
"shopify.com",
"*.shopify.com",
"*.myshopify.com",
];
let updatedCsp: Record<string, string[] | string | boolean> = {
frameAncestors: weaverseHosts,
defaultSrc: ["'self'", "data:", ...weaverseHosts],
scriptSrc: ["'self'", "'unsafe-inline'", ...weaverseHosts],
styleSrc: ["'self'", "'unsafe-inline'", ...weaverseHosts],
connectSrc: ["'self'", ...weaverseHosts],
};
if (isDesignMode) {
updatedCsp.frameAncestors = ["*"];
}
return updatedCsp;
}
2.4 サーバーコンテキストの更新
既存のコンテキストファイル(通常は server.ts または app/lib/context.ts)を変更します。
// ADD these imports
import { WeaverseClient } from "@weaverse/hydrogen";
import { themeSchema } from "~/weaverse/schema.server"; // adjust path alias
import { components } from "~/weaverse/components";
// INSIDE createAppLoadContext, after hydrogenContext is created:
return {
...hydrogenContext,
weaverse: new WeaverseClient({
...hydrogenContext,
request,
cache,
themeSchema,
components,
}),
};
コンテキストの作成方法を再構成しないでください。 既存の戻り値オブジェクトに Weaverse クライアントを展開して追加するだけです。
2.5 ルートファイルとエントリーファイルの更新
app/root.tsx — withWeaverse でラップする
import { withWeaverse } from "@weaverse/hydrogen";
import { GlobalStyle } from "~/weaverse/style";
// Keep their existing Layout/App components untouched
// Only change: wrap the default export
// BEFORE:
// export default function App() { ... }
// AFTER:
function App() {
// ... their existing App code, unchanged
}
export default withWeaverse(App);
Layout コンポーネントの <head> 内に <GlobalStyle /> を追加します。
app/entry.server.tsx — Weaverse の CSP を追加する
import { getWeaverseCsp } from "~/weaverse/csp";
// Inside handleRequest, merge Weaverse CSP with existing:
const { nonce, header, NonceProvider } = createContentSecurityPolicy({
...getWeaverseCsp(request, context),
shop: {
checkoutDomain: context.env?.PUBLIC_CHECKOUT_DOMAIN || context.env?.PUBLIC_STORE_DOMAIN,
storeDomain: context.env?.PUBLIC_STORE_DOMAIN,
},
});
既存の CSP 設定とマージしてください。置き換えないでください。
フェーズ 3:既存のコンポーネントを Weaverse セクションに変換する
これは最も重要なフェーズです。ユーザーの既存コンポーネントを、正確な見た目と動作を維持したまま Weaverse で編集可能なセクションに変換します。
3.1 変換方針
変換可能なコンポーネントごとに、以下を行います。
- 元のコンポーネントを読む — props、state、データ取得、スタイルを把握します
- Weaverse ラッパーを作成する — schema と必要に応じて loader を追加します
- 元のレンダリングを維持する — JSX を書き換えず、ラップするだけにします
- components.ts に登録する — 名前空間インポートを追加します
3.2 変換パターン
変換前のコンポーネント:
// app/components/hero-banner.tsx
interface HeroBannerProps {
heading: string;
subtitle: string;
backgroundImage: string;
alignment: "left" | "center";
}
function HeroBanner({ heading, subtitle, backgroundImage, alignment }: HeroBannerProps) {
return (
<section className="relative bg-cover bg-center" style={{ backgroundImage: `url(${backgroundImage})` }}>
<div className={`flex flex-col ${alignment === 'center' ? 'items-center text-center' : 'items-start'}`}>
<h1 className="text-4xl font-bold">{heading}</h1>
<p className="text-xl mt-4">{subtitle}</p>
</div>
</section>
);
}
export default HeroBanner;
変換後のコンポーネント:
// app/sections/hero-banner.tsx (or keep original path, just add schema)
import type { HydrogenComponentProps } from "@weaverse/hydrogen";
import { createSchema } from "@weaverse/hydrogen";
interface HeroBannerProps extends HydrogenComponentProps {
heading: string;
subtitle: string;
backgroundImage: string;
alignment: "left" | "center";
}
function HeroBanner({ heading, subtitle, backgroundImage, alignment, children, ...rest }: HeroBannerProps) {
return (
<section {...rest} className="relative bg-cover bg-center" style={{ backgroundImage: `url(${backgroundImage})` }}>
<div className={`flex flex-col ${alignment === 'center' ? 'items-center text-center' : 'items-start'}`}>
<h1 className="text-4xl font-bold">{heading}</h1>
<p className="text-xl mt-4">{subtitle}</p>
</div>
{children}
</section>
);
}
export default HeroBanner;
export let schema = createSchema({
type: "hero-banner",
title: "Hero Banner",
settings: [
{
group: "Content",
inputs: [
{ type: "text", name: "heading", label: "Heading", defaultValue: "Welcome" },
{ type: "textarea", name: "subtitle", label: "Subtitle" },
{ type: "image", name: "backgroundImage", label: "Background Image" },
{
type: "toggle-group",
name: "alignment",
label: "Alignment",
configs: {
options: [
{ value: "left", label: "Left" },
{ value: "center", label: "Center" },
],
},
defaultValue: "center",
},
],
},
],
presets: {
heading: "Welcome",
alignment: "center",
},
});
主な変更点:
HydrogenComponentPropsを拡張する(children、loaderData、Weaverse の内部情報を追加)- ルート要素で
{...rest}を展開する(Studio との連携に必須) - ネストしたセクションを受け入れられるコンポーネントでは
{children}をレンダリングする createSchema()を使ってschemaをエクスポートする- JSX の構造とスタイルを完全に同じに保つ
3.3 スキーマ設計ルール
変換したコンポーネントのスキーマを作成する場合:
| 元の prop の型 | スキーマの入力型 |
|---|---|
string(短いテキスト) | text |
string(長いテキスト) | textarea または richtext |
string(URL) | url |
string(画像パス) | image |
string(16 進カラーコード) | color |
number | range(適切な min/max/step を設定) |
boolean | switch |
string(列挙型) | select または toggle-group |
| Shopify データを含むオブジェクト | product、collection、blog など |
設定を論理的にグループ化します。 コンポーネントに適した形にし、通常は次のようにします。
- 「コンテンツ」グループ — テキスト、画像、リンク
- 「デザイン」グループ — 色、余白、レイアウトオプション
- 「高度な設定」グループ — 表示設定、カスタム CSS クラス
3.4 データ取得を行うコンポーネントの変換
元のコンポーネントがデータを取得する場合(例:特集コレクション)、データ取得処理を Weaverse loader に変換します。
import type { ComponentLoaderArgs } from "@weaverse/hydrogen";
type SectionData = {
collectionHandle: string;
count: number;
};
export let loader = async ({ weaverse, data }: ComponentLoaderArgs<SectionData>) => {
if (!data?.collectionHandle) return null;
return weaverse.storefront.query(COLLECTION_QUERY, {
variables: { handle: data.collectionHandle, first: data.count ?? 8 },
});
};
プロジェクトで既に使用されている GraphQL クエリとフラグメントを使用し、書き換えないでください。共有クエリを含む graphql/ ディレクトリがある場合は、そこからインポートします。
3.5 変換したコンポーネントの登録
app/weaverse/components.ts を更新します。
import * as HeroBanner from "~/sections/hero-banner";
import * as FeaturedCollection from "~/sections/featured-collection";
// ... other converted components
export let components: HydrogenComponent[] = [
HeroBanner,
FeaturedCollection,
// ...
];
必ず import * as X を使用してください。 import X from は使用しないでください。これは最もよくある間違いです。
フェーズ 4:ルートの更新
Weaverse で編集可能にする各ルートに対して、以下を行います。
4.1 ルートの変換パターン
// BEFORE — original route
import { useLoaderData } from "react-router"; // or "@remix-run/react"
import HeroBanner from "~/components/hero-banner";
import ProductGrid from "~/components/product-grid";
export async function loader({ context, params }: LoaderFunctionArgs) {
const productData = await context.storefront.query(PRODUCT_QUERY, { ... });
return { product: productData.product };
}
export default function Homepage() {
const { product } = useLoaderData<typeof loader>();
return (
<div>
<HeroBanner heading="Sale" subtitle="Big deals" />
<ProductGrid products={product} />
</div>
);
}
// AFTER — Weaverse-enabled route
import { WeaverseContent } from "~/weaverse";
export async function loader({ context, params }: LoaderFunctionArgs) {
// Keep existing data loading
const productData = await context.storefront.query(PRODUCT_QUERY, { ... });
// ADD Weaverse page loading
const weaverseData = await context.weaverse.loadPage({ type: "INDEX" });
return {
product: productData.product,
weaverseData,
};
}
export default function Homepage() {
// Render Weaverse content — it will use the registered components
return <WeaverseContent />;
}
4.2 ページタイプ
| ルート | type の値 |
|---|---|
ホームページ(_index) | "INDEX" |
| 商品ページ | "PRODUCT"(handle: params.productHandle を指定) |
| コレクションページ | "COLLECTION"(handle: params.collectionHandle を指定) |
| コレクション一覧 | "ALL_PRODUCTS" |
| ブログ | "BLOG" |
| 記事 | "ARTICLE"(handle: params.articleHandle を指定) |
| カスタムページ | "PAGE"(handle: params.pageHandle を指定) |
| カスタムテンプレート | "CUSTOM" |
4.3 段階的な移行(推奨)
すべてのルートを一度に変換する必要はありません。次の順に始めてください。
- ホームページ — 影響が最も大きく、通常は最も簡単です
- 商品ページ — マーチャントにとっての価値が高いです
- コレクションページ — ビジュアルマーチャンダイジングが可能になります
- その他のページ — 必要に応じて対応します
まだ変換していないルートは、そのままにしておいてください。Weaverse は Weaverse 以外のルートに干渉しません。
フェーズ 5:エッジケースへの対応
5.1 既存のレイアウトコンポーネント
プロジェクトに共通のレイアウトコンポーネント(ヘッダー、フッター、ナビゲーション)がある場合:
- ヘッダー/フッター — ひとまず Weaverse の外に置き、
root.tsxの Layout でレンダリングします - または、ユーザーが編集可能にしたい場合は、Weaverse コンポーネントに変換します
- どちらの方法を希望するか、ユーザーに確認してください
5.2 共通コンポーネント(ボタン、入力欄など)
プリミティブ/共通コンポーネントは変換しないでください。これらは app/components/ に置いたまま、Weaverse セクション内で使用します。
5.3 サードパーティ連携
プロジェクトで以下を使用している場合:
- アナリティクス(GA4、Segment など)— ルートローダーまたはルートレイアウトに保持します
- A/B テスト — Weaverse のページレンダリングの外に保持します
- カスタムミドルウェア — Weaverse CSP がサードパーティのスクリプトをブロックしないようにします
- CMS データ(Contentful、Sanity など)— 併用できます。Weaverse はビジュアルレイアウトを処理し、外部 CMS は構造化コンテンツを処理します
5.4 TypeScript 型
プロジェクトの型定義に追加します。
// Wherever the project defines AppLoadContext
interface AppLoadContext {
// ... existing properties
weaverse: import("@weaverse/hydrogen").WeaverseClient;
}
フェーズ 6:確認チェックリスト
統合後、次の項目を確認します。
-
npm run devがエラーなしで起動する - 既存のルートが引き続き正しくレンダリングされる(ビジュアルリグレッションチェック)
- ローカル開発 URL で Weaverse Studio のプレビューが読み込まれる
- 変換したコンポーネントが Weaverse Studio のコンポーネントピッカーに表示される
- Studio > Theme > Customize にテーマ設定が表示される
- 変換したコンポーネントが元のコンポーネントと同一にレンダリングされる
- コンポーネントスキーマで適切な編集可能設定が公開される
- データを取得するセクションでデータが正しく読み込まれる
-
npm run buildがエラーなしで完了する - TypeScript が新たなエラーなしでコンパイルされる
- カート、チェックアウト、顧客アカウントの各フローが引き続き機能する
- CSP に関連するコンソールエラーがない
避けるべきよくある間違い
| 間違い | 修正方法 |
|---|---|
import * as X ではなく import X from を使う | コンポーネント登録では必ず名前空間インポートを使います |
ルート要素に {...rest} を付け忘れる | Weaverse Studio のドラッグ&ドロップ操作に必須です |
コンテナコンポーネントで {children} をレンダリングしない | ネストされたセクションに必須です |
| 既存の CSP をマージせずに上書きする | Weaverse CSP を既存の設定に展開してマージします |
| コンポーネントの JSX を「改善するため」に書き換える | 元のレンダリングを正確に保持します |
| すべてのコンポーネントを一度に変換する | まずセクションを変換し、プリミティブは共通コンポーネントのままにします |
スキーマで inspector を使う | settings を使います。inspector は非推奨です |
app/ の外に app/weaverse/ を作成する | app ディレクトリ内に置く必要があります |
| 型定義に環境変数を追加し忘れる | Env 型に WEAVERSE_* を追加します |
クイックリファレンス — ファイル変更の概要
| ファイル | 操作 |
|---|---|
package.json | @weaverse/hydrogen 依存関係を追加 |
.env | WEAVERSE_PROJECT_ID、WEAVERSE_API_KEY を追加 |
app/weaverse/schema.server.ts | 作成 — テーマスキーマ |
app/weaverse/style.tsx | 作成 — グローバルスタイルコンポーネント |
app/weaverse/components.ts | 作成 — コンポーネントレジストリ |
app/weaverse/index.tsx | 作成 — WeaverseContent ラッパー |
app/weaverse/csp.ts | 作成 — CSP 設定 |
server.ts(またはコンテキストファイル) | 変更 — コンテキストに WeaverseClient を追加 |
app/root.tsx | 変更 — withWeaverse でラップし、<GlobalStyle /> を追加 |
app/entry.server.tsx | 変更 — Weaverse CSP を統合 |
app/sections/*.tsx | 作成/変更 — 変換済みコンポーネント |
| ルートファイル | 変更 — weaverse.loadPage() を追加し、<WeaverseContent /> をレンダリング |
| 型定義 | 変更 — WEAVERSE_* 環境変数と weaverse コンテキストを追加 |
.gitignore | 確認 — .react-router/ が無視されていること(RRv7 プロジェクト) |