SiamCafe.net Blog
Technology

Shopify Hydrogen Home Lab Setup สร้าง Custom Storefront บนเครองตวเอง

shopify hydrogen home lab setup
Shopify Hydrogen Home Lab Setup | SiamCafe Blog
2025-07-04· อ. บอม — SiamCafe.net· 1,027 คำ

Shopify Hydrogen ?????????????????????

Shopify Hydrogen ???????????? React-based framework ????????????????????????????????? custom storefronts ???????????????????????????????????? Shopify backend ???????????? Storefront API ????????? Remix ???????????? foundation ????????? SSR (Server-Side Rendering) ????????? streaming ??????????????? storefront ????????????????????? ??????????????? built-in commerce components ?????????????????? cart, product, collection

Home Lab Setup ????????????????????? ????????????????????? development environment ???????????????????????????????????????????????????????????? local server ?????????????????? develop ????????? test Hydrogen storefronts ?????????????????????????????????????????? cloud services ????????????????????????????????????????????????????????????????????? development ????????????????????????????????????????????????????????? ??????????????????????????????????????????????????????

Hydrogen ????????????????????????????????? Brands ?????????????????????????????? custom storefront ?????????????????????????????? Liquid themes, Headless commerce ?????????????????????????????? performance ?????????, Multi-channel selling ????????? Shopify backend ????????? frontend ?????????????????????????????????, Progressive Web Apps (PWA) ?????????????????? mobile-first experience

????????????????????? Hydrogen Development Environment

Setup local development ?????????????????? Hydrogen

# === Hydrogen Development Setup ===

# 1. Prerequisites
node --version  # Node.js 18+
npm --version   # npm 9+

# 2. Create Hydrogen Project
npm create @shopify/hydrogen@latest -- \
  --template demo-store \
  --language ts

cd hydrogen-store

# 3. Project Structure
cat > project-structure.txt << 'EOF'
hydrogen-store/
  app/
    components/
      cart/
        CartLineItem.tsx
        CartSummary.tsx
      product/
        ProductCard.tsx
        ProductGallery.tsx
        ProductForm.tsx
      layout/
        Header.tsx
        Footer.tsx
        Layout.tsx
    routes/
      ($locale)._index.tsx        # Homepage
      ($locale).products.$handle.tsx  # Product page
      ($locale).collections.$handle.tsx  # Collection page
      ($locale).cart.tsx           # Cart page
      ($locale).account.tsx        # Account page
    lib/
      shopify.ts                  # Shopify client config
      utils.ts                    # Helper utilities
    styles/
      app.css                     # Global styles
      tailwind.css                # Tailwind imports
  public/
    favicon.ico
  .env                            # Environment variables
  remix.config.js
  tailwind.config.js
  package.json
EOF

# 4. Environment Configuration
cat > .env << 'EOF'
# Shopify Store Connection
SESSION_SECRET="your-session-secret"
PUBLIC_STOREFRONT_API_TOKEN="your-storefront-api-token"
PUBLIC_STORE_DOMAIN="your-store.myshopify.com"
PRIVATE_STOREFRONT_API_TOKEN="your-private-token"

# Development
PUBLIC_STOREFRONT_API_VERSION="2024-04"
EOF

# 5. Install Dependencies
npm install
npm install @shopify/hydrogen @shopify/cli
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

# 6. Start Development Server
npm run dev
# Opens at http://localhost:3000

echo "Hydrogen development environment ready"

??????????????? Custom Storefront

Hydrogen components ?????????????????? e-commerce

// === Custom Storefront Components ===

// File: app/routes/($locale).products.$handle.tsx
import { json, type LoaderFunctionArgs } from '@shopify/remix-oxygen';
import { useLoaderData } from '@remix-run/react';
import { Image, Money, ShopPayButton } 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 },
  });

  if (!product) throw new Response('Not Found', { status: 404 });
  return json({ product });
}

