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

feature(SSR): 支持通过导出metadataLoader()设置页面的TDK等meta信息 #11833

Merged
merged 59 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
53f38f2
fix: dev环境构建SSR server.js时,环境判断错误导致输出的dev产物带上了hash
Oct 8, 2023
7f6d6d5
Update packages/preset-umi/src/features/ssr/webpack/webpack.ts
gwuhaolin Oct 8, 2023
5d004a1
fix: dev环境构建SSR server.js时,环境判断错误导致输出的dev产物带上了hash
Oct 8, 2023
3fc62cf
Merge branch 'umijs:master' into master
gwuhaolin Oct 9, 2023
5b0946a
feature: 支持自定义SSR构建目标,默认为node,可配置为webworker以支持运行在类似Cloudflare Workers的平台
Oct 9, 2023
7fe8bdc
feature: getManifest支持传入sourceDir表示SSR产物目录
Oct 9, 2023
542304a
feature: getManifest支持传入sourceDir表示SSR产物目录
Oct 9, 2023
335e6a6
fix: rendertoreadablestream is not a function
Oct 9, 2023
e7fb0c1
Revert "feature: 支持自定义SSR构建目标,默认为node,可配置为webworker以支持运行在类似Cloudflare…
Oct 9, 2023
64a9a42
fix: rendertoreadablestream is not a function
Oct 9, 2023
bfcd087
Update packages/server/src/ssr.ts
gwuhaolin Oct 10, 2023
d1a6e33
Update packages/server/src/ssr.ts
gwuhaolin Oct 10, 2023
e9ced7f
fix: 还原g_getAssets
Oct 10, 2023
a496ec7
Merge branch 'umijs:master' into master
gwuhaolin Oct 10, 2023
1ab01c4
fix: 被执行时才调用getManifest(),避免在入口立即调用getManifest()
Oct 10, 2023
af6b87f
fix: 被执行时才调用getManifest(),避免在入口立即调用getManifest()
Oct 10, 2023
aceacd1
fix: 被执行时才调用getManifest(),避免在入口立即调用getManifest()
Oct 10, 2023
0f9f649
Merge branch 'umijs:master' into master
gwuhaolin Oct 11, 2023
a55b708
feature: SSR模式下,多输出一份和index.html完全一致的*.html文件,用于ER场景
Oct 11, 2023
d572247
feature: SSR模式下,多输出一份和index.html完全一致的*.html文件,用于ER场景
Oct 11, 2023
ac8bf17
fix: SSR withoutHTML模式下,包一层<div id="root">{app}</div>
Oct 11, 2023
f5dfd89
Merge branch 'umijs:master' into master
gwuhaolin Oct 11, 2023
38ad928
Merge branch 'umijs:master' into master
gwuhaolin Oct 13, 2023
0a165a5
fix: 回滚SSR模式下,多输出一份和index.html完全一致的*.html文件,用于ER场景
Oct 13, 2023
8965465
Merge branch 'umijs:master' into master
gwuhaolin Oct 13, 2023
2bc9ad8
fix: SSR withoutHTML模式下也需要注入loaderData数据用于注水时
Oct 13, 2023
335fc09
fix: 在有basename的情况下__serverLoader的请求路径需要加上basename
Oct 14, 2023
c47a03c
Merge branch 'umijs:master' into master
gwuhaolin Oct 14, 2023
9ed9906
Merge branch 'umijs:master' into master
gwuhaolin Oct 17, 2023
f6c557f
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 18, 2023
6c7458f
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 18, 2023
d9eec13
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 18, 2023
b2eab5c
fix: async 函数返回值不需要 await ,不然会多造成一次异步成本。
Oct 18, 2023
2a7ac13
fix: 在请求__serverLoader时,带上cookie,以实现在SSR时请求需要登入态的接口
Oct 18, 2023
78d7be9
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 18, 2023
dfd4b15
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 18, 2023
26e3276
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 18, 2023
7530f81
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 18, 2023
7ff8d65
Merge branch 'umijs:master' into master
gwuhaolin Oct 19, 2023
1b4bff2
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 19, 2023
73fe5ed
fix: dumi 里做 ssg 时传的 path 是不带 host 的,需要加上host
Oct 19, 2023
105306d
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 19, 2023
54119dc
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 19, 2023
4c9e80e
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 19, 2023
808c8d1
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 19, 2023
9f54ac6
feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers
Oct 19, 2023
7ca9d75
Merge branch 'umijs:master' into master
gwuhaolin Nov 2, 2023
5c5905e
fix: 防止多chunk情况下(有懒加载时)的文件名冲突报错
Nov 2, 2023
be1cb28
fix: 防止多chunk情况下(有懒加载时)的文件名冲突报错
Nov 2, 2023
09407ad
Update packages/preset-umi/src/features/ssr/webpack/webpack.ts
sorrycc Nov 2, 2023
05f2c08
Merge branch 'umijs:master' into master
gwuhaolin Nov 3, 2023
0d912a0
Merge branch 'umijs:master' into master
gwuhaolin Nov 6, 2023
ac21a1f
feature(SSR): 支持通过导出metadataLoader()设置页面的TDK等meta信息
Nov 6, 2023
8e62386
feature(SSR): 支持通过导出metadataLoader()设置页面的TDK等meta信息
Nov 7, 2023
de44ea7
feature(SSR): 支持通过导出metadataLoader()设置页面的TDK等meta信息
Nov 7, 2023
7a7f1a8
Merge branch 'master' into master
gwuhaolin Nov 7, 2023
2e7b74b
feature(SSR): 支持通过导出metadataLoader()设置页面的TDK等meta信息
Nov 7, 2023
b46fac8
feature(SSR): 支持通过导出metadataLoader()设置页面的TDK等meta信息
Nov 7, 2023
c7df640
chore: export types and format
fz6m Nov 7, 2023
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
1 change: 1 addition & 0 deletions packages/preset-umi/src/features/tmpFiles/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export async function getRoutes(opts: {
: [];
if (enableSSR) {
routes[id].hasServerLoader = exports.includes('serverLoader');
routes[id].hasMetadataLoader = exports.includes('metadataLoader');
}
if (enableClientLoader && exports.includes('clientLoader')) {
routes[id].clientLoader = `clientLoaders['${id}']`;
Expand Down
44 changes: 25 additions & 19 deletions packages/renderer-react/src/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@ import { Routes } from './browser';
import { createClientRoutes } from './routes';
import { IRouteComponents, IRoutesById } from './types';

// Get the root React component for ReactDOMServer.renderToString
export async function getClientRootComponent(opts: {
interface IMetadata {
title?: string;
description?: string;
keywords?: string[];
lang?: string;
metas?: Array<{name: string; content: string}>;
}

interface IHtmlProps {
routes: IRoutesById;
routeComponents: IRouteComponents;
pluginManager: any;
location: string;
loaderData: { [routeKey: string]: any };
manifest: any;
withoutHTML?: boolean;
}) {
metadata?: IMetadata;
}

// Get the root React component for ReactDOMServer.renderToString
export async function getClientRootComponent(opts: IHtmlProps) {
const basename = '/';
const components = { ...opts.routeComponents };
const clientRoutes = createClientRoutes({
Expand Down Expand Up @@ -57,37 +67,33 @@ export async function getClientRootComponent(opts: {
{rootContainer}
</AppContext.Provider>
);
if (opts.withoutHTML) {
return <>
<div id="root">{app}</div>
<script
dangerouslySetInnerHTML={{
__html: `window.__UMI_LOADER_DATA__ = ${JSON.stringify(
opts.loaderData,
)}`,
}}
/>
</>;
}
return (
<Html loaderData={opts.loaderData} manifest={opts.manifest}>
<Html {...opts}>
{app}
</Html>
);
}

function Html({ children, loaderData, manifest }: any) {
function Html({ children, loaderData, manifest, metadata }: IHtmlProps & { children: React.ReactNode }) {
gwuhaolin marked this conversation as resolved.
Show resolved Hide resolved
// TODO: 处理 head 标签,比如 favicon.ico 的一致性
// TODO: root 支持配置

return (
<html lang="en">
<html lang={metadata?.lang}>
gwuhaolin marked this conversation as resolved.
Show resolved Hide resolved
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{manifest.assets['umi.css'] && (
<link rel="stylesheet" href={manifest.assets['umi.css']} />
)}
{metadata?.title && <title>{metadata.title}</title>}
{metadata?.description && (
<meta name="description" content={metadata.description} />
)}
{metadata?.keywords?.length && (
<meta name="keywords" content={metadata.keywords.join(',')} />
)}
{metadata?.metas?.map((em)=> <meta name={em.name} content={em.content}/>)}
gwuhaolin marked this conversation as resolved.
Show resolved Hide resolved
</head>
<body>
<noscript
Expand Down
28 changes: 26 additions & 2 deletions packages/server/src/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ interface CreateRequestHandlerOptions {
createHistory: (opts: any) => any;
helmetContext?: any;
ServerInsertedHTMLContext: React.Context<ServerInsertedHTMLHook | null>;
withoutHTML?: boolean;
sourceDir?: string;
}

Expand Down Expand Up @@ -89,6 +88,7 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) {
}

const loaderData: { [key: string]: any } = {};
const metadata: { [key: string]: any } = {};
gwuhaolin marked this conversation as resolved.
Show resolved Hide resolved
await Promise.all(
matches
.filter((id: string) => routes[id].hasServerLoader)
Expand All @@ -100,6 +100,17 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) {
routesWithServerLoader,
serverLoaderArgs,
);
// 如果有metadataLoader,执行metadataLoader
// metadataLoader在serverLoader返回之后执行这样metadataLoader可以使用serverLoader的返回值
// 如果有多层嵌套路由和合并多层返回的metadata但最里层的优先级最高
if(routes[id].hasMetadataLoader) {
Object.assign(metadata, await executeMetadataLoader(
id,
routesWithServerLoader,
serverLoaderArgs,
loaderData[id],
));
}
resolve();
}),
),
Expand All @@ -116,7 +127,7 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) {
location: url,
manifest,
loaderData,
withoutHTML: opts.withoutHTML,
gwuhaolin marked this conversation as resolved.
Show resolved Hide resolved
metadata,
};

const element = (await opts.getClientRootComponent(
Expand Down Expand Up @@ -333,3 +344,16 @@ async function executeLoader(
// TODO: 处理错误场景
return mod.serverLoader(serverLoaderArgs);
}

async function executeMetadataLoader(
routeKey: string,
routesWithServerLoader: RouteLoaders,
serverLoaderArgs?: IServerLoaderArgs,
serverLoaderData?: any, // serverLoader的返回值
gwuhaolin marked this conversation as resolved.
Show resolved Hide resolved
) {
const mod = await routesWithServerLoader[routeKey]();
if (!mod.serverLoader || typeof mod.serverLoader !== 'function') {
return;
}
return mod.metadataLoader(serverLoaderArgs, serverLoaderData);
gwuhaolin marked this conversation as resolved.
Show resolved Hide resolved
}
Loading