SiamCafe · Blog
Shopify Hydrogen กับ Infrastructure as Code —
บทความ

Shopify Hydrogen กับ Infrastructure as Code —

เผยแพร่ 28 พฤษภาคม 2569

Shopify Hydrogen

Shopify Hydrogen เป็น React Framework สำหรับ Headless Commerce ใช้ Remix Foundation รองรับ SSR Streaming Caching เชื่อมกับ Storefront API Performance สูง

Infrastructure as Code จัดการ Infrastructure ด้วย Code Terraform Pulumi สร้าง Servers CDN อัตโนมัติ Version Control Reproducible

Hydrogen Project Setup

=== Shopify Hydrogen Setup ===

1. สร้าง Project

npm create @shopify/hydrogen@latest -- --template demo-store

cd my-hydrogen-store

2. Project Structure

my-hydrogen-store/

├── app/

│ ├── components/ # React Components

│ ├── routes/ # Remix Routes

│ ├── styles/ # CSS/Tailwind

│ ├── lib/ # Utilities

│ └── entry.server.tsx

├── public/ # Static files

├── .env # Environment variables

├── hydrogen.config.ts # Hydrogen config

├── remix.config.js # Remix config

├── tailwind.config.js # Tailwind config

└── package.json

3. Environment Variables (.env)

SESSION_SECRET=your-session-secret

PUBLIC_STOREFRONT_API_TOKEN=your-storefront-token

PUBLIC_STORE_DOMAIN=your-store.myshopify.com

PRIVATE_STOREFRONT_API_TOKEN=your-private-token

4. Development

npm run dev

http://localhost:3000

5. Build

npm run build

6. Preview Production Build

npm run preview

7. Storefront API Query Example

app/routes/products.$handle.tsx

import { json, type LoaderFunctionArgs } from '@shopify/remix-oxygen';

import { useLoaderData } from '@remix-run/react';

export async function loader({ params, context }: LoaderFunctionArgs) {

const { product } = await context.storefront.query(PRODUCT_QUERY, {

variables: { handle: params.handle },

});

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

priceRange {

minVariantPrice { amount currencyCode }

}

images(first: 5) {

nodes { url altText width height }

}

variants(first: 10) {

nodes { id title price { amount currencyCode } availableForSale }

}

}

}

