### Install Shopify AI Toolkit via VS Code Command Palette Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Use the Command Palette to install the plugin by selecting the install command and providing the repository URL. ```text Chat: Install Plugin From Source ``` ```text https://github.com/Shopify/shopify-ai-toolkit ``` -------------------------------- ### Install Shopify AI Toolkit for Hermes Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Download and execute the install script in your terminal to set up the Shopify plugin for Hermes. ```bash curl -fsSL https://raw.githubusercontent.com/Shopify/Shopify-AI-Toolkit/main/.hermes-plugin/install.sh -o /tmp/shopify-hermes-install.sh bash /tmp/shopify-hermes-install.sh ``` -------------------------------- ### Install Shopify AI Toolkit via OpenClaw Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Run this command in your terminal to install the toolkit using the OpenClaw plugin manager. ```bash openclaw plugins install npm:@shopify/ai-toolkit ``` -------------------------------- ### Install Shopify AI Toolkit via Pi Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Run this command in your terminal to install the toolkit using the Pi package manager. ```bash pi install npm:@shopify/ai-toolkit ``` -------------------------------- ### Install Shopify AI Toolkit for Antigravity CLI Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Run this command in your terminal to install the Shopify plugin for the Antigravity CLI. ```bash agy plugin install https://github.com/Shopify/shopify-ai-toolkit ``` -------------------------------- ### Start Hydrogen development server with npm Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching/graphiql Command to run the Hydrogen development server using npm. ```bash npx shopify hydrogen dev ``` -------------------------------- ### Run the Hydrogen development server Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Navigate to the project directory and start the development server to view the Mock.shop inventory at http://localhost:3000. ```bash cd hydrogen-quickstart shopify hydrogen dev ``` -------------------------------- ### Bitbucket pipeline configuration Source: https://shopify.dev/docs/storefronts/headless/hydrogen/deployments/custom-ci-cd Example configuration for a Bitbucket pipeline that installs dependencies and deploys to Oxygen using the SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN variable. ```yaml image: atlassian/default-image:4 pipelines: default: - step: name: 'Build and deploy to Oxygen' script: - npm ci - npx shopify hydrogen deploy --token $SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN ``` -------------------------------- ### Create a new Hydrogen storefront Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Initialize a new Hydrogen project using the quickstart flag, which applies recommended default options. ```bash npm create @shopify/hydrogen@latest -- --quickstart ``` -------------------------------- ### Start Hydrogen development server with pnpm Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching/graphiql Command to run the Hydrogen development server using pnpm. ```bash pnpm shopify hydrogen dev ``` -------------------------------- ### Create a Response object Source: https://shopify.dev/docs/storefronts/headless/hydrogen/deployments/oxygen-runtime Example of instantiating a new Response object using a body and initialization options. ```javascript const response = new Response(body, init); ``` -------------------------------- ### Complete pagination example Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching/pagination A standard implementation of data fetching with pagination using getPaginationVariables and the Pagination component. ```javascript import {getPaginationVariables, Pagination} from '@shopify/hydrogen'; import {useLoaderData, Link} from '@remix-run/react'; import {json} from '@shopify/remix-oxygen'; export async function loader({context, request}) { const variables = getPaginationVariables(request, { pageBy: 4, }); const {products} = await context.storefront.query(ALL_PRODUCTS_QUERY, { variables, }); return json({ products, }); } export default function () { const {products} = useLoaderData(); return ( {({nodes, NextLink, PreviousLink, isLoading}) => ( <> {isLoading ? 'Loading...' : 'Load previous products'} {nodes.map((product) => ( {product.title} ))} {isLoading ? 'Loading...' : 'Load next products'} )} ``` -------------------------------- ### Start development server in debug mode Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/server-code Run this command to start the server with the --debug flag, which enables a port (default 9229) for debugger connections. The --worker flag is required to mimic the Oxygen environment. ```bash npx shopify hydrogen dev --worker --debug ``` -------------------------------- ### Start Hydrogen development server with Yarn Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching/graphiql Command to run the Hydrogen development server using Yarn. ```bash yarn shopify hydrogen dev ``` -------------------------------- ### Install Shopify AI Toolkit for Claude Code Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Run this command in your terminal to install the Shopify AI toolkit plugin for Claude Code. ```bash claude plugin install shopify-ai-toolkit@claude-plugins-official ``` -------------------------------- ### Install Shopify AI Toolkit for Codex Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Run this command in your terminal to add the Shopify plugin to Codex. ```bash codex plugin add shopify@openai-curated ``` -------------------------------- ### Query the Storefront API in JavaScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching This example demonstrates how to query the Storefront API within a /app/routes/products.$productHandle.jsx route using JavaScript. ```javascript import {useLoaderData} from '@shopify/remix-oxygen'; // Fetch and return API data with a Remix loader function export async function loader({params, context}) { const {handle} = params; const {storefront} = context; const {product} = await storefront.query(PRODUCT_QUERY, { variables: {handle}, }); return {product}; } // Render the component using data returned by the loader export default function Product() { const {product} = useLoaderData(); return (

