Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 20, 2025

Adds standaloneEngineDefinition to defineSearchEngine() return value, mirroring commerce SSR-Next pattern. Enables pages with standalone search boxes to skip unnecessary server-side search execution.

Changes

New standalone static state factory

  • standalone-static-state-factory.ts: Initializes controllers without calling engine.executeFirstSearch()
  • Returns empty searchActions array

Updated defineSearchEngine() return type

// Before
const engineDefinition = defineSearchEngine(config);

// After
const {searchEngineDefinition, standaloneEngineDefinition} = defineSearchEngine(config);

Both definitions share hydrateStaticState, getAccessToken, setAccessToken. Standalone uses separate fetchStaticState that skips search execution.

Fixed hydration for empty search actions

  • hydrated-state-factory.ts: Only waits for waitForSearchCompletedAction() when searchActions.length > 0

Usage

// Homepage with standalone search box - no API call
const state = await standaloneEngineDefinition.fetchStaticState({
  navigatorContext: {...}
});

// Search results page - executes search
const state = await searchEngineDefinition.fetchStaticState({
  navigatorContext: {...},
  searchParams: {q: 'query'}
});

Backward compatible via destructuring.

Original prompt

This section details on the original issue you should resolve

<issue_title>[DXUI Feature]: Support SSR standalone components</issue_title>
<issue_description>### Feature Description

Feature Request

Add standalone search engine definition support to SSR-Next search implementation (packages/headless/src/ssr-next/search/).

Currently, fetchStaticState() always executes a server-side search, even for standalone search boxes that only need query suggestions and redirection functionality. This creates unnecessary:

  • API requests to the Coveo platform on every page load
  • Server load and latency
  • Resource consumption for pages that don't need search results

Note: This is a new feature for ssr-next/ only (not a breaking change). The older ssr/ implementation will remain unchanged.

Current Behavior

// In packages/headless/src/ssr-next/search/factories/static-state-factory.ts
engine.executeFirstSearch();  // Always executes, no way to skip
const searchActions = [await engine.waitForSearchCompletedAction()];
return createStaticState({searchActions, controllers});

Desired Behavior

Add a new standaloneEngineDefinition option (similar to commerce SSR-Next) that:

  1. Initializes controllers without executing searches
  2. Enables standalone search boxes across the site
  3. Follows the same pattern as commerce's standaloneEngineDefinition
  4. Maintains backward compatibility - existing defineSearchEngine() usage continues to work

Reference Implementation

Commerce SSR-Next already implements this pattern in packages/headless/src/ssr-next/commerce/engine/commerce-engine.ssr.ts:

return {
  listingEngineDefinition: {...},
  searchEngineDefinition: {...},
  standaloneEngineDefinition: {  // ← Search needs this
    fetchStaticState: fetchStaticState(SolutionType.standalone),
    hydrateStaticState: hydrateStaticState(SolutionType.standalone),
  },
};

In commerce's ssr-next/commerce/factories/static-state-factory.ts:

switch (solutionType) {
  case SolutionType.listing:
    buildProductListing(engine).executeFirstRequest();
    break;
  case SolutionType.search:
    buildSearch(engine).executeFirstSearch();
    break;
  // Note: SolutionType.standalone has no case - it skips execution
}

Proposed Implementation

1. Update defineSearchEngine to Return Multiple Engine Definitions

IMPORTANT: This changes the return type, making it a new feature rather than modifying existing behavior.

// packages/headless/src/ssr-next/search/engine/search-engine.ssr.ts
export function defineSearchEngine<TControllerDefinitions>(
  options: SearchEngineDefinitionOptions<TControllerDefinitions>
): {
  searchEngineDefinition: SearchEngineDefinition<SSRSearchEngine, TControllerDefinitions>;
  standaloneEngineDefinition: SearchEngineDefinition<SSRSearchEngine, TControllerDefinitions>;
} {
  // Current implementation becomes searchEngineDefinition
  // Add new standaloneEngineDefinition
}

2. Create Standalone Static State Factory

Create a new factory that skips search execution:

// packages/headless/src/ssr-next/search/factories/standalone-static-state-factory.ts (NEW FILE)
export function fetchStandaloneStaticStateFactory<TControllerDefinitions>(
  controllerDefinitions: AugmentedControllerDefinition<TControllerDefinitions>,
  options: SearchEngineDefinitionOptions<TControllerDefinitions>
): FetchStaticStateFunction<TControllerDefinitions> {
  return async (params) => {
    const {engine, controllers} = await buildFactory(
      controllerDefinitions,
      options
    )(params);
    
    // Skip executeFirstSearch() for standalone
    const staticState = createStaticState({
      searchActions: [],  // Empty array - no search executed
      controllers,
    });
    
    return {...params, ...staticState};
  };
}

3. Update Engine Definition to Export Both

// packages/headless/src/ssr-next/search/engine/search-engine.ssr.ts
const fetchStaticState = fetchStaticStateFactory(...);
const fetchStandaloneStaticState = fetchStandaloneStaticStateFactory(...);  // NEW

const hydrateStaticState = hydratedStaticStateFactory(...);

return {
  searchEngineDefinition: {
    fetchStaticState,
    hydrateStaticState,
    getAccessToken,
    setAccessToken,
  },
  standaloneEngineDefinition: {  // NEW
    fetchStaticState: fetchStandaloneStaticState,
    hydrateStaticState,  // Same hydration logic
    getAccessToken,
    setAccessToken,
  },
};

Files to Create/Modify

New Files

  • packages/headless/src/ssr-next/search/factories/standalone-static-state-factory.ts - Factory that skips search execution
  • packages/headless/src/ssr-next/search/factories/standalone-static-state-factory.test.ts - Tests for standalone factory

Modified Files

  • packages/headless/src/ssr-next/search/engine/search-engine.ssr.ts - Update return type and add standalone definition
  • `packages/headles...

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

- Created standalone-static-state-factory.ts that skips search execution
- Added comprehensive tests for standalone factory
- Updated search-engine.ssr.ts to return both searchEngineDefinition and standaloneEngineDefinition
- Updated hydrated-state-factory.ts to conditionally wait for search completion
- Updated search-engine.ssr.test.ts with tests for both definitions and backward compatibility

Co-authored-by: y-lakhdar <[email protected]>
Copilot AI changed the title [WIP] Add support for SSR standalone components Add standalone engine definition to SSR-Next search Nov 20, 2025
Copilot finished work on behalf of y-lakhdar November 20, 2025 20:15
Copilot AI requested a review from y-lakhdar November 20, 2025 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DXUI Feature]: Support SSR standalone components

2 participants