export default function ProductPage() {
  const { product } = useLoaderData<typeof loader>();
  const selectedVariant = product.variants.nodes[0];

  return (
    <div className="max-w-7xl mx-auto px-4 py-8">
      <div className="grid md:grid-cols-2 gap-8">
        {/* Product Gallery */}
        <div className="space-y-4">
          {product.images.nodes.map((image: any) => (
            <Image
              key={image.id}
              data={image}
              sizes="(min-width: 768px) 50vw, 100vw"
              className="rounded-lg"
            />
          ))}
        </div>

        {/* Product Info */}
        <div className="space-y-6">
          <h1 className="text-3xl font-bold">{product.title}</h1>
          <div className="text-2xl">
            <Money data={selectedVariant.price} />
          </div>
          <div dangerouslySetInnerHTML={{ __html: product.descriptionHtml }} />
          <AddToCartButton variantId={selectedVariant.id} />
          <ShopPayButton
            variantIds={[selectedVariant.id]}
            storeDomain={product.shop?.primaryDomain?.url || ''}
          />
        </div>
      </div>
    </div>
  );
}

function AddToCartButton({ variantId }: { variantId: string }) {
  return (
    <form method="post" action="/cart">
      <input type="hidden" name="variantId" value={variantId} />
      <button
        type="submit"
        className="w-full bg-black text-white py-3 px-6 rounded-lg hover:bg-gray-800 transition"
      >
        Add to Cart
      </button>
    </form>
  );
}

const PRODUCT_QUERY = `#graphql
  query Product($handle: String!) {
    product(handle: $handle) {
      id
      title
      handle
      descriptionHtml
      images(first: 10) {
        nodes {
          id
          url
          altText
          width
          height
        }
      }
      variants(first: 10) {
        nodes {
          id
          title
          availableForSale
          price {
            amount
            currencyCode
          }
          compareAtPrice {
            amount
            currencyCode
          }
        }
      }
    }
  }
`;

Home Lab Infrastructure

????????????????????? home lab ?????????????????? development

# === Home Lab Infrastructure ===

# 1. Docker Compose for Full Development Stack
cat > docker-compose.dev.yml << 'EOF'
version: '3.8'
services:
  # Hydrogen Dev Server
  hydrogen:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
    env_file:
      - .env

  # Mock Shopify API (for offline development)
  mock-api:
    image: mockoon/cli:latest
    ports:
      - "3001:3001"
    volumes:
      - ./mock/shopify-api.json:/data/shopify-api.json
    command: --data /data/shopify-api.json --port 3001

  # Redis (Session storage)
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  # Nginx (Reverse proxy + caching)
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/certs:/etc/nginx/certs
    depends_on:
      - hydrogen
EOF

# 2. Dockerfile for Development
cat > Dockerfile.dev << 'EOF'
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
EOF

# 3. Nginx Configuration
cat > nginx/nginx.conf << 'EOF'
events { worker_connections 1024; }