{product.title}

) } // Query the product title by its ID const PRODUCT_QUERY = `#graphql product(handle: $handle) { title }` ``` -------------------------------- ### Implement custom caching with CacheCustom Source: https://shopify.dev/docs/storefronts/headless/hydrogen/caching This example demonstrates how to configure a custom caching strategy that requires revalidation, prevents transformation, and sets a 30-second freshness window. ```javascript storefront.CacheCustom({ mode: 'must-revalidate, no-transform', maxAge: 30, }) ``` -------------------------------- ### Loader with Promise.all in JavaScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/subrequest-profiler An example of a loader function using Promise.all to fetch multiple queries simultaneously. ```javascript export async function loader({context}) { const [query1, query2, query3] = await Promise.all([ context.some3p('query1'), context.some3p('query2'), context.some3p('query3'), ]); return defer({ query1, query2, query3, }); } ``` -------------------------------- ### Create a third-party API client Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching/third-party This example demonstrates creating an API client that leverages Hydrogen's caching utilities to maintain consistent data fetching behavior. ```javascript import {createWithCache} from '@shopify/hydrogen'; export function createRickAndMortyClient({cache, waitUntil}) { const withCache = createWithCache({cache, waitUntil}); return { query: (query, variables) => withCache('rick-and-morty', { query, variables, }, async () => { const response = await fetch('https://rickandmortyapi.com/graphql', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({query, variables}), }); return response.json(); }), }; } ``` ```typescript import {createWithCache} from '@shopify/hydrogen'; import type {CacheStrategy} from '@shopify/hydrogen'; export function createRickAndMortyClient({ cache, waitUntil, }: { cache: Cache; waitUntil: (promise: Promise) => void; }) { const withCache = createWithCache({cache, waitUntil}); return { query: (query: string, variables?: Record) => withCache('rick-and-morty', { query, variables, }, async () => { const response = await fetch('https://rickandmortyapi.com/graphql', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({query, variables}), }); return response.json(); }), }; } ``` -------------------------------- ### Render character list in JSX Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching/third-party This example shows how to fetch data using a loader and render it in a JSX route file. ```jsx import {json} from '@shopify/remix-oxygen'; import {useLoaderData} from '@remix-run/react'; import {CacheShort} from '@shopify/hydrogen'; // Fetch and return API data with a Remix loader function export async function loader({context}) { const {characters} = await context.rickAndMorty.query(CHARACTERS_QUERY, { cache: CacheShort(), }); return json({characters}); } // Render the component using data returned by the loader export default function Characters() { const {characters} = useLoaderData(); return (

Rick & Morty Characters

    {(characters.results || []).map((character) => (
  • {character.name}
  • ))}
); } // Query the API for a list of characters const CHARACTERS_QUERY = `#graphql:rickAndMorty query { characters(page: 1) { results { name id } } } `; ``` -------------------------------- ### Query the Storefront API in TypeScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching This example demonstrates how to query the Storefront API within a /app/routes/products.$productHandle.jsx route using TypeScript with proper type definitions. ```typescript import {useLoaderData} from '@shopify/remix-oxygen'; import type { LoaderArgs } from '@shopify/remix-oxygen'; import type { Product } from '@shopify/hydrogen/storefront-api-types'; // Fetch and return API data with a Remix loader function export async function loader({params, context}: LoaderArgs) { const {handle} = params; const {storefront} = context; const {product} = await storefront.query(PRODUCT_QUERY, { variables: {handle}, }); return {product}; } // Render the component using data returned by the loader export default function Product() { const {product} = useLoaderData(); return (

