weaverse-hydrogen

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Weaverse Hydrogen — Agent Skill

Weaverse Hydrogen — Agent Skill

Build Shopify Hydrogen storefronts with Weaverse visual page builder. Docs: https://docs.weaverse.io | GitHub: https://github.com/Weaverse
使用Weaverse可视化页面构建器搭建Shopify Hydrogen店面。 文档:https://docs.weaverse.io | GitHub:https://github.com/Weaverse

Live Documentation

实时文档

For the most up-to-date Weaverse documentation, use these scripts:
  • node scripts/search_weaverse_docs.mjs "<query>"
    — search Weaverse docs
  • node scripts/get_weaverse_page.mjs "<page-path>"
    — fetch a specific page (use paths from search results)
  • Weaverse docs: https://docs.weaverse.io
Examples:
bash
node scripts/search_weaverse_docs.mjs "component schema"
node scripts/search_weaverse_docs.mjs "data fetching"
node scripts/get_weaverse_page.mjs "development-guide/component-schema"
node scripts/get_weaverse_page.mjs "api-reference/weaverse-client"
The reference files below provide offline context but may not reflect the latest changes.

如需获取最新的Weaverse文档,可使用以下脚本:
  • node scripts/search_weaverse_docs.mjs "<query>"
    — 搜索Weaverse文档
  • node scripts/get_weaverse_page.mjs "<page-path>"
    — 获取指定页面内容(使用搜索结果中的路径)
  • Weaverse文档地址:https://docs.weaverse.io
示例:
bash
node scripts/search_weaverse_docs.mjs "component schema"
node scripts/search_weaverse_docs.mjs "data fetching"
node scripts/get_weaverse_page.mjs "development-guide/component-schema"
node scripts/get_weaverse_page.mjs "api-reference/weaverse-client"
下方的参考文件提供了离线上下文,但可能不包含最新变更。

What is Weaverse?

什么是Weaverse?

Weaverse is a visual page builder for Shopify Hydrogen. It lets merchants customize storefronts via a drag-and-drop Studio while developers build type-safe React components with schemas that define the editor UI.
Stack: React 19 · React Router v7 · Shopify Hydrogen · TypeScript · Tailwind CSS · Vite

Weaverse是面向Shopify Hydrogen的可视化页面构建器。商家可以通过拖拽式工作室自定义店面,同时开发者可以借助定义编辑器UI的Schema构建类型安全的React组件。
技术栈: React 19 · React Router v7 · Shopify Hydrogen · TypeScript · Tailwind CSS · Vite

1. Project Structure

1. 项目结构

app/
├── components/        # Reusable UI components
├── graphql/           # GraphQL queries & fragments
├── hooks/             # Custom React hooks
├── routes/            # React Router v7 route files
├── sections/          # Weaverse section components ← YOUR WORK GOES HERE
├── styles/            # Global styles + Tailwind
├── weaverse/
│   ├── components.ts  # Component registry
│   ├── schema.server.ts  # Theme schema (global settings)
│   └── csp.ts         # Content Security Policy for Weaverse
├── entry.client.tsx
├── entry.server.tsx
└── root.tsx           # Wrapped with withWeaverse(App)
server.ts              # WeaverseClient initialization
vite.config.ts
react-router.config.ts
tailwind.config.js
.env

app/
├── components/        # 可复用UI组件
├── graphql/           # GraphQL查询与片段
├── hooks/             # 自定义React hooks
├── routes/            # React Router v7路由文件
├── sections/          # Weaverse区块组件 ← 你的开发代码放在这里
├── styles/            # 全局样式 + Tailwind配置
├── weaverse/
│   ├── components.ts  # 组件注册中心
│   ├── schema.server.ts  # 主题Schema(全局设置)
│   └── csp.ts         # Weaverse的内容安全策略
├── entry.client.tsx
├── entry.server.tsx
└── root.tsx           # 用withWeaverse(App)包裹
server.ts              # WeaverseClient初始化
vite.config.ts
react-router.config.ts
tailwind.config.js
.env

2. Component Anatomy

2. 组件结构

Every Weaverse component has up to 3 exports from a single file (or directory):
tsx
// app/sections/my-section/index.tsx

