Skip to content

Commit

Permalink
fix: 修复 getClientRootComponent 方法. 增加 ssr basename 案例
Browse files Browse the repository at this point in the history
  • Loading branch information
jaykou25 committed Jul 11, 2024
1 parent bbebea9 commit d39247c
Show file tree
Hide file tree
Showing 19 changed files with 247 additions and 49 deletions.
6 changes: 6 additions & 0 deletions examples/ssg-basename/.umirc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
exportStatic: {},
ssr: {},
base: '/base/',
publicPath: '/base/', // 布署时需要布署在 base 文件夹下.
};
14 changes: 14 additions & 0 deletions examples/ssg-basename/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "@example/ssg-basename",
"private": true,
"description": "该案例用于测试 ssg 预渲染. 当 umi 配置表中设置了 base 后, ssg 输出的预渲染页面中的 a 标签需要有正确的 base 前缀",
"scripts": {
"build": "umi build",
"dev": "umi dev",
"setup": "umi setup",
"start": "npm run dev"
},
"dependencies": {
"umi": "workspace:*"
}
}
14 changes: 14 additions & 0 deletions examples/ssg-basename/src/layouts/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

import { Outlet } from 'umi';

const Layout = () => {
return (
<div>
<div style={{ marginBottom: '10px' }}>HEADER</div>
<Outlet />
</div>
);
};

export default Layout;
24 changes: 24 additions & 0 deletions examples/ssg-basename/src/pages/about/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useState } from 'react';
import { Link } from 'umi';

const About = () => {
const [num, setNum] = useState(0);

return (
<div>
<div>
<strong>ABOUT</strong> page
<button
style={{ marginLeft: '5px' }}
onClick={() => setNum((val) => val + 1)}
>
couts: {num}
</button>
</div>
<br />
<Link to="/">to home</Link>
</div>
);
};

export default About;
24 changes: 24 additions & 0 deletions examples/ssg-basename/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useState } from 'react';
import { Link } from 'umi';

const Home = () => {
const [num, setNum] = useState(0);
return (
<div>
<div>
<strong>HOME</strong> page
<button
style={{ marginLeft: '5px' }}
onClick={() => setNum((val) => val + 1)}
>
couts: {num}
</button>
</div>

<br />
<Link to="/about">to about</Link>
</div>
);
};

export default Home;
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export default {
ssr: {},
exportStatic: {},
hash: true,
base: '/a/',
base: '/base/',
};
File renamed without changes.
37 changes: 37 additions & 0 deletions examples/ssr-basename/plugins/mylogger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { writeFileSync } from 'fs';
import { IApi } from 'umi';

export default (api: IApi) => {
api.describe({
key: 'mylogger',
config: {
schema(joi) {
return joi.string();
},
},
enableBy: api.EnableBy.register,
});

api.registerMethod({
name: 'mylogger',
fn: (pathname, obj) => {
let cache = [];
const str = JSON.stringify(obj, function (key, value) {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
// 移除
return;
}
// 收集所有的值
cache.push(value);
}
return value;
});
cache = null;

writeFileSync(pathname, str, () => {
console.log('write log finish');
});
},
});
};
28 changes: 28 additions & 0 deletions examples/ssr-basename/plugins/picker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { IApi } from 'umi';

export default (api: IApi) => {
api.describe({
key: 'routePicker',
config: {
schema({ zod }) {
return zod.array(zod.string());
},
},
enableBy: () => {
return api.name === 'dev';
},
});

console.log('插件 picker 注册');

api.onCheck(async () => {
// console.log('插件', api.appData.routes);
console.log('插件config', api.config);
api.config.routes = [
{
path: '/',
component: 'index',
},
];
});
};
14 changes: 14 additions & 0 deletions examples/ssr-basename/src/layouts/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

import { Outlet } from 'umi';

const Layout = () => {
return (
<div>
<div style={{ marginBottom: '10px' }}>HEADER</div>
<Outlet />
</div>
);
};

export default Layout;
3 changes: 3 additions & 0 deletions examples/ssr-basename/src/pages/about/form/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function AboutForm() {
return <div>About Form</div>;
}
24 changes: 24 additions & 0 deletions examples/ssr-basename/src/pages/about/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useState } from 'react';
import { Link } from 'umi';

