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

feat(react): add addUrlForHydration and integrate into FeatureAppLoader #320

Merged
merged 1 commit into from
Jan 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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