{product.title}

) } // Query the product title by its ID const PRODUCT_QUERY = `#graphql product(handle: $handle) { title } ` ``` -------------------------------- ### Default Hydrogen project structure Source: https://shopify.dev/docs/storefronts/headless/hydrogen/fundamentals The standard directory layout for a new Hydrogen project initialized via the Quickstart template. ```text 📂 hydrogen-quickstart/ ├── 📁 app/ │ ├── 📁 assets/ │ ├── 📁 components/ │ ├── 📁 graphql/ │ ├── 📁 lib/ │ ├── 📁 routes/ │ ├── 📁 styles/ │ ├── entry.client.jsx │ ├── entry.server.jsx │ └── root.jsx ├── 📁 public/ ├── CHANGELOG.md ├── README.md ├── customer-accountapi.generated.d.ts ├── env.d.ts ├── jsconfig.json ├── package.json ├── postcss.config.js ├── server.js ├── storefrontapi.generated.d.ts └── vite.config.js ``` -------------------------------- ### GitLab CI/CD configuration Source: https://shopify.dev/docs/storefronts/headless/hydrogen/deployments/custom-ci-cd Example configuration for a GitLab CI/CD pipeline using a Node.js image to build and deploy the Hydrogen storefront. ```yaml stages: - build-and-deploy build-and-deploy: image: node:18 stage: build-and-deploy script: - npm ci - npx shopify hydrogen deploy --token $SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN ``` -------------------------------- ### Update /app/root.jsx with nonce Source: https://shopify.dev/docs/storefronts/headless/hydrogen/content-security-policy This example demonstrates how to use the useNonce hook and pass the nonce prop to script-generating components within the App and ErrorBoundary functions in /app/root.jsx. ```javascript import {useNonce} from '@shopify/hydrogen'; export default function App() { const nonce = useNonce(); const data = useLoaderData(); return ( {/** Pass the nonce to all components that generate a script **/} ); } export function ErrorBoundary() { const error = useRouteError(); const [root] = useMatches(); const nonce = useNonce(); let errorMessage = "Unknown error"; let errorStatus = 500; if (isRouteErrorResponse(error)) { errorMessage = error?.data?.message ?? error.data; errorStatus = error.status; } else if (error instanceof Error) { errorMessage = error.message; } return (

Oops

{errorStatus}

