Skip to content

Server-render catalog search with InstantSearchNext #539

Description

@field123

Parent

#553 — Spec: one session for Elastic Path identity

What to build

A search engine or link preview fetching a category page receives the products in the HTML
instead of an empty shell — which is what has forced the package to recommend a weaker listing
component for pages that matter for ranking.

A consumer mounts nothing and sets no property to get this.

Spec stories 17, 18, 27.

Acceptance criteria

  • A category page scoped by its base filter contains its products in the server-rendered HTML, verifiable without running scripts.
  • Hydration is correct: the browser does not discard and refetch the server-rendered results, and there is no hydration mismatch.
  • Requests made after hydration still route through the storefront's own origin.
  • A failure during the server pass never returns a 500 — the page renders and the browser fetches, so a transient upstream blip cannot become a cached indexing failure.
  • A deep-linked search or refinement URL renders the unrefined first page and corrects itself on hydration, with no visible error. This is an accepted limitation, not a defect.
  • A designer who scopes a category page by URL refinements rather than the base filter gets a development warning that asks whether this is a category page rather than asserting a defect.
  • A consumer adds no route, no property and no component to get server rendering.
  • The server-rendering library's Next module requirements are satisfied by the externals landed in Externalize next/navigation and next/headers for SSR catalog search #547, with no further build change needed here.

Blocked by

The tracker's dependency graph on this issue is authoritative; this list mirrors it.


Below is the original ticket, kept intact — it carries the research and decisions from #486, #495, #523 and #524.

In brief

Catalog search currently renders only in the browser. A search engine or a link preview fetching a category page gets an empty shell, which is why the package has historically pointed people at a different, weaker listing component for pages that matter for SEO.

This issue renders the first page of results on the server so the products are in the HTML.

One honest limitation, accepted deliberately: the server pass renders the default, unfiltered first page. Category pages work correctly because their scope comes from a component property rather than the URL. A deep-linked search URL such as ?query=boots renders the unfiltered page and then corrects itself once the page loads in the browser — acceptable, because search result pages are conventionally excluded from search engines anyway.

Part of the ADR-0003 token architecture. Decided on #524, facts from #523.

Why

The listing-path recommendation (catalog search for everything, SSR and SEO-critical pages included) is conditioned on this landing.

Work

Unconditional <InstantSearchNext> swap — no prop, no separate component. No call site names a transport, a designer has no basis to reason about SSR, and a registered prop is permanent once shipped.

Require-only, never mixed with import for the InstantSearch packages. require of both works; import of one plus require of the other yields two react-instantsearch-core copies, two contexts, Invariant failed, and an SSR 500 on every request. The package's require-everywhere style becomes a load-bearing invariant rather than a style.

baseFilter dev warning, firing on server pass + enableUrlSync + empty baseFilter. SSR is correct only because category scope rides <Configure filters>; a designer can equally scope a category page with EPHierarchicalMenu/EPRefinementList off the URL — identical in Studio, fine in the browser, wrong only in the HTML. The heuristic cannot tell a category page from a search page, so the copy must say "if this is a category page", not assert a defect. Making baseFilter required was rejected: a search page legitimately has none, and a newly-required prop is a break.

Server-render failure falls through to client rendering and must never 500 the page. A deliberate narrowing of the keep-the-error-slot rule to the client side: a shopper always sees the hydrated render, whereas the alternative is a crawler indexing "Catalog Search is not available" for a category page, and a transient proxy blip becoming a cached SEO failure.

What SSR delivers, and does not

It server-renders the unrefined default first page. <Configure query/filters/hitsPerPage> flows; initialUiState and routing-derived URL state do not, and useSearchParams() is empty during the server pass even under force-dynamic — so skipping conditionally is foreclosed, not rejected. A deep-linked ?query=boots or refinement URL renders unrefined and self-corrects on hydration. Accepted: those pages are conventionally noindex and were never the SEO case.

Consumer wiring is zero — no route, no prop, nothing to mount.

Acceptance criteria (original — folded into the list above)

Blocked by: the platform enablement issue, the dependency floors issue, and the catalog-search shim issue.


ADR-0003: plasmicpkgs/commerce-providers/elastic-path/docs/adr/0003-one-session-for-elastic-path-identity.md. Map: #486. Issue set: #496.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestready-for-agentScoped tracer-bullet slice, ready for an agent to pick up

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions