Skip to content

Commit

Permalink
feat: add client metadata hydrate data
Browse files Browse the repository at this point in the history
  • Loading branch information
Jinbao1001 committed Apr 1, 2024
1 parent f3ad7f5 commit c973bb7
Show file tree
Hide file tree
Showing 10 changed files with 47 additions and 62 deletions.
2 changes: 1 addition & 1 deletion examples/ssr-demo/.umirc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default {
scripts: [`https://a.com/b.js`],
ssr: {
builder: 'webpack',
hydrateFromHtml: true,
hydrateFromRoot: false,
},
styles: [`body { color: red; }`, `https://a.com/b.css`],

Expand Down
2 changes: 1 addition & 1 deletion packages/preset-umi/src/features/ssr/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default (api: IApi) => {
serverBuildPath: zod.string(),
platform: zod.string(),
builder: zod.enum(['esbuild', 'webpack']),
hydrateFromHtml: zod.boolean(),
hydrateFromRoot: zod.boolean(),
})
.deepPartial();
},
Expand Down
18 changes: 5 additions & 13 deletions packages/preset-umi/src/features/tmpFiles/tmpFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { importLazy, lodash, winPath } from '@umijs/utils';
import { existsSync, readdirSync } from 'fs';
import { basename, dirname, join } from 'path';
import { RUNTIME_TYPE_FILE_NAME } from 'umi';
import { getMarkupArgs } from '../../commands/dev/getMarkupArgs';
import { TEMPLATES_DIR } from '../../constants';
import { IApi } from '../../types';
import { getModuleExports } from './getModuleExports';
import { importsToStr } from './importsToStr';