`;

echo "Hydrogen Project created"

echo " Framework: Remix + React"

echo " API: Shopify Storefront GraphQL"

echo " Dev: npm run dev (localhost:3000)"

Terraform Infrastructure

=== Terraform สำหรับ Hydrogen Deployment ===

main.tf — Infrastructure สำหรับ Hydrogen on AWS

terraform {

required_providers {

aws = { source = "hashicorp/aws", version = "~> 5.0" }

cloudflare = { source = "cloudflare/cloudflare", version = "~> 4.0" }

}

backend "s3" {

bucket = "terraform-state-hydrogen"

key = "hydrogen/terraform.tfstate"

region = "ap-southeast-1"

}

}

provider "aws" { region = "ap-southeast-1" }

# ECR Repository

resource "aws_ecr_repository" "hydrogen" {

name = "hydrogen-store"

image_tag_mutability = "MUTABLE"

image_scanning_configuration { scan_on_push = true }

}

# ECS Cluster

resource "aws_ecs_cluster" "main" {

name = "hydrogen-cluster"

setting { name = "containerInsights" value = "enabled" }

}

# ECS Task Definition

resource "aws_ecs_task_definition" "hydrogen" {

family = "hydrogen-store"

network_mode = "awsvpc"

requires_compatibilities = ["FARGATE"]

cpu = 512

memory = 1024

execution_role_arn = aws_iam_role.ecs_execution.arn

container_definitions = jsonencode([{

name = "hydrogen"

image = ":latest"

essential = true

portMappings = [{ containerPort = 3000, hostPort = 3000 }]

environment = [

{ name = "SESSION_SECRET", value = var.session_secret },

{ name = "PUBLIC_STORE_DOMAIN", value = var.store_domain },

]

logConfiguration = {

logDriver = "awslogs"

options = {

"awslogs-group" = "/ecs/hydrogen"

"awslogs-region" = "ap-southeast-1"

}

}

}])

}

# ALB

resource "aws_lb" "hydrogen" {

name = "hydrogen-alb"

internal = false

load_balancer_type = "application"

security_groups = [aws_security_group.alb.id]

subnets = var.public_subnets

}

# CloudFront CDN

resource "aws_cloudfront_distribution" "hydrogen" {

origin {

domain_name = aws_lb.hydrogen.dns_name

origin_id = "hydrogen-alb"

custom_origin_config {

http_port = 80

https_port = 443

origin_protocol_policy = "https-only"

origin_ssl_protocols = ["TLSv1.2"]

}

}

enabled = true

default_cache_behavior {

allowed_methods = ["GET", "HEAD", "OPTIONS"]

cached_methods = ["GET", "HEAD"]

target_origin_id = "hydrogen-alb"

viewer_protocol_policy = "redirect-to-https"

cache_policy_id = "658327ea-f89d-4fab-a63d-7e88639e58f6"

}

}

variables.tf

variable "session_secret" { type = string sensitive = true }

variable "store_domain" { type = string }

variable "public_subnets" { type = list(string) }

terraform init

terraform plan

terraform apply

infrastructure = {

"Compute": "AWS ECS Fargate (512 CPU, 1GB RAM)",

"Container": "ECR (Docker Registry)",

"Load Balancer": "ALB (Application Load Balancer)",

"CDN": "CloudFront (Global Edge)",

"DNS": "Route53 / Cloudflare",

"Monitoring": "CloudWatch + Container Insights",

"State": "S3 Backend with DynamoDB Lock",

}

print("Terraform Infrastructure:")

for component, detail in infrastructure.items():

print(f" {component}: {detail}")

CI/CD Pipeline

=== GitHub Actions CI/CD สำหรับ Hydrogen ===

.github/workflows/deploy.yml

name: Deploy Hydrogen

on:

push:

branches: [main]

env:

AWS_REGION: ap-southeast-1

ECR_REPOSITORY: hydrogen-store

ECS_CLUSTER: hydrogen-cluster

ECS_SERVICE: hydrogen-service

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

build-deploy:

needs: test

runs-on: ubuntu-latest

steps:

  • uses: actions/checkout@v4
  • name: Configure AWS

uses: aws-actions/configure-aws-credentials@v4

with:

aws-access-key-id: }

aws-secret-access-key: }

aws-region: }

  • name: Login to ECR

id: ecr

uses: aws-actions/amazon-ecr-login@v2

  • name: Build and Push

env:

ECR_REGISTRY: }

IMAGE_TAG: }

run: |

docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .

docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

  • name: Deploy to ECS

run: |

aws ecs update-service \

--cluster $ECS_CLUSTER \

--service $ECS_SERVICE \

--force-new-deployment

  • name: Invalidate CloudFront

run: |

aws cloudfront create-invalidation \

--distribution-id } \

--paths "/*"

Dockerfile

FROM node:20-alpine AS build

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build

FROM node:20-alpine

WORKDIR /app

COPY --from=build /app/build ./build

COPY --from=build /app/node_modules ./node_modules

COPY --from=build /app/package.json ./

EXPOSE 3000

CMD ["npm", "run", "start"]

pipeline_stages = [

{"stage": "Test", "steps": ["Typecheck", "Lint", "Unit Tests"]},

{"stage": "Build", "steps": ["Docker Build", "Push to ECR"]},

{"stage": "Deploy", "steps": ["Update ECS Service", "Rolling Update"]},

{"stage": "Post-deploy", "steps": ["CloudFront Invalidation", "Health Check"]},

]

print("CI/CD Pipeline:")

for p in pipeline_stages:

print(f" {p['stage']}:")

for step in p['steps']:

print(f" - {step}")

Best Practices

  • Caching: ใช้ Hydrogen Cache API สำหรับ Storefront API Responses
  • CDN: ใช้ CloudFront/Cloudflare Cache Static Assets และ Pages
  • IaC: ใช้ Terraform จัดการ Infrastructure ทั้งหมด Version Control ด้วย Git
  • Environment: แยก Environment (dev/staging/prod) ด้วย Terraform Workspaces
  • Monitoring: ใช้ CloudWatch + Datadog/New Relic Monitor Performance
  • Security: เก็บ API Keys ใน Secrets Manager ไม่ Hardcode ใน Code

Shopify Hydrogen คืออะไร

React Framework สำหรับ Headless Commerce Shopify Remix Foundation SSR Streaming Caching Storefront API Performance สูง Custom Storefront