// 1. Default export — React component
function MySection(props: MySectionProps) { ... }
export default MySection;

// 2. Schema export — editor configuration
export let schema = createSchema({ ... });

// 3. Loader export (optional) — server-side data fetching
export let loader = async (args: ComponentLoaderArgs<DataType>) => { ... };
每个Weaverse组件最多从单个文件(或目录)导出3个部分:
tsx
// app/sections/my-section/index.tsx

// 1. 默认导出 — React组件
function MySection(props: MySectionProps) { ... }
export default MySection;

// 2. Schema导出 — 编辑器配置
export let schema = createSchema({ ... });

// 3. Loader导出(可选) — 服务端数据获取
export let loader = async (args: ComponentLoaderArgs<DataType>) => { ... };

Minimal Example

最简示例

tsx
import { createSchema } from '@weaverse/hydrogen';
import type { HydrogenComponentProps } from '@weaverse/hydrogen';

interface BannerProps extends HydrogenComponentProps {
  heading: string;
  description: string;
}

function Banner({ heading, description, children, ...rest }: BannerProps) {
  return (
    <section {...rest} className="py-16 px-4 text-center">
      <h2 className="text-3xl font-bold">{heading}</h2>
      <p className="mt-4 text-lg text-gray-600">{description}</p>
      {children}
    </section>
  );
}

export default Banner;

export let schema = createSchema({
  type: 'banner',
  title: 'Banner',
  settings: [
    {
      group: 'Content',
      inputs: [
        { type: 'text', name: 'heading', label: 'Heading', defaultValue: 'Hello World' },
        { type: 'textarea', name: 'description', label: 'Description', defaultValue: 'Welcome to our store.' },
      ],
    },
  ],
  presets: {
    heading: 'Hello World',
    description: 'Welcome to our store.',
  },
});
tsx
import { createSchema } from '@weaverse/hydrogen';
import type { HydrogenComponentProps } from '@weaverse/hydrogen';

interface BannerProps extends HydrogenComponentProps {
  heading: string;
  description: string;
}

function Banner({ heading, description, children, ...rest }: BannerProps) {
  return (
    <section {...rest} className="py-16 px-4 text-center">
      <h2 className="text-3xl font-bold">{heading}</h2>
      <p className="mt-4 text-lg text-gray-600">{description}</p>
      {children}
    </section>
  );
}

export default Banner;

export let schema = createSchema({
  type: 'banner',
  title: 'Banner',
  settings: [
    {
      group: 'Content',
      inputs: [
        { type: 'text', name: 'heading', label: 'Heading', defaultValue: 'Hello World' },
        { type: 'textarea', name: 'description', label: 'Description', defaultValue: 'Welcome to our store.' },
      ],
    },
  ],
  presets: {
    heading: 'Hello World',
    description: 'Welcome to our store.',
  },
});

Key Rules

核心规则

  • Spread
    {...rest}
    on the root element — required for Weaverse Studio interaction.
  • Render
    {children}
    if the component accepts child components (
    childTypes
    ).
  • forwardRef
    is optional
    in React 19. If using React 18, wrap with
    forwardRef
    and attach
    ref
    to root element.
  • type
    must be unique
    across all components, use kebab-case (e.g.,
    hero-banner
    ).

  • 在根元素上展开
    {...rest}
    — 这是Weaverse Studio交互的必要条件。
  • 如果组件支持接收子组件(配置了
    childTypes
    ),必须渲染
    {children}
  • forwardRef
    在React 19中是可选的
    ,如果使用React 18,需要用
    forwardRef
    包裹组件并将
    ref
    挂载到根元素上。
  • type
    字段在所有组件中必须唯一
    ,使用短横线命名法(例如
    hero-banner
    )。

3. Component Registration

3. 组件注册

Components must be registered in
app/weaverse/components.ts
:
tsx
import type { HydrogenComponent } from '@weaverse/hydrogen';

// MUST use namespace imports (import * as X), NOT default imports
import * as HeroBanner from '~/sections/hero-banner';
import * as FeaturedCollection from '~/sections/featured-collection';
import * as ProductCard from '~/sections/product-card';