{errorMessage && (
{errorMessage}
)}
{/** Make sure to remember to pass the nonce to components within the ErrorBoundary **/} ); } ``` -------------------------------- ### GitHub workflow deployment and testing Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/end-to-end-testing Example of a GitHub Actions workflow step that deploys to Oxygen and subsequently runs end-to-end tests using the generated token and URL from the log file. ```yaml jobs: deploy: ... steps: - name: Build and Publish to Oxygen id: deploy run: - npx shopify hydrogen deploy --auth-bypass-token --token $SHOPIFY_HYDROGEN_DEPLOYMENT_TOKEN - name: Run End-to-end Tests run: | export AUTH_BYPASS_TOKEN=$(jq -r '.authBypassToken' h2_deploy_log.json) export DEPLOYMENT_URL=$(jq -r '.url' h2_deploy_log.json) npm run e2e-test ``` -------------------------------- ### Create a custom CMS fetcher in server.js (JavaScript) Source: https://shopify.dev/docs/storefronts/headless/hydrogen/caching/third-party This example demonstrates how to define a custom fetcher for a third-party CMS using withCache.fetch within the server.js file. ```javascript import {createStorefrontClient, createWithCache} from '@shopify/hydrogen'; import {createRequestHandler} from '@shopify/remix-oxygen'; export default { async fetch(request, env, executionContext) { const cache = await caches.open('hydrogen'); const waitUntil = (promise) => executionContext.waitUntil(promise); const {storefront} = createStorefrontClient({ cache, waitUntil, // ... }); const withCache = createWithCache({cache, waitUntil, request}); const fetchMyCMS = ( query: string, cacheStrategy = storefront.CacheLong(), ) => { const CMS_API_ENDPOINT = 'https://example-cms.com/api'; const cacheKey = [CMS_API_ENDPOINT, query]; return withCache.fetch( CMS_API_ENDPOINT, { method: 'POST', body: JSON.stringify({query}), headers: {'Content-Type': 'application/json'}, }, { cacheKey, cacheStrategy, // Cache if there are no data errors or specific data that make this result not suited for caching shouldCacheResponse: (result) => !(result?.errors || result?.isLoggedIn), }, ); }; const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, getLoadContext: () => ({storefront, fetchMyCMS, waitUntil}), }); return handleRequest(request); }, }; ``` -------------------------------- ### View CPU profiler output Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/cpu-startup Example of the terminal output generated by the CPU profiler, showing the location of the .cpuprofile file and the measured startup times. ```text Starting profiler for CPU startup...Profile will be written to: ./startup.cpuprofile #1 Total time: 362.337 ms #2 Total time: 123.359 ms #3 Total time: 72.048 ms ./startup.cpuprofile Waiting for changes... ``` -------------------------------- ### Oxygen GitHub workflow file example Source: https://shopify.dev/docs/storefronts/headless/hydrogen/deployments/github This file controls deployments to Oxygen from GitHub. It is automatically added to your repository when you connect it to the Hydrogen channel. ```yaml name: Oxygen on: push: branches: - main pull_request: jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: shopify/oxygen-deployment-action@v1 with: shopify_storefront_api_token: ${{ secrets.SHOPIFY_STOREFRONT_API_TOKEN }} shopify_storefront_id: ${{ secrets.SHOPIFY_STOREFRONT_ID }} ``` -------------------------------- ### Create a custom GraphiQL route in JavaScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/data-fetching/graphiql Example of creating a custom GraphiQL route in a JavaScript file at /app/routes/graphiql.jsx, ensuring it is only accessible in development. ```javascript import {graphiqlLoader} from '@shopify/hydrogen'; import {redirect} from '@shopify/remix-oxygen'; export async function loader(args) { if (process.env.NODE_ENV === 'development') { // Default Hydrogen GraphiQL behavior return graphiqlLoader(args); } return redirect('/'); } ``` -------------------------------- ### Caching Third-Party CMS Data with createWithCache Source: https://shopify.dev/docs/storefronts/headless/hydrogen/caching/third-party This example demonstrates how to initialize the Hydrogen storefront client and use createWithCache to fetch and cache data from an external CMS API endpoint. ```typescript import {createStorefrontClient, createWithCache} from '@shopify/hydrogen'; import {createRequestHandler} from '@shopify/remix-oxygen'; export default { async fetch(request: Request, env: Env, executionContext: ExecutionContext) { const cache = await caches.open('hydrogen'); const waitUntil = (promise: Promise) => executionContext.waitUntil(promise); const {storefront} = createStorefrontClient({ cache, waitUntil, // ... }); const withCache = createWithCache({cache, waitUntil, request}); const fetchMyCMS = ( query: string, cacheStrategy = storefront.CacheLong(), ) => { const CMS_API_ENDPOINT = 'https://example-cms.com/api'; const cacheKey = [CMS_API_ENDPOINT, query]; return withCache.fetch( CMS_API_ENDPOINT, { method: 'POST', body: JSON.stringify({query}), headers: {'Content-Type': 'application/json'}, }, { cacheKey, cacheStrategy, // Cache if there are no data errors or specific data that make this result not suited for caching shouldCacheResponse: (result: My3PDataResponse) => !(result?.errors || result?.isLoggedIn), }, ); }; const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, getLoadContext: () => ({storefront, fetchMyCMS, waitUntil}), }); return handleRequest(request); }, }; ``` -------------------------------- ### Visual Studio Code launch configuration Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/server-code Add this configuration to your .vscode/launch.json file to connect the VS Code debugger to the local worker. Ensure the port matches the one specified when starting the server. ```json { "version": "0.2.0", "configurations": [ { "name": "Hydrogen", "type": "node", "request": "attach", "port": 9229, "cwd": "/", "resolveSourceMapLocations": null, "attachExistingChildren": false, "autoAttachChildProcesses": false, "restart": true } ] } ``` -------------------------------- ### Run the CPU profiler Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/cpu-startup Execute this command in your terminal to build the app, run the bundle, and begin profiling startup time. ```bash npx shopify hydrogen debug cpu ``` -------------------------------- ### Deploy Hydrogen storefront Source: https://shopify.dev/docs/storefronts/headless/hydrogen/deployments Use the Shopify CLI to initiate a deployment of your Hydrogen storefront. ```bash npx shopify hydrogen deploy ``` -------------------------------- ### ReadableStream.getReader(options) Source: https://shopify.dev/docs/storefronts/headless/hydrogen/deployments/oxygen-runtime Gets an instance of a reader and locks the ReadableStream to that reader instance. ```APIDOC ## getReader(options) ### Description Gets an instance of ReadableStreamDefaultReader or ReadableStreamBYOBReader and locks the stream. ### Parameters - **options** (Object) - Optional - An object where the key 'mode' can be set to 'byob' to create a ReadableStreamBYOBReader. ### Returns - **ReadableStreamDefaultReader | ReadableStreamBYOBReader** - The reader instance. ``` -------------------------------- ### Loader with Promise.all in TypeScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/subrequest-profiler An example of a loader function using Promise.all with TypeScript type annotations. ```typescript export async function loader({context}: LoaderFunctionArgs) { const [query1, query2, query3] = await Promise.all([ context.some3p('query1'), context.some3p('query2'), context.some3p('query3'), ]); return defer({ query1, query2, query3, }); } ``` -------------------------------- ### Configure Content Security Policy in JavaScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/analytics/consent Use this implementation in /app/entry.server.jsx to initialize the CSP provider with shop domain settings. ```javascript export default async function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, reactRouterContext: EntryContext, context: AppLoadContext, ) { const {nonce, header, NonceProvider} = createContentSecurityPolicy({ shop: { checkoutDomain: context.env.PUBLIC_CHECKOUT_DOMAIN, storeDomain: context.env.PUBLIC_STORE_DOMAIN, } }); ``` -------------------------------- ### Exception log JSON structure Source: https://shopify.dev/docs/storefronts/headless/hydrogen/logging Example of an exception log generated by uncaught exceptions in the Hydrogen storefront. ```json { hostname: "example.com", shop_id: "123456", deployment_id: "abc8221", storefront_id: "11111", timestamp: "2023-03-30T10:00:00.000Z", request_id: "abc4-3123fe-rg", path: "/url_path", idx: 2, type: "exception", name: "StandardError", message: "Error when assigning value to a variable" } ``` -------------------------------- ### Configure Third-Party Caching in server.js (JavaScript) Source: https://shopify.dev/docs/storefronts/headless/hydrogen/caching/third-party This example shows how to set up a custom fetch function for a third-party CMS within the server.js file, using createWithCache to handle caching logic and error checking. ```javascript import {createStorefrontClient, createWithCache} from '@shopify/hydrogen'; import {createRequestHandler} from '@shopify/remix-oxygen'; export default { async fetch(request, env, executionContext) { const cache = await caches.open('hydrogen'); const waitUntil = (promise) => executionContext.waitUntil(promise); const {storefront} = createStorefrontClient({ cache, waitUntil, // ... }); const withCache = createWithCache({cache, waitUntil, request}); const fetchMyCMS = ( query: string, cacheStrategy = storefront.CacheLong(), ) => { const CMS_API_ENDPOINT = 'https://example-cms.com/api'; const cacheKey = [CMS_API_ENDPOINT, query]; return withCache.run( { cacheKey, cacheStrategy, // Cache if there are no data errors shouldCacheResult: (result) => result.errors.length === 0, }, async () => { const response = await fetch(CMS_API_ENDPOINT, { method: 'POST', body: JSON.stringify({query}), headers: {'Content-Type': 'application/json'}, }); if (!response.ok) return {errors: ['Something went wrong']}; const {product} = await response.json(); return {id: product.id, errors: []}; }, ); }; const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, getLoadContext: () => ({storefront, fetchMyCMS, waitUntil}), }); return handleRequest(request); }, }; ``` -------------------------------- ### Request log JSON structure Source: https://shopify.dev/docs/storefronts/headless/hydrogen/logging Example of a request log generated by Shopify containing metadata about a specific request. ```json { hostname: "example.com", shop_id: "123456", deployment_id: "abc8221", storefront_id: "11111", timestamp: "2023-03-30T10:00:00.000Z", request_id: "abc4-3123fe-rg", path: "/url_path", idx: 0, type: "request", code: 200, method: "GET", url: "example.com/url_path", user_agent: "Mozilla/5.0" } ``` -------------------------------- ### Link Hydrogen project to Shopify Source: https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started Use the Shopify CLI to link the local project to a Shopify storefront by following the interactive prompts. ```bash npx shopify hydrogen link ``` -------------------------------- ### Request waterfall pattern in JavaScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/subrequest-profiler An example of a loader function where subrequests are awaited sequentially, creating a waterfall effect. ```javascript export async function loader({context}) { return defer({ query1: await context.some3p('query1'), query2: await context.some3p('query2'), query3: await context.some3p('query3'), }); } ``` -------------------------------- ### Access custom request headers Source: https://shopify.dev/docs/storefronts/headless/hydrogen/deployments/oxygen-runtime Example of retrieving a custom Oxygen header, such as the buyer's country, from the request headers. ```javascript const userCountry = request.headers.get('oxygen-buyer-country'); ``` -------------------------------- ### Cache request trace JSON example Source: https://shopify.dev/docs/storefronts/headless/hydrogen/trace-exports Sample cache request trace data exported in the OpenTelemetry JSON format. ```json { "resourceSpans": [{ "resource": { "attributes": [ { "key": "service.name", "value": {"stringValue": "oxygen"} }, ] }, "scopeSpans": [{ "spans": [{ "spanId": "7a8b9c0d1e2f", "traceId": "4bf92f3577b34da6a3ce929d0e0e4736", "parentSpanId": "3e5f6a7b8c9d", "name": "CACHE [HIT] query ProductDetails", "kind": 2, "startTimeUnixNano": "1645567489010000000", "endTimeUnixNano": "1645567489015000000", "attributes": [ { "key": "request.type", "value": {"stringValue": "cache_api"} }, { "key": "cache.status", "value": {"stringValue": "hit"} }, { "key": "status.code", "value": {"intValue": 200} }, { "key": "cache.query.type", "value": {"stringValue": "query"} }, { ``` -------------------------------- ### Primary request trace JSON example Source: https://shopify.dev/docs/storefronts/headless/hydrogen/trace-exports Sample primary request trace data exported in the OpenTelemetry JSON format. ```json { "resourceSpans": [{ "resource": { "attributes": [ { "key": "service.name", "value": {"stringValue": "oxygen"} }, ] }, "scopeSpans": [{ "spans": [{ "spanId": "3e5f6a7b8c9d", "traceId": "4bf92f3577b34da6a3ce929d0e0e4736", "name": "GET /products/123", "kind": 2, "startTimeUnixNano": "1645567489000000000", "endTimeUnixNano": "1645567489100000000", "attributes": [ { "key": "request.type", "value": {"stringValue": "request"} }, { "key": "http.method", "value": {"stringValue": "GET"} }, { "key": "http.path", "value": {"stringValue": "/products/123"} }, { "key": "http.status_code", "value": {"intValue": 200} }, { ``` -------------------------------- ### Runtime log JSON structure Source: https://shopify.dev/docs/storefronts/headless/hydrogen/logging Example of a runtime log generated by console methods like console.log, console.warn, or console.error. ```json { hostname: "example.com", shop_id: "123456", deployment_id: "abc8221", storefront_id: "11111", timestamp: "2023-03-30T10:00:00.000Z", request_id: "abc4-3123fe-rg", path: "/url_path", idx: 1, type: "runtime", level: "info", message: "this is log message" } ``` -------------------------------- ### Configure server.js for JavaScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/caching/third-party Initializes the withCache utility and passes it to the Remix load context in a JavaScript environment. ```javascript import {createStorefrontClient, createWithCache} from '@shopify/hydrogen'; import {createRequestHandler} from '@shopify/remix-oxygen'; export default { async fetch(request, env, executionContext) { const cache = await caches.open('hydrogen'); const waitUntil = (promise) => executionContext.waitUntil(promise); const {storefront} = createStorefrontClient({ cache, waitUntil, // ... }); // Create withCache object const withCache = createWithCache({cache, waitUntil, request}); const handleRequest = createRequestHandler({ build: remixBuild, mode: process.env.NODE_ENV, // Pass withCache to the Remix context getLoadContext: () => ({storefront, withCache, waitUntil}), }); return handleRequest(request); }, }; ``` -------------------------------- ### Loader function with defer in JavaScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/subrequest-profiler An example of a loader function using the defer utility to handle multiple third-party queries in JavaScript. ```javascript export async function loader({context}) { return defer({ query1: await context.some3p('query1'), query2: context.some3p('query2'), query3: context.some3p('query3'), }); } ``` -------------------------------- ### Request waterfall pattern in TypeScript Source: https://shopify.dev/docs/storefronts/headless/hydrogen/debugging/subrequest-profiler An example of a loader function using TypeScript where subrequests are awaited sequentially, creating a waterfall effect. ```typescript export async function loader({context}: LoaderFunctionArgs) { return defer({ query1: await context.some3p('query1'), query2: await context.some3p('query2'), query3: await context.some3p('query3'), }); } ```