Skip to content

Commit

Permalink
fix(headless,headless-react): make ssr terminology more consistent (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
btaillon-coveo authored Sep 13, 2023
1 parent d700a24 commit 91755ea
Show file tree
Hide file tree
Showing 23 changed files with 245 additions and 229 deletions.
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> {
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

0 comments on commit 91755ea

Please sign in to comment.