Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(headless,headless-react): make ssr terminology more consistent #3159

Merged
merged 9 commits into from
Sep 13, 2023
68 changes: 34 additions & 34 deletions packages/headless-react/src/search-engine.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,25 @@ describe('Headless react SSR utils', () => {

test('defines react search engine', () => {
const {
fetchInitialState,
hydrateInitialState,
fetchStaticState,
hydrateStaticState,
build,
useEngine,
controllers,
SSRStateProvider,
CSRProvider,
StaticStateProvider,
HydratedStateProvider,
...rest
} = defineSearchEngine({
configuration: sampleConfig,
});

[
fetchInitialState,
hydrateInitialState,
fetchStaticState,
hydrateStaticState,
build,
useEngine,
SSRStateProvider,
CSRProvider,
StaticStateProvider,
HydratedStateProvider,
].forEach((returnValue) => expect(typeof returnValue).toBe('function'));

expect(controllers).toEqual({});
Expand All @@ -66,10 +66,10 @@ describe('Headless react SSR utils', () => {
controllers: {resultList: defineResultList()},
});
const {
fetchInitialState,
hydrateInitialState,
SSRStateProvider,
CSRProvider,
fetchStaticState,
hydrateStaticState,
StaticStateProvider,
HydratedStateProvider,
controllers,
useEngine,
} = engineDefinition;
Expand Down Expand Up @@ -120,25 +120,25 @@ describe('Headless react SSR utils', () => {
);
});

test('should render with SSRProvider', async () => {
const ssrState = await fetchInitialState();
test('should render with StaticStateProvider', async () => {
const staticState = await fetchStaticState();
render(
<SSRStateProvider controllers={ssrState.controllers}>
<StaticStateProvider controllers={staticState.controllers}>
<TestResultList />
</SSRStateProvider>
</StaticStateProvider>
);

await checkRenderedResultList();
});

test('should hydrate results with CSRProvider', async () => {
const ssrState = await fetchInitialState();
const {engine, controllers} = await hydrateInitialState(ssrState);
test('should hydrate results with HydratedStateProvider', async () => {
const staticState = await fetchStaticState();
const {engine, controllers} = await hydrateStaticState(staticState);

render(
<CSRProvider engine={engine} controllers={controllers}>
<HydratedStateProvider engine={engine} controllers={controllers}>
<TestResultList />
</CSRProvider>
</HydratedStateProvider>
);

await checkRenderedResultList();
Expand All @@ -152,35 +152,35 @@ describe('Headless react SSR utils', () => {
);
});

test('should not return engine with SSRProvider', async () => {
const ssrState = await fetchInitialState();
function ssrStateProviderWrapper({children}: PropsWithChildren) {
test('should not return engine with StaticStateProvider', async () => {
const staticState = await fetchStaticState();
function staticStateProviderWrapper({children}: PropsWithChildren) {
return (
<SSRStateProvider controllers={ssrState.controllers}>
<StaticStateProvider controllers={staticState.controllers}>
{children}
</SSRStateProvider>
</StaticStateProvider>
);
}

const {result} = renderHook(() => useEngine(), {
wrapper: ssrStateProviderWrapper,
wrapper: staticStateProviderWrapper,
});
expect(result.current).toBeUndefined();
});

test('should return engine with CSRProvider', async () => {
const ssrState = await fetchInitialState();
const {engine, controllers} = await hydrateInitialState(ssrState);
function csrStateProviderWrapper({children}: PropsWithChildren) {
test('should return engine with HydratedStateProvider', async () => {
const staticState = await fetchStaticState();
const {engine, controllers} = await hydrateStaticState(staticState);
function hydratedStateProviderWrapper({children}: PropsWithChildren) {
return (
<CSRProvider controllers={controllers} engine={engine}>
<HydratedStateProvider controllers={controllers} engine={engine}>
{children}
</CSRProvider>
</HydratedStateProvider>
);
}

const {result} = renderHook(() => useEngine(), {
wrapper: csrStateProviderWrapper,
wrapper: hydratedStateProviderWrapper,
});
expect(result.current).toStrictEqual(engine);
});
Expand Down
24 changes: 13 additions & 11 deletions packages/headless-react/src/search-engine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {useContext, useCallback, useMemo, Context} from 'react';
import React from 'react';
import {useSyncMemoizedStore} from './client-utils';
import {
ContextCSRState,
ContextHydratedState,
ContextState,
ControllerHook,
InferControllerHooksMapFromDefinition,
Expand All @@ -20,7 +20,7 @@ import {SingletonGetter, capitalize, singleton, mapObject} from './utils';

export class MissingEngineProviderError extends Error {
static message =
'Unable to find Context. Please make sure you are wrapping your component with either `SSRStateProvider` or `CSRProvider` component that can provide the required context.';
'Unable to find Context. Please make sure you are wrapping your component with either `StaticStateProvider` or `HydratedStateProvider` component that can provide the required context.';
constructor() {
super(MissingEngineProviderError.message);
}
Expand All @@ -35,12 +35,12 @@ export function createSingletonContext<
);
}

function isCSRContext<
function isHydratedStateContext<
TEngine extends CoreEngine,
TControllers extends ControllerDefinitionsMap<TEngine, Controller>,
>(
ctx: ContextState<TEngine, TControllers>
): ctx is ContextCSRState<TEngine, TControllers> {
): ctx is ContextHydratedState<TEngine, TControllers> {
btaillon-coveo marked this conversation as resolved.
Show resolved Hide resolved
return 'engine' in ctx;
}

Expand All @@ -61,13 +61,15 @@ function buildControllerHook<
}
const subscribe = useCallback(
(listener: () => void) =>
isCSRContext(ctx) ? ctx.controllers[key].subscribe(listener) : () => {},
isHydratedStateContext(ctx)
? ctx.controllers[key].subscribe(listener)
: () => {},
[ctx]
);
const getSSRState = useCallback(() => ctx.controllers[key].state, [ctx]);
const state = useSyncMemoizedStore(subscribe, getSSRState);
const getStaticState = useCallback(() => ctx.controllers[key].state, [ctx]);
const state = useSyncMemoizedStore(subscribe, getStaticState);
const methods = useMemo(() => {
if (!isCSRContext(ctx)) {
if (!isHydratedStateContext(ctx)) {
return undefined;
}
const controller = ctx.controllers[key];
Expand Down Expand Up @@ -98,7 +100,7 @@ export function defineSearchEngine<
if (ctx === null) {
throw new MissingEngineProviderError();
}
return isCSRContext(ctx) ? ctx.engine : undefined;
return isHydratedStateContext(ctx) ? ctx.engine : undefined;
},
controllers: (options.controllers
? Object.fromEntries(
Expand All @@ -108,11 +110,11 @@ export function defineSearchEngine<
])
)
: {}) as InferControllerHooksMapFromDefinition<TControllers>,
SSRStateProvider: ({controllers, children}) => {
StaticStateProvider: ({controllers, children}) => {
const {Provider} = singletonContext.get();
return <Provider value={{controllers}}>{children}</Provider>;
},
CSRProvider: ({controllers, engine, children}) => {
HydratedStateProvider: ({controllers, engine, children}) => {
const {Provider} = singletonContext.get();
return <Provider value={{engine, controllers}}>{children}</Provider>;
},
Expand Down
18 changes: 9 additions & 9 deletions packages/headless-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import {InferControllerFromDefinition} from '@coveo/headless/dist/definitions/ap
import {
ControllerDefinitionsMap,
InferControllersMapFromDefinition,
InferControllerSSRStateMapFromDefinitions,
InferControllerStaticStateMapFromDefinitions,
EngineDefinition,
} from '@coveo/headless/ssr';
import {FunctionComponent, PropsWithChildren} from 'react';

export type ContextSSRState<
export type ContextStaticState<
TEngine extends CoreEngine,
TControllers extends ControllerDefinitionsMap<TEngine, Controller>,
> = {controllers: InferControllerSSRStateMapFromDefinitions<TControllers>};
> = {controllers: InferControllerStaticStateMapFromDefinitions<TControllers>};

export type ContextCSRState<
export type ContextHydratedState<
TEngine extends CoreEngine,
TControllers extends ControllerDefinitionsMap<TEngine, Controller>,
> = {
Expand All @@ -30,8 +30,8 @@ export type ContextState<
TEngine extends CoreEngine,
TControllers extends ControllerDefinitionsMap<TEngine, Controller>,
> =
| ContextSSRState<TEngine, TControllers>
| ContextCSRState<TEngine, TControllers>;
| ContextStaticState<TEngine, TControllers>
| ContextHydratedState<TEngine, TControllers>;

export type ControllerHook<TController extends Controller> = () => {
state: TController['state'];
Expand All @@ -53,12 +53,12 @@ export type ReactEngineDefinition<
> = EngineDefinition<TEngine, TControllers, TEngineOptions> & {
controllers: InferControllerHooksMapFromDefinition<TControllers>;
useEngine(): TEngine | undefined;
SSRStateProvider: FunctionComponent<
StaticStateProvider: FunctionComponent<
PropsWithChildren<{
controllers: InferControllerSSRStateMapFromDefinitions<TControllers>;
controllers: InferControllerStaticStateMapFromDefinitions<TControllers>;
}>
>;
CSRProvider: FunctionComponent<
HydratedStateProvider: FunctionComponent<
PropsWithChildren<{
engine: TEngine;
controllers: InferControllersMapFromDefinition<TControllers>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ describe('SSR', () => {
});

it('returns 3 functions', () => {
const {build, fetchInitialState, hydrateInitialState} = engineDefinition;
const {build, fetchStaticState, hydrateStaticState} = engineDefinition;
expect(typeof build).toBe('function');
expect(typeof fetchInitialState).toBe('function');
expect(typeof hydrateInitialState).toBe('function');
expect(typeof fetchStaticState).toBe('function');
expect(typeof hydrateStaticState).toBe('function');
});

it('fetches initial state of engine', async () => {
const {fetchInitialState} = engineDefinition;
const engineSSRState = await fetchInitialState();
expect(engineSSRState).toBeTruthy();
const {fetchStaticState} = engineDefinition;
const engineStaticState = await fetchStaticState();
expect(engineStaticState).toBeTruthy();
});

it('hydrates engine and fetches results using hydrated engine', async () => {
const {fetchInitialState, hydrateInitialState} = engineDefinition;
const engineSSRState = await fetchInitialState();
const {engine} = await hydrateInitialState(engineSSRState);
const {fetchStaticState, hydrateStaticState} = engineDefinition;
const engineStaticState = await fetchStaticState();
const {engine} = await hydrateStaticState(engineStaticState);
expect(engine.state.configuration.organizationId).toEqual(
getSampleSearchEngineConfiguration().organizationId
);
Expand Down
28 changes: 14 additions & 14 deletions packages/headless/src/app/search-engine/search-engine.ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {EngineDefinitionBuildOptionsWithProps} from '../ssr-engine/types/build';
import {
ControllerDefinitionsMap,
ControllersMap,
EngineSSRState,
InferControllerSSRStateMapFromDefinitions,
EngineStaticState,
InferControllerStaticStateMapFromDefinitions,
InferControllersMapFromDefinition,
OptionsExtender,
} from '../ssr-engine/types/common';
Expand Down Expand Up @@ -84,26 +84,26 @@ export function defineSearchEngine<
};
};

const fetchInitialState: SearchEngineDefinition<TControllerDefinitions>['fetchInitialState'] =
const fetchStaticState: SearchEngineDefinition<TControllerDefinitions>['fetchStaticState'] =
(
...[executeOptions]: Parameters<
SearchEngineDefinition<TControllerDefinitions>['fetchInitialState']
SearchEngineDefinition<TControllerDefinitions>['fetchStaticState']
>
) =>
new Promise<
EngineSSRState<
EngineStaticState<
{type: string},
InferControllerSSRStateMapFromDefinitions<TControllerDefinitions>
InferControllerStaticStateMapFromDefinitions<TControllerDefinitions>
>
>((resolve, reject) => {
let initialControllers: ControllersMap;
let staticControllers: ControllersMap;
const middleware: Middleware = () => (next) => (action) => {
next(action);
if (action.type === 'search/executeSearch/fulfilled') {
resolve({
controllers: mapObject(initialControllers, (controller) => ({
controllers: mapObject(staticControllers, (controller) => ({
state: controller.state,
})) as InferControllerSSRStateMapFromDefinitions<TControllerDefinitions>,
})) as InferControllerStaticStateMapFromDefinitions<TControllerDefinitions>,
searchFulfilledAction: JSON.parse(JSON.stringify(action)),
});
}
Expand All @@ -123,15 +123,15 @@ export function defineSearchEngine<
controllers: executeOptions.controllers,
}),
}).then(({engine, controllers}) => {
initialControllers = controllers;
staticControllers = controllers;
engine.executeFirstSearch();
});
});

const hydrateInitialState: SearchEngineDefinition<TControllerDefinitions>['hydrateInitialState'] =
const hydrateStaticState: SearchEngineDefinition<TControllerDefinitions>['hydrateStaticState'] =
async (
...[hydrateOptions]: Parameters<
SearchEngineDefinition<TControllerDefinitions>['hydrateInitialState']
SearchEngineDefinition<TControllerDefinitions>['hydrateStaticState']
>
) => {
const {engine, controllers} = await build(
Expand All @@ -150,7 +150,7 @@ export function defineSearchEngine<

return {
build,
fetchInitialState,
hydrateInitialState,
fetchStaticState,
hydrateStaticState,
};
}
6 changes: 3 additions & 3 deletions packages/headless/src/app/ssr-engine/types/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {CoreEngine} from '../../engine';
import {
ControllersMap,
ControllersPropsMap,
EngineAndControllers,
HydratedState,
OptionsExtender,
} from './common';

Expand Down Expand Up @@ -31,7 +31,7 @@ export interface BuildWithProps<
TEngineOptions,
TControllersProps
>
): Promise<EngineAndControllers<TEngine, TControllersMap>>;
): Promise<HydratedState<TEngine, TControllersMap>>;
}

export interface BuildWithoutProps<
Expand All @@ -44,5 +44,5 @@ export interface BuildWithoutProps<
*/
build(
options?: EngineDefinitionBuildOptionsWithoutProps<TEngineOptions>
): Promise<EngineAndControllers<TEngine, TControllersMap>>;
): Promise<HydratedState<TEngine, TControllersMap>>;
}
Loading
Loading