Shopify Hydrogen Best Practices
Shopify Hydrogen React Remix Headless Commerce Storefront API SSR Streaming Custom Storefront Oxygen Deploy Performance SEO
| Feature | Hydrogen | Liquid Theme | Next.js + Shopify |
|---|---|---|---|
| Framework | Remix (React) | Liquid Template | Next.js (React) |
| Rendering | SSR + Streaming | Server-side | SSR/SSG/ISR |
| Customization | สูงมาก | จำกัด | สูงมาก |
| Performance | ดีมาก | ดี | ดีมาก |
| Deploy | Oxygen/Cloud | Shopify CDN | Vercel/Cloud |
| ความซับซ้อน | สูง | ต่ำ | สูง |
Hydrogen Setup
# === Shopify Hydrogen Setup ===
# npm create @shopify/hydrogen@latest my-store
# cd my-store
# npm run dev
# .env
# SESSION_SECRET=your-session-secret
# PUBLIC_STOREFRONT_API_TOKEN=your-public-token
# PUBLIC_STORE_DOMAIN=your-store.myshopify.com
# PRIVATE_STOREFRONT_API_TOKEN=your-private-token
# app/root.tsx — Root Layout
# import { Links, Meta, Outlet, Scripts } from '@remix-run/react';
# import { Layout } from '~/components/Layout';
#
# export default function App() {
# return (
#
#
#
#
#
#
#
#
#
#
#
#
#
#
# );
# }
# app/routes/products.$handle.tsx — Product Page
# import { json, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
# import { useLoaderData } from '@remix-run/react';
# import { Image, Money } from '@shopify/hydrogen';
#
# export async function loader({ params, context }: LoaderFunctionArgs) {
# const { handle } = params;
# const { storefront } = context;
#
# const { product } = await storefront.query(PRODUCT_QUERY, {
# variables: { handle },
# cache: storefront.CacheLong(),
# });
#
# if (!product) throw new Response('Not Found', { status: 404 });
# return json({ product });
# }
#
# const PRODUCT_QUERY = `#graphql
# query Product($handle: String!) {
# product(handle: $handle) {
# id
# title
# description
# handle
# priceRange {
# minVariantPrice {
# amount
# currencyCode
# }
# }
# images(first: 10) {
# nodes {
# url
# altText
# width
# height
# }
# }
# variants(first: 50) {
# nodes {
# id
# title
# availableForSale
# price { amount currencyCode }
# }
# }
# }
# }
# `;
from dataclasses import dataclass, field
from typing import List
@dataclass
class HydrogenRoute:
path: str
file: str
cache: str
description: str
routes = [
HydrogenRoute("/", "app/routes/_index.tsx", "CacheShort()", "Homepage"),
HydrogenRoute("/products/:handle", "app/routes/products.$handle.tsx", "CacheLong()", "Product Page"),
HydrogenRoute("/collections/:handle", "app/routes/collections.$handle.tsx", "CacheLong()", "Collection Page"),
HydrogenRoute("/cart", "app/routes/cart.tsx", "CacheNone()", "Cart Page"),
HydrogenRoute("/account", "app/routes/account.tsx", "CacheNone()", "Account Page"),
HydrogenRoute("/search", "app/routes/search.tsx", "CacheShort()", "Search Page"),
]
print("Hydrogen Routes:")
for r in routes:
print(f" {r.path}")
print(f" File: {r.file}")
print(f" Cache: {r.cache} | {r.description}")
Caching Strategy
# === Hydrogen Caching Best Practices ===
# Cache Strategies in Hydrogen
# import { CacheShort, CacheLong, CacheNone, CacheCustom }
# from '@shopify/hydrogen';
#
# // Product pages — long cache (1 hour)
# const { product } = await storefront.query(QUERY, {
# cache: storefront.CacheLong(),
# });
#
# // Homepage — short cache (1 minute)
# const { collections } = await storefront.query(QUERY, {
# cache: storefront.CacheShort(),
# });
#
# // Cart, Account — no cache
# const { cart } = await storefront.query(QUERY, {
# cache: storefront.CacheNone(),
# });
#
# // Custom cache
# const { products } = await storefront.query(QUERY, {
# cache: storefront.CacheCustom({
# mode: 'public',
# maxAge: 60 * 30, // 30 minutes
# staleWhileRevalidate: 60 * 5, // 5 minutes
# }),
# });
# SEO Best Practices
# import { getSeoMeta } from '@shopify/hydrogen';
#
# export const meta = ({ data }) => {
# return getSeoMeta({
# title: data.product.title,
# description: data.product.description,
# url: `https://mystore.com/products/`,
# image: data.product.images.nodes[0]?.url,
# jsonLd: {
# '@type': 'Product',
# name: data.product.title,
# description: data.product.description,
# offers: {
# '@type': 'Offer',
# price: data.product.priceRange.minVariantPrice.amount,
# priceCurrency: 'THB',
# },
# },
# });
# };
cache_strategies = {
"CacheLong()": {
"duration": "1 ชั่วโมง + SWR 23 ชม.",
"use": "Product, Collection, Pages ที่ไม่เปลี่ยนบ่อย",
"example": "Product Detail, Blog Post",
},
"CacheShort()": {
"duration": "1 นาที + SWR 9 นาที",
"use": "Homepage, Search, Listings",
"example": "Homepage, Collection List",
},
"CacheNone()": {
"duration": "ไม่ Cache",
"use": "Cart, Account, Checkout",
"example": "Cart Page, Login",
},
"CacheCustom()": {
"duration": "กำหนดเอง",
"use": "กรณีพิเศษ",
"example": "Flash Sale (5 นาที)",
},
}
print("Hydrogen Cache Strategies:")
for strategy, info in cache_strategies.items():
print(f"\n [{strategy}]")
for k, v in info.items():
print(f" {k}: {v}")
Performance & Deploy
# === Performance & Deployment ===
# Performance Checklist
perf_checklist = {
"Image Optimization": [
"ใช้ component จาก @shopify/hydrogen",
"Lazy Loading สำหรับ Below-the-fold Images",
"WebP Format อัตโนมัติผ่าน Shopify CDN",
"Responsive srcSet สำหรับทุกขนาดหน้าจอ",
],
"Code Splitting": [
"Remix Auto Code Splitting ตาม Route",
"Dynamic Import สำหรับ Heavy Components",
"Prefetch Links ด้วย ",
],
"Caching": [
"CacheLong สำหรับ Static Content",
"CacheShort สำหรับ Dynamic Listings",
"SWR (Stale While Revalidate) ให้ Fast Response",
],
"SEO": [
"Server-Side Rendering ทุกหน้า",
"JSON-LD Structured Data (Product, BreadcrumbList)",
"Canonical URLs, Hreflang Tags",
"Sitemap.xml อัตโนมัติ",
"Meta Tags ครบ Title, Description, OG",
],
}
print("Performance Checklist:")
for category, items in perf_checklist.items():
print(f"\n [{category}]")
for item in items:
print(f" - {item}")
# Deployment Options
deploy_options = {
"Shopify Oxygen": {
"setup": "shopify hydrogen deploy",
"pros": "Integrated, Edge CDN, Free for Plus",
"cons": "Shopify Plus only",
},
"Vercel": {
"setup": "vercel deploy",
"pros": "Edge Functions, Preview Deploys, Analytics",
"cons": "ค่าใช้จ่ายเพิ่มเติม",
},
"Cloudflare Workers": {
"setup": "wrangler deploy",
"pros": "Edge Computing, Low Latency, ถูก",
"cons": "Setup ซับซ้อนกว่า",
},
"Fly.io": {
"setup": "fly deploy",
"pros": "Global Regions, Docker Support",
"cons": "ต้อง Config เอง",
},
}
print(f"\n\nDeployment Options:")
for platform, info in deploy_options.items():
print(f"\n [{platform}]")
for k, v in info.items():
print(f" {k}: {v}")
เคล็ดลับ
- Cache: ใช้ CacheLong สำหรับ Product Pages ลด API Calls
- Image: ใช้ Hydrogen Image Component ไม่ใช่ img tag ธรรมดา
- Prefetch: ใช้ Link prefetch='intent' โหลดหน้าล่วงหน้า
- SEO: ใส่ JSON-LD Product Schema ทุก Product Page
- Analytics: ใช้ Shopify Analytics + Google Analytics 4
Shopify Hydrogen คืออะไร
React Remix Framework Headless Commerce Storefront API SSR Streaming Custom Storefront Oxygen Deploy Shopify
Headless Commerce ต่างจาก Shopify ปกติอย่างไร
Shopify ปกติ Liquid Template จำกัด Headless แยก Frontend Backend API ปรับแต่ง UI อิสระ Performance SEO ดีกว่า ซับซ้อนกว่า
Storefront API คืออะไร
GraphQL API Shopify Frontend Products Collections Cart Checkout Customer Public Access Token Rate Limit 1000 req/s
Oxygen คืออะไร
Shopify Hosting Hydrogen Deploy GitHub Edge CDN Shopify Admin Logs Metrics ฟรี Shopify Plus ไม่ต้อง Setup Infrastructure
สรุป
Shopify Hydrogen React Remix Headless Commerce Storefront API GraphQL SSR Streaming CacheLong CacheShort Image Optimization SEO JSON-LD Oxygen Vercel Cloudflare Deploy Performance