const routesApi: typeof import('./routes') = importLazy(
require.resolve('./routes'),
);
Expand Down Expand Up @@ -496,16 +496,8 @@ if (process.env.NODE_ENV === 'development') {
}
return memo;
}, []);
const {
headScripts,
scripts,
styles,
title,
favicons,
links,
metas,
ssr,
} = api.config;
const { headScripts, scripts, styles, title, favicons, links, metas } =
await getMarkupArgs({ api });
api.writeTmpFile({
noPluginDir: true,
path: 'umi.server.ts',
Expand All @@ -531,9 +523,9 @@ if (process.env.NODE_ENV === 'development') {
favicons,
links,
metas,
scripts: scripts || [],
}),
scripts: JSON.stringify(scripts || []),
hydrateFromHtml: ssr?.hydrateFromHtml ?? true,
hydrateFromRoot: api.config.ssr?.hydrateFromRoot ?? false,
},
});
}
Expand Down
3 changes: 1 addition & 2 deletions packages/preset-umi/templates/server.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@ const createOpts = {
createHistory,
ServerInsertedHTMLContext,
metadata: {{{metadata}}},
scripts: {{{scripts}}},
hydrateFromHtml: {{{hydrateFromHtml}}}
hydrateFromRoot: {{{hydrateFromRoot}}}

};
const requestHandler = createRequestHandler(createOpts);
Expand Down
10 changes: 8 additions & 2 deletions packages/renderer-react/src/browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export type RenderClientOpts = {
* ssr 是否从 html 根节点开始 hydrate
* @doc 默认 true,从 html 开始渲染,false 时从 app root 开始
*/
hydrateFromHtml?: boolean;
hydrateFromRoot?: boolean;
/**
* 当前的路由配置
*/
Expand Down Expand Up @@ -336,13 +336,19 @@ const getBrowser = (
*/
export function renderClient(opts: RenderClientOpts) {
const rootElement = opts.rootElement || document.getElementById('root')!;

const Browser = getBrowser(opts, <Routes />);
// 为了测试,直接返回组件
if (opts.components) return Browser;
if (opts.hydrate) {
// @ts-ignore
const loaderData = window.__UMI_LOADER_DATA__ || {};
// @ts-ignore
const metadata = window.__UMI_METADATA_LOADER_DATA__ || {};

ReactDOM.hydrateRoot(
document,
<Html {...opts}>
<Html {...{ metadata, loaderData }}>
<Browser />
</Html>,
);
Expand Down
19 changes: 10 additions & 9 deletions packages/renderer-react/src/html.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,16 @@ export function Html({
/>

<div id="root">{children}</div>
{loaderData && (
<script
dangerouslySetInnerHTML={{
__html: `window.__UMI_LOADER_DATA__ = ${JSON.stringify(
loaderData,
)}`,
}}
/>
)}
<script
dangerouslySetInnerHTML={{
__html: `window.__UMI_LOADER_DATA__ = ${JSON.stringify(
loaderData || {},
)}; window.__UMI_METADATA_LOADER_DATA__ = ${JSON.stringify(
metadata,
)}`,
}}
/>

{metadata?.scripts?.map((script: IScript, key: number) => {
const { content, ...rest } = normalizeScripts(script);
return (
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer-react/src/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export async function getClientRootComponent(opts: IRootComponentOptions) {
{rootContainer}
</AppContext.Provider>
);
if (opts.hydrateFromHtml) {
if (!opts.hydrateFromRoot) {
return <Html {...opts}>{app}</Html>;
} else {
return app;
Expand Down
2 changes: 1 addition & 1 deletion packages/renderer-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export interface IRootComponentOptions {
loaderData: { [routeKey: string]: any };
manifest: any;
metadata?: IMetadata;
hydrateFromHtml: boolean;
hydrateFromRoot: boolean;
}

export interface IHtmlProps {
Expand Down
44 changes: 15 additions & 29 deletions packages/server/src/ssr.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/// <reference lib="webworker" />
import type { RequestHandler } from '@umijs/bundler-utils/compiled/express';
import mergeWith from 'lodash.mergewith';
import React, { ReactElement } from 'react';
import * as ReactDomServer from 'react-dom/server';
import { matchRoutes } from 'react-router-dom';
import { Writable } from 'stream';
import type {
IOpts,
IMetadata,
IRoutesById,
IServerLoaderArgs,
MetadataLoader,
Expand Down Expand Up @@ -40,9 +39,8 @@ interface CreateRequestHandlerOptions extends CreateRequestServerlessOptions {
createHistory: (opts: any) => any;
helmetContext?: any;
ServerInsertedHTMLContext: React.Context<ServerInsertedHTMLHook | null>;
metadata: IOpts;
scripts: IOpts['scripts'];
hydrateFromHtml: boolean;
metadata: IMetadata;
hydrateFromRoot: boolean;
}

interface IExecLoaderOpts {
Expand Down Expand Up @@ -112,7 +110,7 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) {
}

const loaderData: Record<string, any> = {};
let metadata: Record<string, any> = {};
// let metadata: Record<string, any> = {};
await Promise.all(
matches
.filter((id: string) => routes[id].hasServerLoader)
Expand All @@ -134,17 +132,13 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) {
serverLoaderArgs,
serverLoaderData: loaderData[id],
});

metadata = mergeWith(
metadataLoaderData,
opts.metadata,
(pre, next) => {
if (Array.isArray(pre) || Array.isArray(next)) {
return Array.prototype.concat.call(pre || [], next || []);
}
},
);
metadata.scripts = opts.scripts;
Object.entries(metadataLoaderData).forEach(([k, v]) => {
if (Array.isArray(v)) {
opts.metadata[k] = (opts.metadata[k] || []).concat(v);
} else {
opts.metadata[k] = v;
}
});
}
resolve();
}),
Expand All @@ -162,8 +156,8 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) {
location: url,
manifest,
loaderData,
metadata,
hydrateFromHtml: opts.hydrateFromHtml,
metadata: opts.metadata,
hydrateFromRoot: opts.hydrateFromRoot,
};

const element = (await opts.getClientRootComponent(
Expand Down Expand Up @@ -533,18 +527,10 @@ async function executeLoader(params: IExecLoaderOpts) {
}

async function executeMetadataLoader(params: IExecMetaLoaderOpts) {
const {
routesWithServerLoader,
routeKey,
serverLoaderArgs,
serverLoaderData,
} = params;
const { routesWithServerLoader, routeKey, serverLoaderData } = params;
const mod = await routesWithServerLoader[routeKey]();
if (!mod.serverLoader || typeof mod.serverLoader !== 'function') {
return;
}
return (mod.metadataLoader satisfies MetadataLoader)(
serverLoaderData,
serverLoaderArgs,
);
return (mod.metadataLoader satisfies MetadataLoader)(serverLoaderData);
}
7 changes: 4 additions & 3 deletions packages/server/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ export interface IMetadata {
*/
lang?: string;
metas?: IMetaTag[];
headScripts?: IOpts['headScripts'];
links?: IOpts['links'];
headScripts?: (Record<string, string> | string)[];
links?: Record<string, string>[];
styles?: string[];
favicons?: string[];
scripts?: IOpts['scripts'];
scripts?: (Record<string, string> | string)[];
[key: string]: any;
}
export type MetadataLoader<T = any> = (
serverLoaderData: T,
Expand Down

0 comments on commit c973bb7

Please sign in to comment.