Skip to content

Commit

Permalink
feat(react): add addUrlForHydration and integrate into FeatureAppLoad…
Browse files Browse the repository at this point in the history
…er (#320)
  • Loading branch information
unstubbable authored Jan 30, 2019
1 parent 420523a commit 9de6cf2
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 5 deletions.
30 changes: 29 additions & 1 deletion packages/react/src/__tests__/feature-app-loader.node.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('FeatureAppLoader (on Node.js)', () => {
let mockGetAsyncFeatureAppDefinition: jest.Mock;
let mockAsyncFeatureAppDefinition: AsyncValue<FeatureAppDefinition<unknown>>;
let mockAsyncSsrManager: MockAsyncSsrManager;
let mockAddUrlForHydration: jest.Mock;
let stubbedConsole: Stubbed<Console>;

beforeEach(() => {
Expand All @@ -50,6 +51,8 @@ describe('FeatureAppLoader (on Node.js)', () => {
renderUntilCompleted: jest.fn()
};

mockAddUrlForHydration = jest.fn();

stubbedConsole = stubMethods(console);
});

Expand All @@ -62,7 +65,8 @@ describe('FeatureAppLoader (on Node.js)', () => {
<FeatureHubContextProvider
value={{
featureAppManager: mockFeatureAppManager,
asyncSsrManager: mockAsyncSsrManager
asyncSsrManager: mockAsyncSsrManager,
addUrlForHydration: mockAddUrlForHydration
}}
>
{node}
Expand All @@ -81,6 +85,12 @@ describe('FeatureAppLoader (on Node.js)', () => {

expect(mockAsyncSsrManager.rerenderAfter).not.toHaveBeenCalled();
});

it('does not add a URL for hydration', () => {
renderWithFeatureHubContext(<FeatureAppLoader src="example.js" />);

expect(mockAddUrlForHydration).not.toHaveBeenCalled();
});
});

describe('with a serverSrc', () => {
Expand All @@ -104,6 +114,14 @@ describe('FeatureAppLoader (on Node.js)', () => {
]);
});

it('adds the src URL for hydration', () => {
renderWithFeatureHubContext(
<FeatureAppLoader src="example.js" serverSrc="example-node.js" />
);

expect(mockAddUrlForHydration).toHaveBeenCalledWith('example.js');
});

describe('when a Feature App definition is synchronously available', () => {
let mockFeatureAppDefinition: FeatureAppDefinition<unknown>;

Expand Down Expand Up @@ -163,6 +181,16 @@ describe('FeatureAppLoader (on Node.js)', () => {

expect(mockAsyncSsrManager.rerenderAfter).not.toHaveBeenCalled();
});

it('adds the src URL for hydration', () => {
try {
renderWithFeatureHubContext(
<FeatureAppLoader src="example.js" serverSrc="example-node.js" />
);
} catch {}

expect(mockAddUrlForHydration).toHaveBeenCalledWith('example.js');
});
});
});
});
22 changes: 21 additions & 1 deletion packages/react/src/__tests__/feature-app-loader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('FeatureAppLoader', () => {
let mockGetAsyncFeatureAppDefinition: jest.Mock;
let mockAsyncFeatureAppDefinition: AsyncValue<FeatureAppDefinition<unknown>>;
let mockAsyncSsrManager: MockAsyncSsrManager;
let mockAddUrlForHydration: jest.Mock;
let stubbedConsole: Stubbed<Console>;

beforeEach(() => {
Expand Down Expand Up @@ -52,6 +53,8 @@ describe('FeatureAppLoader', () => {
renderUntilCompleted: jest.fn()
};

mockAddUrlForHydration = jest.fn();

stubbedConsole = stubMethods(console);
});

Expand All @@ -74,7 +77,8 @@ describe('FeatureAppLoader', () => {
<FeatureHubContextProvider
value={{
featureAppManager: mockFeatureAppManager,
asyncSsrManager: mockAsyncSsrManager
asyncSsrManager: mockAsyncSsrManager,
addUrlForHydration: mockAddUrlForHydration
}}
>
{node}
Expand Down Expand Up @@ -166,6 +170,14 @@ describe('FeatureAppLoader', () => {

expect(mockAsyncSsrManager.rerenderAfter).not.toHaveBeenCalled();
});

it('does not add a URL for hydration', () => {
renderWithFeatureHubContext(
<FeatureAppLoader src="example.js" serverSrc="example-node.js" />
);

expect(mockAddUrlForHydration).not.toHaveBeenCalled();
});
});

describe('when the async Feature App definition synchronously has an error', () => {
Expand Down Expand Up @@ -240,6 +252,14 @@ describe('FeatureAppLoader', () => {
expect(mockAsyncSsrManager.rerenderAfter).not.toHaveBeenCalled();
});

it('does not add a URL for hydration', () => {
renderWithFeatureHubContext(
<FeatureAppLoader src="example.js" serverSrc="example-node.js" />
);

expect(mockAddUrlForHydration).not.toHaveBeenCalled();
});

describe('when unmounted before loading has finished', () => {
it('renders nothing', async () => {
const testRenderer = renderWithFeatureHubContext(
Expand Down
10 changes: 8 additions & 2 deletions packages/react/src/feature-app-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ class InternalFeatureAppLoader extends React.PureComponent<
featureAppManager,
src: browserSrc,
serverSrc,
asyncSsrManager
asyncSsrManager,
addUrlForHydration
} = props;

const src = inBrowser ? browserSrc : serverSrc;
Expand All @@ -77,6 +78,10 @@ class InternalFeatureAppLoader extends React.PureComponent<
return;
}

if (!inBrowser && addUrlForHydration) {
addUrlForHydration(browserSrc);
}

const asyncFeatureAppDefinition = featureAppManager.getAsyncFeatureAppDefinition(
src
);
Expand Down Expand Up @@ -202,10 +207,11 @@ class InternalFeatureAppLoader extends React.PureComponent<
export function FeatureAppLoader(props: FeatureAppLoaderProps): JSX.Element {
return (
<FeatureHubContextConsumer>
{({featureAppManager, asyncSsrManager}) => (
{({featureAppManager, asyncSsrManager, addUrlForHydration}) => (
<InternalFeatureAppLoader
featureAppManager={featureAppManager}
asyncSsrManager={asyncSsrManager}
addUrlForHydration={addUrlForHydration}
{...props}
/>
)}
Expand Down
15 changes: 14 additions & 1 deletion packages/react/src/feature-hub-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@ export interface FeatureHubContextValue {
* The `FeatureAppManager` singleton instance.
*/
featureAppManager: FeatureAppManagerLike;

/**
* The Async SSR Manager Feature Service that is bound to the integrator.
* The Async SSR Manager Feature Service that is bound to the integrator. It
* is only provided on the server.
*/
asyncSsrManager?: AsyncSsrManagerV0;

/**
* A callback that the integrator provides on the server, mainly for the
* {@link FeatureAppLoader}, to add browser URLs of those Feature Apps that
* are rendered on the server, so that they can be preloaded in the browser
* before hydration. Calling it more than once with the same URL must not have
* any impact.
*
* @param url The browser URL of a Feature App that is rendered on the server.
*/
addUrlForHydration?(url: string): void;
}

const dummyDefaultFeatureHubContextValue = {};
Expand Down

0 comments on commit 9de6cf2

Please sign in to comment.