weaverse-hydrogen
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWeaverse 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:
- — search Weaverse docs
node scripts/search_weaverse_docs.mjs "<query>" - — fetch a specific page (use paths from search results)
node scripts/get_weaverse_page.mjs "<page-path>" - 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文档,可使用以下脚本:
- — 搜索Weaverse文档
node scripts/search_weaverse_docs.mjs "<query>" - — 获取指定页面内容(使用搜索结果中的路径)
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
.envapp/
├── 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
.env2. 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 on the root element — required for Weaverse Studio interaction.
{...rest} - Render if the component accepts child components (
{children}).childTypes - is optional in React 19. If using React 18, wrap with
forwardRefand attachforwardRefto root element.ref - must be unique across all components, use kebab-case (e.g.,
type).hero-banner
- 在根元素上展开— 这是Weaverse Studio交互的必要条件。
{...rest} - 如果组件支持接收子组件(配置了),必须渲染
childTypes。{children} - 在React 19中是可选的,如果使用React 18,需要用
forwardRef包裹组件并将forwardRef挂载到根元素上。ref - 字段在所有组件中必须唯一,使用短横线命名法(例如
type)。hero-banner
3. Component Registration
3. 组件注册
Components must be registered in :
app/weaverse/components.tstsx
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 — this won't work. Always .
import HeroBanner from ...import * as HeroBanner from ...组件必须在中注册:
app/weaverse/components.tstsx
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()
createSchema()4. 使用createSchema()
定义Schema
createSchema()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' },
],
},
});inspectorsettingsPage types for : , , , , , , , ,
enabledOnINDEXPRODUCTALL_PRODUCTSCOLLECTIONCOLLECTION_LISTPAGEBLOGARTICLECUSTOMtsx
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' },
],
},
});inspectorsettingsenabledOnINDEXPRODUCTALL_PRODUCTSCOLLECTIONCOLLECTION_LISTPAGEBLOGARTICLECUSTOM5. Input Types (Quick Reference)
5. 输入类型(快速参考)
| Type | Returns | Use For |
|---|---|---|
| | Single-line text |
| | Multi-line text |
| | Rich text with formatting |
| | URLs/links |
| | Image picker from Shopify Files |
| | Video picker from Shopify Files |
| | Color picker |
| | Slider (requires |
| | Toggle on/off |
| | Dropdown (requires |
| | Button group (requires |
| — | Section header in settings panel (no data) |
| | Date/time picker |
| Shopify product | Product picker |
| Shopify collection | Collection picker |
| Shopify blog | Blog picker |
| Shopify article | Article picker |
| Shopify metaobject | Metaobject picker |
| Shopify products[] | Multi-product picker |
| Shopify collections[] | Multi-collection picker |
→ Full details: references/04-input-settings.md
| 类型 | 返回值 | 用途 |
|---|---|---|
| | 单行文本 |
| | 多行文本 |
| | 带格式的富文本 |
| | URL/链接 |
| | 从Shopify文件库选择图片 |
| | 从Shopify文件库选择视频 |
| | 颜色选择器 |
| | 滑块(需要配置 |
| | 开关切换 |
| | 下拉选择器(需要配置 |
| | 按钮组选择(需要配置 |
| — | 设置面板的区块标题(不存储数据) |
| | 日期/时间选择器 |
| Shopify product | 商品选择器 |
| Shopify collection | 商品集合选择器 |
| Shopify blog | 博客选择器 |
| Shopify article | 文章选择器 |
| Shopify metaobject | 元对象选择器 |
| Shopify products[] | 多选商品 |
| 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:
- — Shopify Storefront API
weaverse.storefront.query() - — External APIs with caching
weaverse.fetchWithCache(url, options) - — Parallel fetching
Promise.all([...]) - on schema inputs that affect the loader
shouldRevalidate: true
→ 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;核心模式:
- — 调用Shopify Storefront API
weaverse.storefront.query() - — 带缓存的外部API请求
weaverse.fetchWithCache(url, options) - — 并行请求
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 and applied via CSS variables:
app/weaverse/schema.server.tstsx
// 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是首选的样式方案。
全局主题设置在中定义,并通过CSS变量生效:
app/weaverse/schema.server.tstsx
// 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与工具)
| API | Purpose |
|---|---|
| Define component schema with Zod validation |
| Server-side client (initialized in |
| Load page data in route loaders |
| Load global theme settings |
| Cached external API fetching |
| HOC wrapping root |
| Access global Weaverse instance |
| Access global theme settings |
| Access a specific component instance |
| Access parent component instance |
| Access child component instances |
→ Full details: references/10-weaverse-api.md
| API | 用途 |
|---|---|
| 基于Zod验证定义组件Schema |
| 服务端客户端(在 |
| 在路由loader中加载页面数据 |
| 加载全局主题设置 |
| 带缓存的外部API请求 |
| 包裹 |
| 获取全局Weaverse实例 |
| 获取全局主题设置 |
| 获取指定组件实例 |
| 获取父组件实例 |
| 获取子组件实例 |
→ 完整说明: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:
| # | File | Topic |
|---|---|---|
| 01 | references/01-project-structure.md | Project structure & file anatomy |
| 02 | references/02-creating-components.md | Component creation & registration |
| 03 | references/03-component-schema.md | createSchema(), settings, childTypes, presets, enabledOn |
| 04 | references/04-input-settings.md | All input types & configurations |
| 05 | references/05-data-fetching.md | Loaders, Storefront API, caching |
| 06 | references/06-styling-theming.md | Tailwind, theme settings, CVA, CSS variables |
| 07 | references/07-react-router-7.md | React Router v7 conventions |
| 08 | references/08-hydrogen-fundamentals.md | Hydrogen framework essentials |
| 09 | references/09-deployment.md | Oxygen, Docker, env vars |
| 10 | references/10-weaverse-api.md | All hooks & WeaverseClient API |
| 11 | references/11-advanced-features.md | Localization, data connectors, CSP |
| 12 | references/12-pilot-theme.md | Pilot theme patterns & conventions |
| 13 | references/13-migration-v5.md | Remix → React Router v7 migration |
如需特定主题的详细信息,请阅读以下参考文件:
| # | 文件 | 主题 |
|---|---|---|
| 01 | references/01-project-structure.md | 项目结构与文件结构 |
| 02 | references/02-creating-components.md | 组件创建与注册 |
| 03 | references/03-component-schema.md | createSchema()、设置、childTypes、预设、可用页面配置 |
| 04 | references/04-input-settings.md | 所有输入类型与配置 |
| 05 | references/05-data-fetching.md | 加载器、Storefront API、缓存 |
| 06 | references/06-styling-theming.md | Tailwind、主题设置、CVA、CSS变量 |
| 07 | references/07-react-router-7.md | React Router v7规范 |
| 08 | references/08-hydrogen-fundamentals.md | Hydrogen框架基础 |
| 09 | references/09-deployment.md | Oxygen、Docker、环境变量 |
| 10 | references/10-weaverse-api.md | 所有Hook与WeaverseClient API |
| 11 | references/11-advanced-features.md | 本地化、数据连接器、CSP |
| 12 | references/12-pilot-theme.md | Pilot主题模式与规范 |
| 13 | references/13-migration-v5.md | Remix → React Router v7迁移 |
Examples
示例
| File | Shows |
|---|---|
| examples/hero-banner.tsx | Complete section with schema, settings groups, childTypes, presets |
| examples/featured-collection.tsx | Section with loader, Storefront API query |
| examples/product-card.tsx | Child component example |
| examples/components-registry.ts | Registration pattern |
| 文件 | 演示内容 |
|---|---|
| examples/hero-banner.tsx | 完整区块示例,包含Schema、设置分组、childTypes、预设 |
| examples/featured-collection.tsx | 带loader、Storefront API查询的区块示例 |
| examples/product-card.tsx | 子组件示例 |
| examples/components-registry.ts | 组件注册模式 |