export let components: HydrogenComponent[] = [
  HeroBanner,
  FeaturedCollection,
  ProductCard,
];
Common mistake: Using
import HeroBanner from ...
— this won't work. Always
import * as HeroBanner from ...
.

组件必须在
app/weaverse/components.ts
中注册:
tsx
import type { HydrogenComponent } from '@weaverse/hydrogen';

// 必须使用命名空间导入(import * as X),不能使用默认导入
import * as HeroBanner from '~/sections/hero-banner';
import * as FeaturedCollection from '~/sections/featured-collection';
import * as ProductCard from '~/sections/product-card';

export let components: HydrogenComponent[] = [
  HeroBanner,
  FeaturedCollection,
  ProductCard,
];
常见错误: 使用
import HeroBanner from ...
— 这种写法无法正常工作,始终使用
import * as HeroBanner from ...
的写法。

4. Schema with
createSchema()

4. 使用
createSchema()
定义Schema

tsx
import { createSchema } from '@weaverse/hydrogen';

export let schema = createSchema({
  type: 'my-component',          // Unique kebab-case identifier
  title: 'My Component',         // Display name in Studio
  limit: 1,                      // Max instances per page (optional)
  enabledOn: {                   // Page type restrictions (optional)
    pages: ['PRODUCT', 'COLLECTION'],
  },
  settings: [                    // Editor UI groups
    {
      group: 'Content',
      inputs: [
        { type: 'text', name: 'heading', label: 'Heading', defaultValue: 'Title' },
        { type: 'richtext', name: 'body', label: 'Body' },
        { type: 'image', name: 'image', label: 'Image' },
        {
          type: 'select', name: 'layout', label: 'Layout',
          configs: {
            options: [
              { value: 'grid', label: 'Grid' },
              { value: 'list', label: 'List' },
            ],
          },
          defaultValue: 'grid',
        },
      ],
    },
  ],
  childTypes: ['product-card', 'button'],  // Allowed child component types
  presets: {                     // Defaults when component is added to page
    heading: 'Title',
    layout: 'grid',
    children: [
      { type: 'product-card' },
      { type: 'product-card' },
    ],
  },
});
inspector
is deprecated
— always use
settings
.
Page types for
enabledOn
:
INDEX
,
PRODUCT
,
ALL_PRODUCTS
,
COLLECTION
,
COLLECTION_LIST
,
PAGE
,
BLOG
,
ARTICLE
,
CUSTOM

tsx
import { createSchema } from '@weaverse/hydrogen';

export let schema = createSchema({
  type: 'my-component',          // 唯一的短横线格式标识符
  title: 'My Component',         // 在Studio中显示的名称
  limit: 1,                      // 单页面最大实例数(可选)
  enabledOn: {                   // 页面类型限制(可选)
    pages: ['PRODUCT', 'COLLECTION'],
  },
  settings: [                    // 编辑器UI分组
    {
      group: 'Content',
      inputs: [
        { type: 'text', name: 'heading', label: 'Heading', defaultValue: 'Title' },
        { type: 'richtext', name: 'body', label: 'Body' },
        { type: 'image', name: 'image', label: 'Image' },
        {
          type: 'select', name: 'layout', label: 'Layout',
          configs: {
            options: [
              { value: 'grid', label: 'Grid' },
              { value: 'list', label: 'List' },
            ],
          },
          defaultValue: 'grid',
        },
      ],
    },
  ],
  childTypes: ['product-card', 'button'],  // 允许的子组件类型
  presets: {                     // 组件添加到页面时的默认值
    heading: 'Title',
    layout: 'grid',
    children: [
      { type: 'product-card' },
      { type: 'product-card' },
    ],
  },
});
inspector
已废弃
— 始终使用
settings
enabledOn
支持的页面类型:
INDEX
,
PRODUCT
,
ALL_PRODUCTS
,
COLLECTION
,
COLLECTION_LIST
,
PAGE
,
BLOG
,
ARTICLE
,
CUSTOM

5. Input Types (Quick Reference)

5. 输入类型(快速参考)

