Weaverse Hydrogen Tutorial
Welcome to this step-by-step guide on setting up a Weaverse Hydrogen project using the pre-made "Pilot" theme. Aimed at providing a hands-on experience, this tutorial is structured to guide you from installation through to deployment, ensuring you're ready to launch your Shopify store with a custom theme. Whether you're coding along or just browsing, expect to spend about 20 minutes on this guide.
Prerequisites
This tutorial is built for developers with a foundational understanding of several key technologies. If you're unfamiliar with any of the following, please refer to the provided links before proceeding:
- React
- Remix
- Shopify Hydrogen
- Shopify Theme Architecture
- TailwindCSS
- TypeScript
- Shopify Storefront API
Installation Steps
Install Weaverse App
Weaverse can be installed directly from the Shopify App Store. After installation, access it from your Shopify Admin Dashboard. Install Weaverse App
Create a New Project
With Weaverse installed, create a new project by selecting the "Create Project" button. By default, the Pilot theme is selected. Follow the on-screen instructions to finalize the project setup.
Theme Editor Exploration
After project creation, dive into the theme editor to customize your theme, from adding new sections and blocks to previewing changes in real-time.
Setup Local Development
To kickstart your local development with the Weaverse Hydrogen project, there are several methods to clone or set up the project on your local machine. Here's how you can proceed with the Pilot theme, available at: Pilot Theme GitHub Repository.
Method 1: Using Weaverse CLI
The Weaverse CLI simplifies the setup process by configuring the project directly in your workspace.
- Install Weaverse CLI: Execute the following command in your terminal:
Replace
npx @weaverse/cli@latest create --template=pilot --project-id=<your-project-id> --project-name=<your-project-name>
<your-project-id>
and<your-project-name>
with your project's actual ID and name. This will set up the Pilot theme in the specified directory.
Method 2: Cloning from GitHub
Directly cloning the GitHub repository allows you to work with the latest version of the Pilot theme.
- Clone Repository: Use the clone command to copy the Pilot theme repository to your local machine.
Substitute
git clone https://github.com/weaverse/pilot.git <your-project-name>
<your-project-name>
with the desired name for your project directory.
Method 3: Downloading and Extracting ZIP
For those who prefer not to use Git, downloading the project as a ZIP file is a straightforward alternative.
- Download ZIP: Navigate to the Pilot theme's GitHub page and click the "Code" dropdown button, then select "Download ZIP".
- Extract Files: After downloading, extract the ZIP file into your preferred project location.
Method 4: Using GitHub as a Template
GitHub's repository template feature offers an easy way to create a new repository based on the Pilot theme.
- Generate from Template: Visit the Pilot theme's GitHub page and click the "Use this template" button. Follow GitHub's prompts to create a new repository.
- Clone Your New Repository: Once your repository is set up, clone it to your local machine:
Replace
git clone <your-new-repository-url>
<your-new-repository-url>
with the URL of your newly created repository.
Next Steps for Local Development Setup
After selecting one of the setup methods for your project, follow these steps to get your local development environment ready, ensuring to properly configure environment variables for a smooth workflow:
- Navigate to Your Project Directory:
- Switch to your project's directory with:
cd <your-project-name>
- Setting Up Environment Variables:
-
Create a
.env
file in the root of your project directory. -
Install Headless or Hydrogen (paid store only) app on your Shopify store to obtain necessary API keys and tokens. Learn more
-
Populate the
.env
file with necessary environment variables. Here are examples for both the demo setup and a setup with real store data. -
If you already got a store with Hydrogen app installed, you can pull the ENV with this command:
npx shopify hydrogen env pull
For a demo setup using
mock.shop
:SESSION_SECRET="your-randomly-generated-secret"PUBLIC_STORE_DOMAIN="mock.shop"WEAVERSE_PROJECT_ID="your-weaverse-project-id"
For a setup with real store data:
SESSION_SECRET="your-randomly-generated-secret"PUBLIC_STOREFRONT_API_TOKEN="your-public-storefront-api-token"PUBLIC_STORE_DOMAIN="your-store.myshopify.com"WEAVERSE_PROJECT_ID="your-weaverse-project-id"PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID="your-customer-account-api-client-id"PUBLIC_CUSTOMER_ACCOUNT_API_URL="https://your-shopify-store.myshopify.com/api/2022-01/graphql" ### Optional:#PRIVATE_STOREFRONT_API_TOKEN="your-private-storefront-api-token" # Optional#PUBLIC_STOREFRONT_API_VERSION="unstable" # Optional, defaults to Hydrogen's version#WEAVERSE_API_KEY="your-weaverse-api-key" # Optional#WEAVERSE_HOST="https://studio.weaverse.io" # Optional, defaults to Weaverse's studio URL
-
📌 Important: To safeguard sensitive information, do not commit the
.env
file to version control. Instead, use an.env.example
file to share the structure of environment variables without revealing the actual values.
- Install Dependencies:
- Run the following command to install all required dependencies for your project:
npm install
- Start the Development Server:
- With dependencies installed, launch your local development server:
npm run dev
- Your project will now be accessible at
http://localhost:3456
, allowing you to view and interact with it in real-time.
- Update Weaverse Preview URL:
- In Weaverse Studio, update the Project Preview URL to
http://localhost:3456
to preview your local development changes within the Weaverse environment.
Learning and Customizing the Pilot Theme
The Pilot theme serves as a fully functional base for your Shopify Hydrogen store, complete with necessary components and structures for quick customization.
Project Structure Overview
Your project structure will include several directories and files crucial for theme customization, notably within the app/weaverse
and app/sections
folders.
🌳 <root>├── 📁 app│ ├── 📁 ...│ ├── 📁 components│ ├── 📁 data│ ├── 📁 graphql│ ├── 📁 hooks│ ├── 📁 libs│ ├── 📁 routes│ ├── 📁 sections│ ├── 📁 styles│ ├── 📁 weaverse│ │ └── 📄 components.ts│ │ └── 📄 create-weaverse.server.ts│ │ └── 📄 index.tsx│ │ └── 📄 schema.server.ts│ │ └── 📄 style.tsx│ ├── 📄 entry.client.tsx│ ├── 📄 entry.server.tsx│ └── 📄 root.tsx├── 📁 public│ └── 📄 favicon.svg├── 📄 .editorconfig├── 📄 .env├── 📄 package.json├── 📄 remix.config.js├── 📄 remix.env.d.ts├── 📄 server.ts├── 📄 sync-project.md└── 📄 tailwind.config.js└── 📄 ...
Adding Customizable Sections
Creating customizable sections enriches the user experience. Let's add a new section called UserProfiles
to display user profiles, utilizing Shopify's Metaobject for data storage.
Implementing UserProfiles
- Create
UserProfiles
Section: Inapp/sections
, create auser-profiles
folder and add anindex.tsx
file. Implement theUserCard
component from the provided code snippet (which I found from V0.dev).
const UserCard = () => { return ( <div className="border bg-card text-card-foreground rounded-lg overflow-hidden shadow-lg max-w-sm mx-auto hover:shadow-xl transition-all duration-200" data-v0-t="card" > <img alt="Profile picture" className="object-cover w-full" height="320" src="https://cdn.shopify.com/s/files/1/0728/0410/6547/files/medium_3.webp?v=1702346343" style={{ aspectRatio: '320/320', objectFit: 'cover' }} width="320" /> <div className="p-4"> <h2 className="text-2xl font-bold hover:text-gray-700 transition-all duration-200"> Emily Johnson </h2> <h3 className="text-gray-500 hover:text-gray-600 transition-all duration-200"> Front-end Developer </h3> <p className="mt-2 text-gray-600 hover:text-gray-700 transition-all duration-200"> Passionate about creating interactive user interfaces. </p> <div className="flex mt-4 space-x-2"> <button className="inline-flex items-center justify-center whitespace-nowrap text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground h-9 rounded-md px-3 w-full hover:bg-gray-700 hover:text-white transition-all duration-200"> Follow </button> <button className="inline-flex items-center justify-center whitespace-nowrap text-sm font-medium ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent h-9 rounded-md px-3 w-full hover:border-gray-700 hover:text-gray-700 transition-all duration-200"> Message </button> </div> </div> </div> )}
- Define
UserProfiles
Component: Incorporate theUserCard
component withinUserProfiles
, exporting it as the default component.
interface UserProfilesProps extends HydrogenComponentProps {}const UserProfiles = forwardRef<HTMLDivElement, UserProfilesProps>( (props, ref) => { return ( <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 p-4"> <UserCard /> </div> ) },)
export default UserProfiles
- Schema Definition: Define a basic schema for
UserProfiles
to ensure proper rendering and integration with the Weaverse theme editor.
export const schema: HydrogenComponentSchema = { title: 'User Profiles', type: 'user-profiles', inspector: [],}
- Registration: Register
UserProfiles
inapp/weaverse/components.ts
for it to appear in the Weaverse Studio, enabling its addition to pages.
import * as UserProfiles from '~/sections/user-profiles'
export let components: HydrogenComponent[] = [ // ...other components UserProfiles,]
Upon completion, you should be able to add and preview the UserProfiles
section within Weaverse Studio, marking the beginning of your theme's customization journey.
Next Steps: Defining Shopify MetaObject
Shopify MetaObjects offer a powerful way to add custom data to your Shopify store, enabling you to store additional information beyond the standard fields provided by Shopify. This feature is particularly useful for themes and apps that require custom data fields for products, customers, and other resources.
Creating a MetaObject for User Profiles
To incorporate custom data for user profiles in your Weaverse Hydrogen project, you need to define a MetaObject in Shopify Admin. Here's how to set up a UserProfile
MetaObject:
- Navigate to Shopify Admin: Access your store's admin panel and go to
Settings
>Custom data
. - Add a MetaObject Definition:
- In the "Metaobject definitions" section, click "Add definition".
- Enter a definition name, such as
UserProfile
, to start creating your custom data structure.
- Define Fields for UserProfile:
name
(Single line text): The user's full name.avatar
(File): Choose the File type and accept only image file types for the user's avatar.role
(Single line text): The user's role or position.description
(Multiple line text): A detailed bio or user description.
- Save and Apply Changes: After defining the fields, save the MetaObject definition and apply it to your store.
Adding Sample Entries to UserProfile MetaObject
-
Access Shopify Admin: Go to
Settings
>Custom data
. -
Find MetaObjects: Click on
MetaObjects
, then select yourUserProfile
definition. -
Add Sample Entry:
- Click “Add entry”.
- Fill in the fields:
Name
,Avatar
(image file),Role
, andDescription
.
-
Save Entry: Ensure each entry is saved.
-
Repeat: Add more entries to test various data presentations.
Querying the UserProfile MetaObject
To leverage the custom data stored in UserProfile MetaObjects within your Shopify store, you'll need to craft a GraphQL query that fetches this data from the Shopify Storefront API. The query and its implementation are outlined below:
Fetching MetaObject Data
Add the following query to your app/data/queries.ts
file to retrieve MetaObject data. This query is designed to fetch a specific type of MetaObject, including details such as key, type, value, and any associated media images.
// app/data/queries.ts
export const METAOBJECTS_QUERY = `#graphql query MetaObjects($type: String!, $first: Int) { metaobjects(type: $type, first: $first) { nodes { fields { key type value reference { ... on MediaImage { alt image { altText url width height } } } } handle id type } } }`
This query has been added to app/data/queries.ts
in the Weaverse Pilot theme repository for your reference.
Implementing the Loader Function
Next, define a metaobject picker input and a loader function within your component to utilize this query. This example demonstrates how to set up the loader function in app/sections/user-profiles/index.tsx
:
// app/sections/user-profiles/index.tsx
export let schema: HydrogenComponentSchema = { type: 'meta-demo', title: 'Metaobject Demo', toolbar: ['general-settings', ['duplicate', 'delete']], inspector: [ { group: 'Metaobject Demo', inputs: [ { label: 'Select metaobject definition', type: 'metaobject', name: 'metaObjectData', shouldRevalidate: true, }, { label: 'Items per row', name: 'itemsPerRow', type: 'range', configs: { min: 1, max: 10, defaultValue: 3, }, }, ], }, ],}
export let loader = async (args: ComponentLoaderArgs<UserProfilesProps>) => { let { weaverse, data } = args let { storefront } = weaverse if (!data?.metaObjectData) { return null } let { metaobjects } = await storefront.query(METAOBJECTS_QUERY, { variables: { type: data.metaObjectData.type, first: 10, }, }) return { userProfiles: metaobjects.nodes, }}
The shouldRevalidate
property in the metaobject input ensures the page revalidates, allowing the loader function to fetch new data whenever a different metaobject definition is selected.
The loader function returns a userProfiles
object containing the fetched MetaObject data, making it accessible through props.loaderData
in your component for rendering user profiles.
Finishing the UserProfiles Section
It's time to finalize the UserProfiles
section. Update your code with the following snippet in the app/sections/user-profiles/index.tsx
file:
// app/sections/user-profiles/index.tsx
import { Image } from '@shopify/hydrogen'import type { ComponentLoaderArgs, HydrogenComponentProps, HydrogenComponentSchema,} from '@weaverse/hydrogen'import { Button } from '~/components'import { METAOBJECTS_QUERY } from '~/data/queries'import clsx from 'clsx'import { forwardRef } from 'react'
const UserCard = ({ user }: { user: any }) => { let { fields } = user let image = fields.find((field: any) => field.key === 'avatar') let imageData = image?.reference?.image let name = fields.find((field: any) => field.key === 'name')?.value let role = fields.find((field: any) => field.key === 'role')?.value let description = fields.find( (field: any) => field.key === 'description', )?.value return ( <div className="flex flex-col gap-2 items-center border bg-card text-card-foreground rounded-lg overflow-hidden shadow-lg max-w-sm mx-auto hover:shadow-xl transition-all duration-200" data-v0-t="card" > <Image className="object-cover w-full" data={imageData} style={{ aspectRatio: '320/320', objectFit: 'contain' }} /> <div className="p-4"> <h2 className="text-2xl font-bold hover:text-gray-700 transition-all duration-200"> {name} </h2> <h3 className="text-gray-500 hover:text-gray-600 transition-all duration-200"> {role} </h3> <p className="mt-2 text-gray-600 hover:text-gray-700 transition-all duration-200"> {description} </p> <div className="flex mt-4 space-x-2"> <Button>Follow</Button> <Button variant={'secondary'}>Message</Button> </div> </div> </div> )}
interface UserProfilesProps extends HydrogenComponentProps { metaObjectData: { id: string type: string } itemsPerRow: number}
const UserProfiles = forwardRef<HTMLDivElement, UserProfilesProps>( (props, ref) => { let { loaderData, metaObjectData, itemsPerRow, className, ...rest } = props if (!metaObjectData) { return ( <section className={clsx( 'w-full px-6 py-12 md:py-24 lg:py-32 bg-amber-50 mx-auto', className, )} ref={ref} {...rest} > <p className="text-center">Please select a metaobject definition</p> </section> ) } return ( <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 p-4" ref={ref} {...rest} > <div className="grid w-fit mx-auto" style={{ gridTemplateColumns: `repeat(${itemsPerRow}, minmax(0, 1fr))`, gap: '16rem', }} > {loaderData?.userProfiles.map((user: any) => { return <UserCard key={user.id} user={user} /> })} </div> </div> ) },)
The updated UserProfiles
component utilizes data fetched by the loader function. This data is passed from the loaderData
prop and used to render individual UserCard
components for each user profile, displaying the user's name, role, description, and avatar.
To preview the user profiles within Weaverse Studio:
- Navigate back to Weaverse Studio.
- Add the
UserProfiles
section to your page. - Select the
UserProfile
MetaObject definition to display the profiles.
Conclusion
You now have the essential skills to set up a Weaverse Hydrogen project using the Pilot theme, customize sections, and utilize MetaObjects for sophisticated data management. Here are some resources to further expand your expertise: