Skip to content

Commit

Permalink
feat(demos): use addUrlForHydration for preloading in ssr demo (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
unstubbable authored and clebert committed Jan 31, 2019
1 parent c661c58 commit 770090a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 16 deletions.
15 changes: 15 additions & 0 deletions packages/demos/src/server-side-rendering/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {FeatureAppLoader} from '@feature-hub/react';
import * as React from 'react';

export interface AppProps {
readonly port?: number;
}

export function App({port}: AppProps): JSX.Element {
return (
<FeatureAppLoader
src="feature-app.umd.js"
serverSrc={port ? `http://localhost:${port}/feature-app.commonjs.js` : ''}
/>
);
}
26 changes: 19 additions & 7 deletions packages/demos/src/server-side-rendering/integrator.node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ import {
} from '@feature-hub/async-ssr-manager';
import {FeatureAppManager, FeatureServiceRegistry} from '@feature-hub/core';
import {loadCommonJsModule} from '@feature-hub/module-loader-commonjs';
import {FeatureAppLoader, FeatureHubContextProvider} from '@feature-hub/react';
import {
FeatureHubContextProvider,
FeatureHubContextValue
} from '@feature-hub/react';
import {
SerializedStateManagerV0,
serializedStateManagerDefinition
} from '@feature-hub/serialized-state-manager';
import * as React from 'react';
import * as ReactDOM from 'react-dom/server';
import {AppRendererOptions, AppRendererResult} from '../start-server';
import {App} from './app';

export default async function renderApp({
port
Expand Down Expand Up @@ -45,13 +49,21 @@ export default async function renderApp({
moduleLoader: loadCommonJsModule
});

const urlsForHydration = new Set<string>();

const featureHubContextValue: FeatureHubContextValue = {
featureAppManager,
asyncSsrManager,

addUrlForHydration(url: string): void {
urlsForHydration.add(url);
}
};

const html = await asyncSsrManager.renderUntilCompleted(() =>
ReactDOM.renderToString(
<FeatureHubContextProvider value={{featureAppManager, asyncSsrManager}}>
<FeatureAppLoader
src=""
serverSrc={`http://localhost:${port}/feature-app.commonjs.js`}
/>
<FeatureHubContextProvider value={featureHubContextValue}>
<App port={port} />
</FeatureHubContextProvider>
)
);
Expand All @@ -62,5 +74,5 @@ export default async function renderApp({

const serializedStates = serializedStateManager.serializeStates();

return {html, serializedStates};
return {html, serializedStates, urlsForHydration};
}
27 changes: 21 additions & 6 deletions packages/demos/src/server-side-rendering/integrator.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import {FeatureAppManager, FeatureServiceRegistry} from '@feature-hub/core';
import {defineExternals, loadAmdModule} from '@feature-hub/module-loader-amd';
import {FeatureAppLoader, FeatureHubContextProvider} from '@feature-hub/react';
import {FeatureHubContextProvider} from '@feature-hub/react';
import {
SerializedStateManagerV0,
serializedStateManagerDefinition
} from '@feature-hub/serialized-state-manager';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import '../blueprint-css';

const featureAppUrl = 'feature-app.umd.js';
import {App} from './app';

function getSerializedStatesFromDom(): string | undefined {
const scriptElement = document.querySelector(
Expand All @@ -19,6 +18,18 @@ function getSerializedStatesFromDom(): string | undefined {
return (scriptElement && scriptElement.textContent) || undefined;
}

function getUrlsForHydrationFromDom(): string[] {
const scriptElement = document.querySelector(
'script[type="x-feature-hub/urls-for-hydration"]'
);

if (!scriptElement || !scriptElement.textContent) {
return [];
}

return JSON.parse(scriptElement.textContent);
}

(async () => {
const integratorDefinition = {
id: 'test:integrator',
Expand Down Expand Up @@ -46,8 +57,6 @@ function getSerializedStatesFromDom(): string | undefined {

defineExternals({react: React});

await featureAppManager.preloadFeatureApp(featureAppUrl);

const serializedStateManager = featureServices[
serializedStateManagerDefinition.id
] as SerializedStateManagerV0;
Expand All @@ -58,9 +67,15 @@ function getSerializedStatesFromDom(): string | undefined {
serializedStateManager.setSerializedStates(serializedStates);
}

await Promise.all(
getUrlsForHydrationFromDom().map(async url =>
featureAppManager.preloadFeatureApp(url)
)
);

ReactDOM.hydrate(
<FeatureHubContextProvider value={{featureAppManager}}>
<FeatureAppLoader src={featureAppUrl} />
<App />
</FeatureHubContextProvider>,
document.querySelector('main')
);
Expand Down
24 changes: 21 additions & 3 deletions packages/demos/src/start-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface AppRendererOptions {
export interface AppRendererResult {
html: string;
serializedStates?: string;
urlsForHydration?: Set<string>;
}

export type AppRenderer = (
Expand All @@ -20,12 +21,20 @@ export type AppRenderer = (

function createDocumentHtml(
bodyHtml: string,
serializedStates?: string
serializedStates?: string,
urlsForHydration?: Set<string>
): string {
const serializedStatesScript = serializedStates
? `<script type="x-feature-hub/serialized-states">${serializedStates}</script>`
: '';

const urlsForHydrationScript =
urlsForHydration && urlsForHydration.size
? `<script type="x-feature-hub/urls-for-hydration">${JSON.stringify(
Array.from(urlsForHydration)
)}</script>`
: '';

return `
<html>
<head>
Expand All @@ -34,6 +43,7 @@ function createDocumentHtml(
<body>
${bodyHtml}
${serializedStatesScript}
${urlsForHydrationScript}
<script src="integrator.js"></script>
</body>
</html>
Expand All @@ -51,10 +61,18 @@ export async function startServer(
app.get('/', async (req, res) => {
try {
if (renderApp) {
const {html: appHtml, serializedStates} = await renderApp({port, req});
const {
html: appHtml,
serializedStates,
urlsForHydration
} = await renderApp({port, req});

res.send(
createDocumentHtml(`<main>${appHtml}</main>`, serializedStates)
createDocumentHtml(
`<main>${appHtml}</main>`,
serializedStates,
urlsForHydration
)
);
} else {
res.send(createDocumentHtml(`<main></main>`));
Expand Down

0 comments on commit 770090a

Please sign in to comment.