Skip to content

Commit

Permalink
docs: add reference doc for SSR (#3612)
Browse files Browse the repository at this point in the history
  • Loading branch information
y-lakhdar authored Feb 15, 2024
1 parent 095f397 commit efbbcc2
Show file tree
Hide file tree
Showing 49 changed files with 809 additions and 342 deletions.
5 changes: 1 addition & 4 deletions packages/headless-react/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# Headless React Utils for SSR

**:warning: Alpha release**
This is an alpha release with several features yet to be implemented (e.g., analytics, [synchronizing search parameters with the URL](https://docs.coveo.com/en/headless/latest/usage/synchronize-search-parameters-with-the-url/), etc).

`@coveo/headless-react/ssr` provides react utilities for Server side rendering with headless controllers.
`@coveo/headless-react/ssr` provides React utilities for server-side rendering with headless controllers.

- Refer to [samples/headless-ssr](https://github.com/coveo/ui-kit/tree/master/packages/samples/headless-ssr/) for examples.
- All exports from `@coveo/headless/ssr` are also available from under `@coveo/headless-react/ssr` as convenience.
5 changes: 2 additions & 3 deletions packages/headless-react/src/ssr/search-engine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ export function createSingletonContext<
}

/**
* @internal
* Returns controller hooks and SSR, CSR context providers that can be used to interact with a search engine
* in the server and client side respectively.
* Returns controller hooks as well as SSR and CSR context providers that can be used to interact with a search engine
* on the server and client side respectively.
*/
export function defineSearchEngine<
TControllers extends ControllerDefinitionsMap<SearchEngine, Controller>,
Expand Down
8 changes: 8 additions & 0 deletions packages/headless/config/api-extractor/ssr.search.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "./base.json",
"mainEntryPointFilePath": "<projectFolder>/dist/definitions/ssr.index.d.ts",
"docModel": {
"enabled": true,
"apiJsonFilePath": "<projectFolder>/temp/ssr-search.api.json"
}
}
8 changes: 7 additions & 1 deletion packages/headless/doc-parser/doc-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {productListingUseCase} from './use-cases/product-listing';
import {productRecommendationUseCase} from './use-cases/product-recommendation';
import {recommendationUseCase} from './use-cases/recommendation';
import {searchUseCase} from './use-cases/search';
import {ssrSearchUseCase} from './use-cases/ssr-search';
import {UseCaseConfiguration} from './use-cases/use-case-configuration';

interface UseCase {
Expand All @@ -36,7 +37,7 @@ interface ResolvedUseCase {
engine: Engine;
}

const useCases: UseCase[] = [
export const useCases: UseCase[] = [
{
name: 'search',
entryFile: 'temp/index.api.json',
Expand Down Expand Up @@ -67,6 +68,11 @@ const useCases: UseCase[] = [
entryFile: 'temp/insight.api.json',
config: insightUseCase,
},
{
name: 'ssr-search',
entryFile: 'temp/ssr-search.api.json',
config: ssrSearchUseCase,
},
// eslint-disable-next-line @cspell/spellchecker
// TODO CAPI-89: Uncomment when we're ready to make the Commerce sub-package public.
//{
Expand Down
10 changes: 9 additions & 1 deletion packages/headless/doc-parser/src/api-finder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ApiEntryPoint} from '@microsoft/api-extractor-model';

export function findApi(entry: ApiEntryPoint, apiName: string) {
const canonicalName = extractCanonicalName(apiName);
const canonicalName = extractCanonicalName(removeTypeTemplate(apiName));
const [result] = entry.findMembersByName(canonicalName);

if (!result) {
Expand All @@ -20,3 +20,11 @@ function extractCanonicalName(apiName: string) {

return apiName.slice(0, endIndex).trim();
}

const removeTypeTemplate = (input: string): string => {
// Regular expression to match the templatable type
const regex = /^(.+)<.*>$/;
const match = input.match(regex);

return match ? match[1] : input;
};
170 changes: 170 additions & 0 deletions packages/headless/doc-parser/use-cases/ssr-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import {ActionLoaderConfiguration} from '../src/headless-export-resolvers/action-loader-resolver';
import {ControllerConfiguration} from '../src/headless-export-resolvers/controller-resolver';
import {EngineConfiguration} from '../src/headless-export-resolvers/engine-resolver';

const controllers: ControllerConfiguration[] = [
{
initializer: 'defineFacet',
samplePaths: {},
},
{
initializer: 'defineContext',
samplePaths: {},
},
{
initializer: 'defineDictionaryFieldContext',
samplePaths: {},
},
{
initializer: 'defineBreadcrumbManager',
samplePaths: {},
},
{
initializer: 'defineDidYouMean',
samplePaths: {},
},
{
initializer: 'defineFacetManager',
samplePaths: {},
},
{
initializer: 'defineAutomaticFacetGenerator',
samplePaths: {},
},
{
initializer: 'defineCategoryFacet',
samplePaths: {},
},
{
initializer: 'defineDateFacet',
samplePaths: {},
},
{
initializer: 'defineDateFilter',
samplePaths: {},
},
{
initializer: 'defineNumericFacet',
samplePaths: {},
},
{
initializer: 'defineNumericFilter',
samplePaths: {},
},
{
initializer: 'defineCategoryFieldSuggestions',
samplePaths: {},
},
{
initializer: 'defineFieldSuggestions',
samplePaths: {},
},
{
initializer: 'defineFoldedResultList',
samplePaths: {},
},
{
initializer: 'defineHistoryManager',
samplePaths: {},
},
{
initializer: 'defineInstantResults',
samplePaths: {},
},
{
initializer: 'definePager',
samplePaths: {},
},
{
initializer: 'defineQueryError',
samplePaths: {},
},
{
initializer: 'defineQuerySummary',
samplePaths: {},
},
{
initializer: 'defineQuickview',
samplePaths: {},
},
{
initializer: 'defineRecentQueriesList',
samplePaths: {},
},
{
initializer: 'defineRelevanceInspector',
samplePaths: {},
},
{
initializer: 'defineResultList',
samplePaths: {},
},
{
initializer: 'defineResultsPerPage',
samplePaths: {},
},
{
initializer: 'defineSearchBox',
samplePaths: {},
},
{
initializer: 'defineSearchParameterManager',
samplePaths: {},
},
{
initializer: 'defineSearchStatus',
samplePaths: {},
},
{
initializer: 'defineSmartSnippet',
samplePaths: {},
},
{
initializer: 'defineSmartSnippetQuestionsList',
samplePaths: {},
},
{
initializer: 'defineSort',
samplePaths: {},
},
{
initializer: 'defineStandaloneSearchBox',
samplePaths: {},
},
{
initializer: 'defineStaticFilter',
samplePaths: {},
},
{
initializer: 'defineTab',
samplePaths: {},
},
{
initializer: 'defineNotifyTrigger',
samplePaths: {},
},
{
initializer: 'defineExecuteTrigger',
samplePaths: {},
},
{
initializer: 'defineQueryTrigger',
samplePaths: {},
},
{
initializer: 'defineRedirectionTrigger',
samplePaths: {},
},
{
initializer: 'defineRecentResultsList',
samplePaths: {},
},
];

const actionLoaders: ActionLoaderConfiguration[] = [];

const engine: EngineConfiguration = {
initializer: 'defineSearchEngine',
};

export const ssrSearchUseCase = {controllers, actionLoaders, engine};
36 changes: 18 additions & 18 deletions packages/headless/src/app/search-engine/search-engine.ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,15 @@ import {
} from './search-engine';

/**
* @internal
* The SSR search engine.
*/
export interface SSRSearchEngine extends SearchEngine {
/**
* Waits for the search to be completed and returns a promise that resolves to a `SearchCompletedAction`.
*/
waitForSearchCompletedAction(): Promise<SearchCompletedAction>;
}

/**
* @internal
*/
export type SearchEngineDefinition<
TControllers extends ControllerDefinitionsMap<SSRSearchEngine, Controller>,
> = EngineDefinition<SSRSearchEngine, TControllers, SearchEngineOptions>;

/**
* @internal
*/
export type SearchEngineDefinitionOptions<
TControllers extends ControllerDefinitionsMap<SSRSearchEngine, Controller>,
> = EngineDefinitionOptions<SearchEngineOptions, TControllers>;
Expand Down Expand Up @@ -74,22 +67,29 @@ function buildSSRSearchEngine(options: SearchEngineOptions): SSRSearchEngine {
};
}

export interface SearchEngineDefinition<
TControllers extends ControllerDefinitionsMap<SSRSearchEngine, Controller>,
> extends EngineDefinition<
SSRSearchEngine,
TControllers,
SearchEngineOptions
> {}

/**
* @internal
*
* Initializes a Search engine definition in SSR with given controllers definitions and search engine config.
* @returns Three utility functions to fetch initial state of engine in SSR, hydrate the state in CSR
* @param options - The search engine definition
* @returns Three utility functions to fetch the initial state of the engine in SSR, hydrate the state in CSR,
* and a build function that can be used for edge cases requiring more control.
*/
export function defineSearchEngine<
TControllerDefinitions extends ControllerDefinitionsMap<
SearchEngine,
Controller
>,
>({
controllers: controllerDefinitions,
...engineOptions
}: SearchEngineDefinitionOptions<TControllerDefinitions>): SearchEngineDefinition<TControllerDefinitions> {
>(
options: SearchEngineDefinitionOptions<TControllerDefinitions>
): SearchEngineDefinition<TControllerDefinitions> {
const {controllers: controllerDefinitions, ...engineOptions} = options;
type Definition = SearchEngineDefinition<TControllerDefinitions>;
type BuildFunction = Definition['build'];
type FetchStaticStateFunction = Definition['fetchStaticState'];
Expand Down
32 changes: 14 additions & 18 deletions packages/headless/src/app/ssr-engine/types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,40 +42,42 @@ export interface ControllerStaticState<TState> {
export interface ControllerStaticStateMap {
[customName: string]: ControllerStaticState<unknown>;
}
/**
* @internal
*/

export interface ControllerDefinitionWithoutProps<
TEngine extends CoreEngine,
TController extends Controller,
> {
/**
* Creates an instance of the given controller.
*
* @param engine - The search engine.
* @returns The controller.
*/
build(engine: TEngine): TController;
}

/**
* @internal
*/
export interface ControllerDefinitionWithProps<
TEngine extends CoreEngine,
TController extends Controller,
TProps,
> {
/**
* Creates an instance of the given controller.
*
* @param engine - The search engine.
* @param props - The controller properties.
* @returns The controller.
*/
buildWithProps(engine: TEngine, props: TProps): TController;
}

/**
* @internal
*/
export type ControllerDefinition<
TEngine extends CoreEngine,
TController extends Controller,
> =
| ControllerDefinitionWithoutProps<TEngine, TController>
| ControllerDefinitionWithProps<TEngine, TController, unknown>;

/**
* @internal
*/
export interface ControllerDefinitionsMap<
TEngine extends CoreEngine,
TController extends Controller,
Expand Down Expand Up @@ -130,19 +132,13 @@ export type InferControllerPropsMapFromDefinitions<
: K]: InferControllerPropsFromDefinition<TControllers[K]>;
};

/**
* @internal
*/
export type InferControllerFromDefinition<
TDefinition extends ControllerDefinition<CoreEngine, Controller>,
> =
TDefinition extends ControllerDefinition<infer _, infer TController>
? TController
: never;

/**
* @internal
*/
export type InferControllersMapFromDefinition<
TControllers extends ControllerDefinitionsMap<CoreEngine, Controller>,
> = {[K in keyof TControllers]: InferControllerFromDefinition<TControllers[K]>};
Expand Down
Loading

0 comments on commit efbbcc2

Please sign in to comment.