http {
    upstream hydrogen {
        server hydrogen:3000;
    }

    # Cache configuration
    proxy_cache_path /tmp/nginx-cache levels=1:2
        keys_zone=hydrogen_cache:10m max_size=1g inactive=60m;

    server {
        listen 80;
        server_name localhost;

        # Static assets caching
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
            proxy_pass http://hydrogen;
            proxy_cache hydrogen_cache;
            proxy_cache_valid 200 1d;
            add_header X-Cache-Status $upstream_cache_status;
            expires 1y;
        }

        # Dynamic pages
        location / {
            proxy_pass http://hydrogen;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}
EOF

# 4. Home Lab Hardware Recommendations
cat > lab-specs.yaml << 'EOF'
home_lab_specs:
  minimum:
    cpu: "4 cores (Intel i5 / AMD Ryzen 5)"
    ram: "8GB"
    storage: "256GB SSD"
    network: "1Gbps"
    os: "Ubuntu 22.04 / macOS"
    
  recommended:
    cpu: "8 cores (Intel i7 / AMD Ryzen 7)"
    ram: "16GB"
    storage: "512GB NVMe SSD"
    network: "1Gbps + WiFi 6"
    os: "Ubuntu 22.04"
    extras: ["Docker Desktop", "VS Code", "Shopify CLI"]
    
  power_user:
    option_1: "Mini PC (Intel NUC / Beelink)"
    option_2: "Raspberry Pi 5 (8GB) for lightweight testing"
    option_3: "Old laptop as dedicated dev server"
    cloud_hybrid: "Use Cloudflare Tunnel for external access"
EOF

echo "Home lab infrastructure configured"

Performance Optimization

Optimize Hydrogen storefront performance

#!/usr/bin/env python3
# performance_audit.py ??? Hydrogen Performance Audit
import json
import logging
from typing import Dict, List

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("perf")

class HydrogenPerformanceAudit:
    def __init__(self):
        pass
    
    def optimization_checklist(self):
        return {
            "server_side": {
                "streaming_ssr": {
                    "description": "????????? Remix streaming ?????????????????? above-the-fold content",
                    "impact": "?????? TTFB 40-60%",
                    "code": "defer() ?????????????????? non-critical data",
                },
                "cache_strategy": {
                    "description": "Cache API responses ???????????? Shopify cache headers",
                    "impact": "?????? API calls 80%",
                    "headers": "Cache-Control: public, max-age=3600, stale-while-revalidate=86400",
                },
                "query_optimization": {
                    "description": "Request ??????????????? fields ??????????????????????????????????????? Storefront API",
                    "impact": "?????? response size 50%+",
                },
            },
            "client_side": {
                "image_optimization": {
                    "description": "????????? Shopify CDN + responsive images",
                    "impact": "?????? image load 60%",
                    "component": " component with sizes prop",
                },
                "code_splitting": {
                    "description": "Remix auto code-splits per route",
                    "impact": "?????? initial JS 40%",
                },
                "prefetching": {
                    "description": "Prefetch links on hover/viewport",
                    "impact": "Instant page transitions",
                    "code": "",
                },
            },
            "infrastructure": {
                "edge_deployment": {
                    "description": "Deploy to Oxygen (Shopify) ???????????? Cloudflare Workers",
                    "impact": "?????? latency 50-70% (edge computing)",
                },
                "cdn_caching": {
                    "description": "CDN cache ?????????????????? static assets",
                    "impact": "?????? origin requests 90%",
                },
            },
        }
    
    def core_web_vitals_targets(self):
        return {
            "LCP": {"target": "< 2.5s", "hydrogen_typical": "1.2-1.8s"},
            "FID": {"target": "< 100ms", "hydrogen_typical": "< 50ms"},
            "CLS": {"target": "< 0.1", "hydrogen_typical": "< 0.05"},
            "TTFB": {"target": "< 800ms", "hydrogen_typical": "200-500ms (edge)"},
        }

audit = HydrogenPerformanceAudit()
checklist = audit.optimization_checklist()
print("Performance Optimization Checklist:")
for area, items in checklist.items():
    print(f"\n  {area}:")
    for name, info in items.items():
        print(f"    {name}: {info['impact']}")

cwv = audit.core_web_vitals_targets()
print("\nCore Web Vitals Targets:")
for metric, data in cwv.items():
    print(f"  {metric}: Target {data['target']}, Hydrogen {data['hydrogen_typical']}")

Deployment ????????? CI/CD

Deploy Hydrogen storefront

# === Deployment & CI/CD ===

# 1. Shopify Oxygen Deployment
cat > shopify-deploy.sh << 'BASH'
#!/bin/bash
# Deploy to Shopify Oxygen
npx shopify hydrogen deploy

# Or link to store
npx shopify hydrogen link --storefront your-store
npx shopify hydrogen deploy --env production
BASH

# 2. Cloudflare Pages Deployment
cat > wrangler.toml << 'EOF'
name = "hydrogen-store"
compatibility_date = "2024-04-01"

[site]
bucket = "./dist/client"

[[routes]]
pattern = "shop.example.com/*"
zone_name = "example.com"
EOF

# 3. GitHub Actions CI/CD
cat > .github/workflows/deploy.yml << 'EOF'
name: Deploy Hydrogen

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npm run typecheck
      - run: npm run lint
      - run: npm test

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npm run build
      
      - name: Deploy to Oxygen
        uses: shopify/oxygenctl-action@v4
        with:
          oxygen_deployment_token: }
          build_command: "npm run build"
EOF

# 4. Production Dockerfile
cat > Dockerfile << 'EOF'
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
EXPOSE 3000
CMD ["npm", "start"]
EOF

echo "Deployment configured"

FAQ ??????????????????????????????????????????

Q: Hydrogen ????????? Liquid themes ???????????????????????????????????????????

A: Liquid themes ???????????? Shopify's built-in template language render ???????????? server ????????? Shopify customize ???????????? theme editor ???????????? ????????????????????? deploy ????????? ????????????????????????????????? stores ???????????????????????? Hydrogen ???????????? React framework ??????????????? custom storefront ???????????????????????????????????? ????????? Storefront API ??????????????????????????? deploy ?????????????????? Shopify (Oxygen, Vercel, Cloudflare) ?????????????????????????????? ????????????????????? custom UX ????????? Liquid ????????????????????????, ????????????????????? performance ?????????????????? (edge SSR), ????????????????????? headless architecture 80% ????????? Shopify stores ????????? Liquid themes ????????????????????? ??????????????? Hydrogen ????????????????????? dev team ?????????????????????????????? custom experience ???????????????

Q: Home lab ??????????????????????????? ????????? cloud ????????????????????????????

A: Home lab ??????????????????????????? ????????? cloud ?????????????????? ?????????????????????????????? ????????? ???????????????????????? hosting ????????????????????? development, ???????????? ??????????????????????????? deploy ??????????????? local ????????????????????????, Offline ???????????????????????????????????????????????? internet (????????? mock API), ???????????????????????? infrastructure ?????????????????? Docker, Nginx, caching ????????????????????? ???????????? setup ?????????, ??????????????? edge computing testing, Shopify API ???????????? internet ?????????????????? beginner ????????? npm run dev ?????? laptop ????????????????????? ????????????????????? home lab ?????????????????? serious development ????????? Docker Compose + mock API ???????????? test offline

Q: Shopify Oxygen ????????? Vercel ??????????????? deploy ???????????????????

A: Shopify Oxygen ???????????? hosting ????????? Shopify ?????????????????? Hydrogen ???????????????????????? ??????????????????????????? Shopify merchants, integrated ????????? Shopify admin, auto-deploy ????????? GitHub, edge deployment ????????????????????? ???????????????????????? ????????????????????????????????? Hydrogen Vercel ?????????????????? Remix/Next.js ??????????????????????????? ?????? edge functions, analytics, preview deployments ????????????????????????????????????????????? $20/month (Pro) ????????? flexible ???????????? ?????????????????? projects ???????????????????????? ??????????????? ???????????????????????? Oxygen (?????????, integrated) ????????????????????? features ??????????????????????????? (A/B testing, advanced analytics) ?????????????????????????????? Vercel

Q: Hydrogen ?????????????????? multi-language (i18n) ??????????

A: ?????????????????? Hydrogen ?????? built-in i18n pattern ????????? locale prefix ?????? URL (e.g., /th/, /en/) Shopify Storefront API ?????????????????? @inContext directive ?????????????????????????????????????????????????????? language/country ??????????????????????????? route parameters ($locale) ???????????? pass context ?????? API queries Shopify Markets ?????????????????? multi-currency, language, pricing ????????? country ????????? Hydrogen ???????????? settings ???????????????????????????????????? API ?????????????????? store ??????????????? ???????????? default locale ???????????? th-TH ???????????????????????? THB ??????????????? en ?????????????????? international customers

📖 บทความที่เกี่ยวข้อง

Shopify Hydrogen Hexagonal Architectureอ่านบทความ → Shopify Hydrogen Container Orchestrationอ่านบทความ → Shopify Hydrogen Service Level Objective SLOอ่านบทความ → Shopify Hydrogen Audit Trail Loggingอ่านบทความ → Shopify Hydrogen Agile Scrum Kanbanอ่านบทความ →

📚 ดูบทความทั้งหมด →