const About = () => {
const [num, setNum] = useState(0);

return (
<div>
<div>
<strong>ABOUT</strong> page
<button
style={{ marginLeft: '5px' }}
onClick={() => setNum((val) => val + 1)}
>
couts: {num}
</button>
</div>
<br />
<Link to="/">to home</Link>
</div>
);
};

export default About;
24 changes: 24 additions & 0 deletions examples/ssr-basename/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useState } from 'react';
import { Link } from 'umi';

const Home = () => {
const [num, setNum] = useState(0);
return (
<div>
<div>
<strong>HOME</strong> page
<button
style={{ marginLeft: '5px' }}
onClick={() => setNum((val) => val + 1)}
>
couts: {num}
</button>
</div>

<br />
<Link to="/about">to about</Link>
</div>
);
};

export default Home;
15 changes: 0 additions & 15 deletions examples/ssr-export-static-basename/src/pages/about/index.tsx

This file was deleted.

15 changes: 0 additions & 15 deletions examples/ssr-export-static-basename/src/pages/index.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ function getExportHtmlData(routes: Record<string, IRoute>): IExportHtmlItem[] {
async function getPreRenderedHTML(api: IApi, htmlTpl: string, path: string) {
const {
exportStatic: { ignorePreRenderError = false },
base,
} = api.config;
markupRender ??= require(absServerBuildPath(api))._markupGenerator;

try {
const markup = await markupRender(path);
const location = `${base.endsWith('/') ? base.slice(0, -1) : base}${path}`;
const markup = await markupRender(location);
const [mainTpl, extraTpl = ''] = markup.split('</html>');
// TODO: improve return type for markup generator
const helmetContent = mainTpl.match(
Expand Down
11 changes: 5 additions & 6 deletions packages/renderer-react/src/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,12 @@ export async function getClientRootComponent(opts: IHtmlProps) {
routeComponents: components,
});

// If router has a basename, location should be concatenated with that basename
const finalLocation = `${
basename.endsWith('/') ? basename.slice(0, -1) : basename
}${opts.location}`;

let rootContainer = (
<StaticRouter basename={basename} location={finalLocation}>
// 这里的 location 需要包含 basename, 否则会影响 StaticRouter 的匹配.
// 由于 getClientRootComponent 方法会同时用于 ssr 和 ssg, 所以在调用该方法时需要注意传入的 location 是否包含 basename.
// 1. 在用于 ssr 时传入的 location 来源于 request.url, 它是包含 basename 的, 所以没有问题.
// 2. 但是在用于 ssg 时(static export), 需要注意传入的 locaiton 要拼接上 basename.
<StaticRouter basename={basename} location={opts.location}>
<Routes />
</StaticRouter>
);
Expand Down
17 changes: 14 additions & 3 deletions packages/server/src/ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) {
},
});

const matches = matchRoutesForSSR(url, routes);
const matches = matchRoutesForSSR(url, routes, basename);

if (matches.length === 0) {
return;
}
Expand Down Expand Up @@ -336,9 +337,19 @@ export function createUmiServerLoader(opts: CreateRequestHandlerOptions) {
};
}

function matchRoutesForSSR(reqUrl: string, routesById: IRoutesById) {
function matchRoutesForSSR(
reqUrl: string,
routesById: IRoutesById,
basename?: string,
) {
// react-router-dom 在 v6.4.0 版本上增加了对 basename 结尾为斜杠的支持
// 目前 @umijs/server 依赖的 react-router-dom 版本为 v6.3.0
// 如果传入的 basename 结尾带斜杠, 比如 '/base/', 则会匹配不到.
// 日后如果依赖的版本升级, 此段代码可以删除.
const _basename = basename?.endsWith('/') ? basename.slice(0, -1) : basename;

return (
matchRoutes(createClientRoutes({ routesById }), reqUrl)?.map(
matchRoutes(createClientRoutes({ routesById }), reqUrl, _basename)?.map(
(route: any) => route.route.id,
) || []
);
Expand Down
19 changes: 12 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d39247c

Please sign in to comment.