TypeReturnsUse For
text
string
Single-line text
textarea
string
Multi-line text
richtext
string
(HTML)
Rich text with formatting
url
string
URLs/links
image
WeaverseImage
object
Image picker from Shopify Files
video
WeaverseVideo
object
Video picker from Shopify Files
color
string
(#hex)
Color picker
range
number
Slider (requires
configs: { min, max, step }
)
switch
boolean
Toggle on/off
select
string
Dropdown (requires
configs: { options }
)
toggle-group
string
Button group (requires
configs: { options }
)
heading
Section header in settings panel (no data)
datepicker
number
(timestamp)
Date/time picker
product
Shopify productProduct picker
collection
Shopify collectionCollection picker
blog
Shopify blogBlog picker
article
Shopify articleArticle picker
metaobject
Shopify metaobjectMetaobject picker
product-list
Shopify products[]Multi-product picker
collection-list
Shopify collections[]Multi-collection picker
→ Full details: references/04-input-settings.md

类型返回值用途
text
string
单行文本
textarea
string
多行文本
richtext
string
(HTML)
带格式的富文本
url
string
URL/链接
image
WeaverseImage
对象
从Shopify文件库选择图片
video
WeaverseVideo
对象
从Shopify文件库选择视频
color
string
(十六进制)
颜色选择器
range
number
滑块(需要配置
configs: { min, max, step }
switch
boolean
开关切换
select
string
下拉选择器(需要配置
configs: { options }
toggle-group
string
按钮组选择(需要配置
configs: { options }
heading
设置面板的区块标题(不存储数据)
datepicker
number
(时间戳)
日期/时间选择器
product
Shopify product商品选择器
collection
Shopify collection商品集合选择器
blog
Shopify blog博客选择器
article
Shopify article文章选择器
metaobject
Shopify metaobject元对象选择器
product-list
Shopify products[]多选商品
collection-list
Shopify collections[]多选商品集合
→ 完整说明:references/04-input-settings.md

6. Data Fetching

6. 数据获取

tsx
import type { ComponentLoaderArgs, HydrogenComponentProps } from '@weaverse/hydrogen';

type MyData = { collectionHandle: string };

export let loader = async ({ weaverse, data }: ComponentLoaderArgs<MyData>) => {
  let { storefront } = weaverse;
  return await storefront.query(COLLECTION_QUERY, {
    variables: { handle: data.collectionHandle },
  });
};

// Derive props type from loader return
type Props = HydrogenComponentProps<Awaited<ReturnType<typeof loader>>> & MyData;

function MyComponent({ loaderData, ...rest }: Props) {
  let collection = loaderData?.collection;
  return <section {...rest}>{collection?.title}</section>;
}
export default MyComponent;
Key patterns:
  • weaverse.storefront.query()
    — Shopify Storefront API
  • weaverse.fetchWithCache(url, options)
    — External APIs with caching
  • Promise.all([...])
    — Parallel fetching
  • shouldRevalidate: true
    on schema inputs that affect the loader
→ Full details: references/05-data-fetching.md

tsx
import type { ComponentLoaderArgs, HydrogenComponentProps } from '@weaverse/hydrogen';

type MyData = { collectionHandle: string };

export let loader = async ({ weaverse, data }: ComponentLoaderArgs<MyData>) => {
  let { storefront } = weaverse;
  return await storefront.query(COLLECTION_QUERY, {
    variables: { handle: data.collectionHandle },
  });
};

// 从loader返回值推导props类型
type Props = HydrogenComponentProps<Awaited<ReturnType<typeof loader>>> & MyData;

function MyComponent({ loaderData, ...rest }: Props) {
  let collection = loaderData?.collection;
  return <section {...rest}>{collection?.title}</section>;
}
export default MyComponent;
核心模式:
  • weaverse.storefront.query()
    — 调用Shopify Storefront API
  • weaverse.fetchWithCache(url, options)
    — 带缓存的外部API请求
  • Promise.all([...])
    — 并行请求
  • 在影响loader的Schema输入项上配置
    shouldRevalidate: true
→ 完整说明:references/05-data-fetching.md

7. Styling & Theming

7. 样式与主题设置

Tailwind CSS is the primary styling approach.
Global theme settings are defined in
app/weaverse/schema.server.ts
and applied via CSS variables:
tsx
// app/components/GlobalStyle.tsx
import { useThemeSettings } from '@weaverse/hydrogen';

export function GlobalStyle() {
  let settings = useThemeSettings();
  if (!settings) return null;
  return (
    <style dangerouslySetInnerHTML={{ __html: `
      :root {
        --color-primary: ${settings.colorPrimary};
        --body-base-size: ${settings.bodyBaseSize}px;
        --heading-base-size: ${settings.headingBaseSize}px;
      }
    `}} />
  );
}
CVA (Class Variance Authority) for component variants:
tsx
import { cva } from 'class-variance-authority';
let buttonVariants = cva('inline-flex items-center rounded font-medium', {
  variants: {
    variant: { primary: 'bg-blue-600 text-white', secondary: 'bg-gray-200' },
    size: { sm: 'h-8 px-3 text-sm', md: 'h-10 px-4', lg: 'h-12 px-6' },
  },
  defaultVariants: { variant: 'primary', size: 'md' },
});
→ Full details: references/06-styling-theming.md

Tailwind CSS是首选的样式方案。
全局主题设置
app/weaverse/schema.server.ts
中定义,并通过CSS变量生效:
tsx
// app/components/GlobalStyle.tsx
import { useThemeSettings } from '@weaverse/hydrogen';

export function GlobalStyle() {
  let settings = useThemeSettings();
  if (!settings) return null;
  return (
    <style dangerouslySetInnerHTML={{ __html: `
      :root {
        --color-primary: ${settings.colorPrimary};
        --body-base-size: ${settings.bodyBaseSize}px;
        --heading-base-size: ${settings.headingBaseSize}px;
      }
    `}} />
  );
}
使用**CVA (Class Variance Authority)**实现组件变体:
tsx
import { cva } from 'class-variance-authority';
let buttonVariants = cva('inline-flex items-center rounded font-medium', {
  variants: {
    variant: { primary: 'bg-blue-600 text-white', secondary: 'bg-gray-200' },
    size: { sm: 'h-8 px-3 text-sm', md: 'h-10 px-4', lg: 'h-12 px-6' },
  },
  defaultVariants: { variant: 'primary', size: 'md' },
});
→ 完整说明:references/06-styling-theming.md

8. Weaverse API (Key Hooks & Utilities)

8. Weaverse API(核心Hook与工具)

APIPurpose
createSchema()
Define component schema with Zod validation
WeaverseClient
Server-side client (initialized in
server.ts
)
weaverse.loadPage({ type, handle })
Load page data in route loaders
weaverse.loadThemeSettings()
Load global theme settings
weaverse.fetchWithCache(url)
Cached external API fetching
withWeaverse(App)
HOC wrapping root
App
in
root.tsx
useWeaverse()
Access global Weaverse instance
useThemeSettings()
Access global theme settings
useItemInstance()
Access a specific component instance
useParentInstance()
Access parent component instance
useChildInstances()
Access child component instances
→ Full details: references/10-weaverse-api.md

API用途
createSchema()
基于Zod验证定义组件Schema
WeaverseClient
服务端客户端(在
server.ts
中初始化)
weaverse.loadPage({ type, handle })
在路由loader中加载页面数据
weaverse.loadThemeSettings()
加载全局主题设置
weaverse.fetchWithCache(url)
带缓存的外部API请求
withWeaverse(App)
包裹
root.tsx
中根
App
的高阶组件
useWeaverse()
获取全局Weaverse实例
useThemeSettings()
获取全局主题设置
useItemInstance()
获取指定组件实例
useParentInstance()
获取父组件实例
useChildInstances()
获取子组件实例
→ 完整说明:references/10-weaverse-api.md

9. Server Setup (server.ts)

9. 服务端配置(server.ts)

tsx
import { WeaverseClient } from '@weaverse/hydrogen';
import { components } from '~/weaverse/components';
import { themeSchema } from '~/weaverse/schema.server';

export async function createAppLoadContext(request, env, executionContext) {
  let hydrogenContext = createHydrogenContext({ env, request, cache, waitUntil, session, /* ... */ });
  return {
    ...hydrogenContext,
    weaverse: new WeaverseClient({
      ...hydrogenContext,
      request,
      cache,
      themeSchema,
      components,
    }),
  };
}

tsx
import { WeaverseClient } from '@weaverse/hydrogen';
import { components } from '~/weaverse/components';
import { themeSchema } from '~/weaverse/schema.server';

export async function createAppLoadContext(request, env, executionContext) {
  let hydrogenContext = createHydrogenContext({ env, request, cache, waitUntil, session, /* ... */ });
  return {
    ...hydrogenContext,
    weaverse: new WeaverseClient({
      ...hydrogenContext,
      request,
      cache,
      themeSchema,
      components,
    }),
  };
}

10. Route Integration

10. 路由集成

tsx
// app/routes/($locale)._index.tsx
import { WeaverseHydrogenRoot } from '@weaverse/hydrogen';

export async function loader({ context }: LoaderFunctionArgs) {
  let weaverseData = await context.weaverse.loadPage({ type: 'INDEX' });
  return { weaverseData };
}

export default function Homepage() {
  return <WeaverseHydrogenRoot />;
}
For product pages:
tsx
export async function loader({ context, params }: LoaderFunctionArgs) {
  let weaverseData = await context.weaverse.loadPage({
    type: 'PRODUCT',
    handle: params.productHandle,
  });
  return { weaverseData, /* other data */ };
}

tsx
// app/routes/($locale)._index.tsx
import { WeaverseHydrogenRoot } from '@weaverse/hydrogen';

export async function loader({ context }: LoaderFunctionArgs) {
  let weaverseData = await context.weaverse.loadPage({ type: 'INDEX' });
  return { weaverseData };
}

export default function Homepage() {
  return <WeaverseHydrogenRoot />;
}
商品页面配置:
tsx
export async function loader({ context, params }: LoaderFunctionArgs) {
  let weaverseData = await context.weaverse.loadPage({
    type: 'PRODUCT',
    handle: params.productHandle,
  });
  return { weaverseData, /* other data */ };
}

Reference Index

参考索引

For detailed information on specific topics, read these reference files:
#FileTopic
01references/01-project-structure.mdProject structure & file anatomy
02references/02-creating-components.mdComponent creation & registration
03references/03-component-schema.mdcreateSchema(), settings, childTypes, presets, enabledOn
04references/04-input-settings.mdAll input types & configurations
05references/05-data-fetching.mdLoaders, Storefront API, caching
06references/06-styling-theming.mdTailwind, theme settings, CVA, CSS variables
07references/07-react-router-7.mdReact Router v7 conventions
08references/08-hydrogen-fundamentals.mdHydrogen framework essentials
09references/09-deployment.mdOxygen, Docker, env vars
10references/10-weaverse-api.mdAll hooks & WeaverseClient API
11references/11-advanced-features.mdLocalization, data connectors, CSP
12references/12-pilot-theme.mdPilot theme patterns & conventions
13references/13-migration-v5.mdRemix → React Router v7 migration
如需特定主题的详细信息,请阅读以下参考文件:
#文件主题
01references/01-project-structure.md项目结构与文件结构
02references/02-creating-components.md组件创建与注册
03references/03-component-schema.mdcreateSchema()、设置、childTypes、预设、可用页面配置
04references/04-input-settings.md所有输入类型与配置
05references/05-data-fetching.md加载器、Storefront API、缓存
06references/06-styling-theming.mdTailwind、主题设置、CVA、CSS变量
07references/07-react-router-7.mdReact Router v7规范
08references/08-hydrogen-fundamentals.mdHydrogen框架基础
09references/09-deployment.mdOxygen、Docker、环境变量
10references/10-weaverse-api.md所有Hook与WeaverseClient API
11references/11-advanced-features.md本地化、数据连接器、CSP
12references/12-pilot-theme.mdPilot主题模式与规范
13references/13-migration-v5.mdRemix → React Router v7迁移

Examples

示例

FileShows
examples/hero-banner.tsxComplete section with schema, settings groups, childTypes, presets
examples/featured-collection.tsxSection with loader, Storefront API query
examples/product-card.tsxChild component example
examples/components-registry.tsRegistration pattern
文件演示内容
examples/hero-banner.tsx完整区块示例,包含Schema、设置分组、childTypes、预设
examples/featured-collection.tsx带loader、Storefront API查询的区块示例
examples/product-card.tsx子组件示例
examples/components-registry.ts组件注册模式