Template
Remove next/cache usage (use cache, cacheLife, cacheTag, cacheComponents)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F22Ms5Cxam5UHyxaCrtZzu
This commit is contained in:
co-authored by
Claude Fable 5
parent
f23332e42c
commit
1e58ba4ca4
@@ -37,8 +37,7 @@ type AccountPageProps = {
|
|||||||
/**
|
/**
|
||||||
* `/account` — core Customer Accounts surface (name + email only).
|
* `/account` — core Customer Accounts surface (name + email only).
|
||||||
*
|
*
|
||||||
* No `export const dynamic` / `export const fetchCache`: under
|
* No `export const dynamic` / `export const fetchCache`: the page relies on
|
||||||
* `cacheComponents: true`, `force-dynamic` is not allowed. The page relies on
|
|
||||||
* the `AppShell` dynamic context (`await connection()` in the root layout's
|
* the `AppShell` dynamic context (`await connection()` in the root layout's
|
||||||
* shell), which opts the whole subtree into dynamic rendering — any
|
* shell), which opts the whole subtree into dynamic rendering — any
|
||||||
* `headers()`/`cookies()` read inside (e.g. `getCustomerAccessToken()` →
|
* `headers()`/`cookies()` read inside (e.g. `getCustomerAccessToken()` →
|
||||||
|
|||||||
+3
-3
@@ -17,9 +17,9 @@ import { Providers } from "./providers";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Async server shell that owns the per-request (dynamic) reads: the cart seed
|
* Async server shell that owns the per-request (dynamic) reads: the cart seed
|
||||||
* + the shop analytics GID. With `cacheComponents: true`, uncached/dynamic data
|
* + the shop analytics GID. The dynamic data access in this Server Component
|
||||||
* accessed in a Server Component must sit inside a `<Suspense>` boundary so the
|
* sits inside a `<Suspense>` boundary so the static HTML shell prerenders and
|
||||||
* static HTML shell prerenders and the per-buyer parts stream
|
* the per-buyer parts stream
|
||||||
* (`next/server` `connection()` + `headers()`/`cookies()` are per-request).
|
* (`next/server` `connection()` + `headers()`/`cookies()` are per-request).
|
||||||
*
|
*
|
||||||
* Rendered inside `<Suspense>` from the root layout. `await connection()`
|
* Rendered inside `<Suspense>` from the root layout. `await connection()`
|
||||||
|
|||||||
+3
-3
@@ -26,9 +26,9 @@ export const metadata: Metadata = {
|
|||||||
* `CartProvider` would create a divergent inner store vs the root-rendered
|
* `CartProvider` would create a divergent inner store vs the root-rendered
|
||||||
* `CartDrawer` — mutations would not reflect across them.
|
* `CartDrawer` — mutations would not reflect across them.
|
||||||
*
|
*
|
||||||
* `force-dynamic` is not allowed with `cacheComponents: true`; the root layout
|
* No `force-dynamic` needed; the root layout already makes every route
|
||||||
* already makes every route dynamic via `cookies()`/`headers()` in the cart
|
* dynamic via `cookies()`/`headers()` in the cart seed. Reachable via the
|
||||||
* seed. Reachable via the footer `/cart` link (no-JS fallback).
|
* footer `/cart` link (no-JS fallback).
|
||||||
*/
|
*/
|
||||||
export default function CartPage() {
|
export default function CartPage() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { parseCollectionParams, type AvailableFilter } from "@shopify/hydrogen";
|
import { parseCollectionParams, type AvailableFilter } from "@shopify/hydrogen";
|
||||||
import type { ProductFilter as StorefrontApiProductFilter } from "@shopify/hydrogen/storefront-api-types";
|
import type { ProductFilter as StorefrontApiProductFilter } from "@shopify/hydrogen/storefront-api-types";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { cacheLife, cacheTag } from "next/cache";
|
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
|
|
||||||
import { CollectionBrowser } from "@/components/CollectionBrowser";
|
import { CollectionBrowser } from "@/components/CollectionBrowser";
|
||||||
@@ -43,13 +42,7 @@ async function fetchCollection(
|
|||||||
availableFilters: AvailableFilter[];
|
availableFilters: AvailableFilter[];
|
||||||
pageInfo: { hasNextPage: boolean; endCursor?: string | null };
|
pageInfo: { hasNextPage: boolean; endCursor?: string | null };
|
||||||
}> {
|
}> {
|
||||||
"use cache";
|
// Reconstruct URLSearchParams from the serialized search string.
|
||||||
cacheLife("minutes");
|
|
||||||
cacheTag("collections", "products");
|
|
||||||
|
|
||||||
// Reconstruct URLSearchParams from the serialized search string. `use cache`
|
|
||||||
// serializes arguments, so a URLSearchParams passed in loses `.get` — pass a
|
|
||||||
// plain string across the cache boundary and parse inside.
|
|
||||||
const browse = parseCollectionParams(new URLSearchParams(searchString));
|
const browse = parseCollectionParams(new URLSearchParams(searchString));
|
||||||
const result = await query(handle, after, browse.filters, browse.sortKey, browse.reverse);
|
const result = await query(handle, after, browse.filters, browse.sortKey, browse.reverse);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { cacheLife, cacheTag } from "next/cache";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
import { Breadcrumbs } from "@/components/Breadcrumbs";
|
import { Breadcrumbs } from "@/components/Breadcrumbs";
|
||||||
@@ -21,10 +20,6 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function fetchCollections(after?: string) {
|
async function fetchCollections(after?: string) {
|
||||||
"use cache";
|
|
||||||
cacheLife("hours");
|
|
||||||
cacheTag("collections");
|
|
||||||
|
|
||||||
const { data, errors } = await staticStorefrontClient.graphql(COLLECTIONS_QUERY, {
|
const { data, errors } = await staticStorefrontClient.graphql(COLLECTIONS_QUERY, {
|
||||||
variables: { first: 24, after },
|
variables: { first: 24, after },
|
||||||
});
|
});
|
||||||
|
|||||||
+2
-2
@@ -8,8 +8,8 @@ import { SITE_ORIGIN } from "@/lib/site";
|
|||||||
import { AppShell } from "./app-shell";
|
import { AppShell } from "./app-shell";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root layout (engineering.md F1, F4, F7, F10). With `cacheComponents: true`,
|
* Root layout (engineering.md F1, F4, F7, F10). The layout is a
|
||||||
* the layout is a **static shell** — it prerenders the `<html>`/`<body>` +
|
* **static shell** — it prerenders the `<html>`/`<body>` +
|
||||||
* announcement bar, then wraps the per-request (dynamic) `AppShell` (cart seed
|
* announcement bar, then wraps the per-request (dynamic) `AppShell` (cart seed
|
||||||
* + analytics shop + chrome) in `<Suspense>` so the dynamic parts stream while
|
* + analytics shop + chrome) in `<Suspense>` so the dynamic parts stream while
|
||||||
* the static shell serves immediately. `AppShell` calls `connection()` to opt
|
* the static shell serves immediately. `AppShell` calls `connection()` to opt
|
||||||
|
|||||||
+2
-2
@@ -13,8 +13,8 @@ import { getStorefrontClient } from "@/lib/storefront";
|
|||||||
* `references/nextjs.md`). `proxy.ts` cannot inspect the routed response, so
|
* `references/nextjs.md`). `proxy.ts` cannot inspect the routed response, so
|
||||||
* Storefront URL redirects run here, after the framework returns a 404.
|
* Storefront URL redirects run here, after the framework returns a 404.
|
||||||
*
|
*
|
||||||
* With `cacheComponents: true`, the per-request reads (`headers()` +
|
* The per-request reads (`headers()` + `getStorefrontClient()` +
|
||||||
* `getStorefrontClient()` + `redirect()`) must sit inside a `<Suspense>`
|
* `redirect()`) sit inside a `<Suspense>`
|
||||||
* boundary. The static 404 shell prerenders; the `<RedirectChecker>` streams
|
* boundary. The static 404 shell prerenders; the `<RedirectChecker>` streams
|
||||||
* and either `redirect()`s to a matching Shopify URL redirect or renders
|
* and either `redirect()`s to a matching Shopify URL redirect or renders
|
||||||
* nothing (leaving the 404 shell visible).
|
* nothing (leaving the 404 shell visible).
|
||||||
|
|||||||
+1
-7
@@ -1,5 +1,4 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { cacheLife, cacheTag } from "next/cache";
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
import { CollectionCard } from "@/components/CollectionCard";
|
import { CollectionCard } from "@/components/CollectionCard";
|
||||||
@@ -22,13 +21,8 @@ export const metadata: Metadata = {
|
|||||||
twitter: { card: "summary_large_image" },
|
twitter: { card: "summary_large_image" },
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Home catalog fetch — cached at the data boundary (F2: dynamic root layout
|
/** Home catalog fetch. */
|
||||||
* precludes page-level prerender, so the cache-point is the fetch function). */
|
|
||||||
async function fetchHome() {
|
async function fetchHome() {
|
||||||
"use cache";
|
|
||||||
cacheLife("minutes");
|
|
||||||
cacheTag("products", "collections");
|
|
||||||
|
|
||||||
const { data, errors } = await staticStorefrontClient.graphql(HOME_QUERY);
|
const { data, errors } = await staticStorefrontClient.graphql(HOME_QUERY);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
console.error("[hydrogen] Home query failed", errors);
|
console.error("[hydrogen] Home query failed", errors);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { getSelectedProductOptions } from "@shopify/hydrogen";
|
import { getSelectedProductOptions } from "@shopify/hydrogen";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { cacheLife, cacheTag } from "next/cache";
|
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
|
|
||||||
@@ -19,8 +18,6 @@ type Props = {
|
|||||||
|
|
||||||
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||||
const { handle } = await params;
|
const { handle } = await params;
|
||||||
// Re-fetch the product for metadata. It hits the same `use cache` cache-point
|
|
||||||
// as the page render, so this is a cache hit in practice.
|
|
||||||
const { product } = await fetchProduct(handle, "");
|
const { product } = await fetchProduct(handle, "");
|
||||||
const title = product?.title ?? "Product";
|
const title = product?.title ?? "Product";
|
||||||
return {
|
return {
|
||||||
@@ -41,15 +38,9 @@ async function fetchProduct(
|
|||||||
handle: string,
|
handle: string,
|
||||||
searchString: string,
|
searchString: string,
|
||||||
): Promise<{ product: ProductData | null }> {
|
): Promise<{ product: ProductData | null }> {
|
||||||
"use cache";
|
|
||||||
cacheLife("minutes");
|
|
||||||
cacheTag("products");
|
|
||||||
|
|
||||||
// Read variant selection from URL option params (F4: a no-JS GET to
|
// Read variant selection from URL option params (F4: a no-JS GET to
|
||||||
// `?Size=Large&Color=Green` resolves the variant server-side). Do NOT pass
|
// `?Size=Large&Color=Green` resolves the variant server-side). Do NOT pass
|
||||||
// `optionNames: []` — an empty allow-list filters out every param.
|
// `optionNames: []` — an empty allow-list filters out every param.
|
||||||
// Reconstruct URLSearchParams from the serialized search string — `use cache`
|
|
||||||
// serializes arguments, so a URLSearchParams passed in loses `.get`.
|
|
||||||
const selectedOptions = getSelectedProductOptions(new URLSearchParams(searchString));
|
const selectedOptions = getSelectedProductOptions(new URLSearchParams(searchString));
|
||||||
|
|
||||||
const { data, errors } = await staticStorefrontClient.graphql(PRODUCT_QUERY, {
|
const { data, errors } = await staticStorefrontClient.graphql(PRODUCT_QUERY, {
|
||||||
@@ -89,13 +80,9 @@ export default async function ProductPage({ params, searchParams }: Props) {
|
|||||||
/**
|
/**
|
||||||
* Related products (`notes/product.md` "you may also like"). Best-effort: any
|
* Related products (`notes/product.md` "you may also like"). Best-effort: any
|
||||||
* error/timeout returns an empty list so the PDP never breaks. Fetched via the
|
* error/timeout returns an empty list so the PDP never breaks. Fetched via the
|
||||||
* shared `staticStorefrontClient` inside a `use cache` cache-point.
|
* shared `staticStorefrontClient`.
|
||||||
*/
|
*/
|
||||||
async function RelatedProducts({ handle }: { handle: string }) {
|
async function RelatedProducts({ handle }: { handle: string }) {
|
||||||
"use cache";
|
|
||||||
cacheLife("minutes");
|
|
||||||
cacheTag("products");
|
|
||||||
|
|
||||||
let related: ProductCardData[] = [];
|
let related: ProductCardData[] = [];
|
||||||
try {
|
try {
|
||||||
const { data, errors } = await staticStorefrontClient.graphql(RELATED_PRODUCTS_QUERY, {
|
const { data, errors } = await staticStorefrontClient.graphql(RELATED_PRODUCTS_QUERY, {
|
||||||
|
|||||||
+1
-8
@@ -2,7 +2,6 @@ import { parseCollectionParams, type StorefrontApi } from "@shopify/hydrogen";
|
|||||||
import type { AvailableFilter } from "@shopify/hydrogen";
|
import type { AvailableFilter } from "@shopify/hydrogen";
|
||||||
import type { ProductFilter as StorefrontApiProductFilter } from "@shopify/hydrogen/storefront-api-types";
|
import type { ProductFilter as StorefrontApiProductFilter } from "@shopify/hydrogen/storefront-api-types";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { cacheLife, cacheTag } from "next/cache";
|
|
||||||
|
|
||||||
import { CollectionBrowser } from "@/components/CollectionBrowser";
|
import { CollectionBrowser } from "@/components/CollectionBrowser";
|
||||||
import { SEARCH_QUERY } from "@/lib/queries";
|
import { SEARCH_QUERY } from "@/lib/queries";
|
||||||
@@ -37,10 +36,6 @@ type SearchNode = NonNullable<
|
|||||||
type SearchProductNode = Extract<SearchNode, { __typename: "Product" }>;
|
type SearchProductNode = Extract<SearchNode, { __typename: "Product" }>;
|
||||||
|
|
||||||
async function fetchSearch(term: string, searchString: string): Promise<SearchResult> {
|
async function fetchSearch(term: string, searchString: string): Promise<SearchResult> {
|
||||||
"use cache";
|
|
||||||
cacheLife("minutes");
|
|
||||||
cacheTag("products");
|
|
||||||
|
|
||||||
if (!term) {
|
if (!term) {
|
||||||
return {
|
return {
|
||||||
term: "",
|
term: "",
|
||||||
@@ -51,9 +46,7 @@ async function fetchSearch(term: string, searchString: string): Promise<SearchRe
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconstruct URLSearchParams from the serialized search string. `use cache`
|
// Reconstruct URLSearchParams from the serialized search string.
|
||||||
// serializes arguments, so a URLSearchParams passed in loses `.get` — pass a
|
|
||||||
// plain string across the cache boundary and parse inside.
|
|
||||||
const searchParams = new URLSearchParams(searchString);
|
const searchParams = new URLSearchParams(searchString);
|
||||||
const browse = parseCollectionParams(searchParams);
|
const browse = parseCollectionParams(searchParams);
|
||||||
// parseCollectionParams returns a ProductCollectionSortKeys; search only
|
// parseCollectionParams returns a ProductCollectionSortKeys; search only
|
||||||
|
|||||||
+2
-8
@@ -1,5 +1,4 @@
|
|||||||
import type { MetadataRoute } from "next";
|
import type { MetadataRoute } from "next";
|
||||||
import { cacheLife, cacheTag } from "next/cache";
|
|
||||||
|
|
||||||
import { SITEMAP_QUERY } from "@/lib/queries";
|
import { SITEMAP_QUERY } from "@/lib/queries";
|
||||||
import { SITE_ORIGIN } from "@/lib/site";
|
import { SITE_ORIGIN } from "@/lib/site";
|
||||||
@@ -7,9 +6,8 @@ import { staticStorefrontClient } from "@/lib/storefront-static";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* `/sitemap.xml` (engineering.md F10). Lists product + collection URLs with
|
* `/sitemap.xml` (engineering.md F10). Lists product + collection URLs with
|
||||||
* `updatedAt` timestamps, fetched via the shared `staticStorefrontClient`
|
* `updatedAt` timestamps, fetched via the shared `staticStorefrontClient`.
|
||||||
* inside a `use cache` cache-point (catalog, not personalized). mock.shop
|
* mock.shop fallback works (queries mock.shop).
|
||||||
* fallback works (queries mock.shop).
|
|
||||||
*/
|
*/
|
||||||
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||||
const entries = await fetchSitemap();
|
const entries = await fetchSitemap();
|
||||||
@@ -23,10 +21,6 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
|||||||
type SitemapEntry = { loc: string; lastmod?: string };
|
type SitemapEntry = { loc: string; lastmod?: string };
|
||||||
|
|
||||||
async function fetchSitemap(): Promise<SitemapEntry[]> {
|
async function fetchSitemap(): Promise<SitemapEntry[]> {
|
||||||
"use cache";
|
|
||||||
cacheLife("hours");
|
|
||||||
cacheTag("products", "collections");
|
|
||||||
|
|
||||||
const { data, errors } = await staticStorefrontClient.graphql(SITEMAP_QUERY);
|
const { data, errors } = await staticStorefrontClient.graphql(SITEMAP_QUERY);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
console.error("[hydrogen] Sitemap query failed", errors);
|
console.error("[hydrogen] Sitemap query failed", errors);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { FilterGroup } from "@/lib/filters";
|
|||||||
/**
|
/**
|
||||||
* Shared collection/search browser (`hydrogen-collection-browser` /
|
* Shared collection/search browser (`hydrogen-collection-browser` /
|
||||||
* `references/nextjs.md`). The server page fetches the product + filter
|
* `references/nextjs.md`). The server page fetches the product + filter
|
||||||
* snapshot via `staticStorefrontClient` inside a `use cache` cache-point and
|
* snapshot via `staticStorefrontClient` and
|
||||||
* passes it here. This client component owns the `CollectionProvider`,
|
* passes it here. This client component owns the `CollectionProvider`,
|
||||||
* `useCollection`/`useCollectionForm`, URL sync via `useRouter`/`useSearchParams`,
|
* `useCollection`/`useCollectionForm`, URL sync via `useRouter`/`useSearchParams`,
|
||||||
* and the filter/sort/grid UI.
|
* and the filter/sort/grid UI.
|
||||||
|
|||||||
+4
-11
@@ -1,16 +1,14 @@
|
|||||||
import "server-only";
|
import "server-only";
|
||||||
import { analyticsShop as analyticsShopConfig, shop as shopConfig } from "@shared/config";
|
import { analyticsShop as analyticsShopConfig, shop as shopConfig } from "@shared/config";
|
||||||
import { cacheLife, cacheTag } from "next/cache";
|
|
||||||
|
|
||||||
import { SHOP_ANALYTICS_QUERY } from "@/lib/queries";
|
import { SHOP_ANALYTICS_QUERY } from "@/lib/queries";
|
||||||
import { staticStorefrontClient } from "@/lib/storefront-static";
|
import { staticStorefrontClient } from "@/lib/storefront-static";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the shop analytics GID best-effort + non-blocking (engineering.md F1).
|
* Resolve the shop analytics GID best-effort + non-blocking (engineering.md F1).
|
||||||
* The query runs inside a `'use cache'` cache-point (`cacheLife("hours")`,
|
* On timeout/error we fall back to the config-derived shop GID/name (avoids
|
||||||
* `cacheTag("shop")`) so warm requests resolve instantly. On timeout/error we
|
* drift — `@shared/config` `analyticsShop.shopId` is already
|
||||||
* fall back to the config-derived shop GID/name (avoids drift — `@shared/config`
|
* `gid://shopify/Shop/${shop.shopId}`).
|
||||||
* `analyticsShop.shopId` is already `gid://shopify/Shop/${shop.shopId}`).
|
|
||||||
*/
|
*/
|
||||||
export type AnalyticsShop = {
|
export type AnalyticsShop = {
|
||||||
shopId: string;
|
shopId: string;
|
||||||
@@ -24,12 +22,7 @@ const SHOP_FALLBACK: AnalyticsShop = {
|
|||||||
shopDescription: null,
|
shopDescription: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Cache the shop query result for hours (it almost never changes). */
|
|
||||||
async function fetchShopAnalytics(): Promise<AnalyticsShop> {
|
async function fetchShopAnalytics(): Promise<AnalyticsShop> {
|
||||||
"use cache";
|
|
||||||
cacheLife("hours");
|
|
||||||
cacheTag("shop");
|
|
||||||
|
|
||||||
const { data, errors } = await staticStorefrontClient.graphql(SHOP_ANALYTICS_QUERY);
|
const { data, errors } = await staticStorefrontClient.graphql(SHOP_ANALYTICS_QUERY);
|
||||||
if (errors) {
|
if (errors) {
|
||||||
console.error("[hydrogen] Root shop query failed", errors);
|
console.error("[hydrogen] Root shop query failed", errors);
|
||||||
@@ -42,7 +35,7 @@ async function fetchShopAnalytics(): Promise<AnalyticsShop> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Best-effort, non-blocking shop analytics resolution. Races the cached query
|
* Best-effort, non-blocking shop analytics resolution. Races the query
|
||||||
* against a 2000ms timeout; on timeout/error falls back to `@shared/config`.
|
* against a 2000ms timeout; on timeout/error falls back to `@shared/config`.
|
||||||
* Merges the resolved GID/name with the config-derived `analyticsShop`
|
* Merges the resolved GID/name with the config-derived `analyticsShop`
|
||||||
* metadata (acceptedLanguage/currency/hydrogenSubchannelId).
|
* metadata (acceptedLanguage/currency/hydrogenSubchannelId).
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ import { resolveStorefrontConfig } from "./storefront-config";
|
|||||||
* sitemap, related products, shop analytics GID) fetch through this client.
|
* sitemap, related products, shop analytics GID) fetch through this client.
|
||||||
* Only the cart seed uses the per-buyer `getStorefrontClient()`.
|
* Only the cart seed uses the per-buyer `getStorefrontClient()`.
|
||||||
*
|
*
|
||||||
* Caching lives at the `use cache` boundary (cache-points keyed by serializable
|
* The `cache:` option is never passed to `graphql()` (no Oxygen sub-request
|
||||||
* inputs). The `cache:` option is never passed to `graphql()` — Next native
|
* LRU in this Next.js port).
|
||||||
* data cache + `cacheLife`/`cacheTag` replace the Oxygen sub-request LRU.
|
|
||||||
*/
|
*/
|
||||||
const requestContext = createShopifyRequestContext({
|
const requestContext = createShopifyRequestContext({
|
||||||
request: { headers: new Headers() },
|
request: { headers: new Headers() },
|
||||||
|
|||||||
@@ -3,14 +3,10 @@ import type { NextConfig } from "next";
|
|||||||
/**
|
/**
|
||||||
* Next.js 16 config for the Hydrogen example.
|
* Next.js 16 config for the Hydrogen example.
|
||||||
*
|
*
|
||||||
* `cacheComponents: true` enables Cache Components / `use cache` (engineering.md
|
|
||||||
* F2 native Next caching instead of the Oxygen sub-request LRU).
|
|
||||||
*
|
|
||||||
* No `next/image` remote patterns — we use plain `<img>` + the `hydrogen-image`
|
* No `next/image` remote patterns — we use plain `<img>` + the `hydrogen-image`
|
||||||
* helper (F12; Hydrogen ships no Image component and we size CDN URLs ourselves).
|
* helper (F12; Hydrogen ships no Image component and we size CDN URLs ourselves).
|
||||||
*/
|
*/
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
cacheComponents: true,
|
|
||||||
// React Strict Mode is disabled because `@shopify/hydrogen/react`'s
|
// React Strict Mode is disabled because `@shopify/hydrogen/react`'s
|
||||||
// `PredictiveSearchProvider` destroys its store in the Strict Mode effect
|
// `PredictiveSearchProvider` destroys its store in the Strict Mode effect
|
||||||
// cleanup (double-invoke), and `useMemo` returns the same (now-destroyed)
|
// cleanup (double-invoke), and `useMemo` returns the same (now-destroyed)
|
||||||
|
|||||||
Reference in New Issue
Block a user