Skip to content

Commit

Permalink
feat: new ssr (#12489)
Browse files Browse the repository at this point in the history
* feat(preset-umi): unify request handler for ssr and always use stream (#12229)

* refactor(preset): improve types for ssr request handler

* refactor(preset-umi): provide unified request handler for ssr

* refactor: add stream response header

* refactor: correct ts lib usage

* chore: update comment

* refactor: warn for deprecated ssr exports

* refactor: async-able for worker ssr request handler

* refactor: update worker mode condition

* refactor: type correct

* feat: SSR support useServerInsertedHTML (#12247)

* feat: SSR support useServerInsertedHTML

* feat: ssr insert html

* fix: string template

* chore: update lock

* fix: metadata and hydrate root mismatched between csr and ssr (#12220)

* feat: ssr支持head body 配置

* feat: support ssr

* fix: 回退metaloader执行逻辑判断

* fix: ts lint

* feat: 优化部分ssr代码

* feat: add client metadata hydrate data

* docs: hydtateFromRoot doc 修正

* fix: delete merge.with deps

* fix: delete merge.with deps

* fix: change hydrateFromRoot root to renderFromRoot

* fix: NormalizeMeta component for render root

* fix: NormalizeMeta component for render root

---------

Co-authored-by: xiaoxiao <[email protected]>
Co-authored-by: Jinbao1001 <[email protected]>

* fix: hydrate logic for ssr (#12255)

* feat: ssr支持head body 配置

* feat: support ssr

* fix: 回退metaloader执行逻辑判断

* fix: ts lint

* feat: 优化部分ssr代码

* feat: add client metadata hydrate data

* docs: hydtateFromRoot doc 修正

* fix: delete merge.with deps

* fix: delete merge.with deps

* fix: change hydrateFromRoot root to renderFromRoot

* fix: NormalizeMeta component for render root

* fix: NormalizeMeta component for render root

* fix: hydrate 遗留问题处理

* fix: ts-ignore window.__

* fix: 空格

* fix: lint

---------

Co-authored-by: xiaoxiao <[email protected]>
Co-authored-by: Jinbao1001 <[email protected]>

* release: 4.0.0-canary.20240402.1

* fix: wrong react-dom server api for worker ssr mode (#12263)

* fix: wrong react-dom server api for worker ssr mode

* refactor: rename config

* refactor: correct logic

* fix: locked stream in ssr

* feat: align compile time and runtime plugin api between csr and ssr (#12279)

* feat: ssr支持head body 配置

* feat: support ssr

* fix: 回退metaloader执行逻辑判断

* fix: ts lint

* feat: 优化部分ssr代码

* feat: add client metadata hydrate data

* docs: hydtateFromRoot doc 修正

* fix: delete merge.with deps

* fix: delete merge.with deps

* fix: change hydrateFromRoot root to renderFromRoot

* fix: NormalizeMeta component for render root

* fix: NormalizeMeta component for render root

* fix: hydrate 遗留问题处理

* fix: ts-ignore window.__

* fix: 空格

* fix: lint

* feat: addEntryCode to ssr and share the pluginManager

* fix: curry and createPluginManager

* feat: 提取公共 request 方法

* fix: serverloaderRequest

* fix: serverloaderRequest

* fix: serverloaderRequest

* fix: serverloaderRequest

* fix: curry

* fix: curry

* fix: 补充importsAhead and imports

* fix: 条件判断更换

* fix: 代码优化

* fix: tslint

* fix: tslint

* fix: async function export

* fix: add g_umi export and some fixded

* fix: string export

* fix: await clientroutePatch

* feat: patchClientRoutes to async

* fix: ssr禁用 inintial state loading

* feat: 提供render钩子给主应用执行

* feat: 提供render钩子给主应用执行

* feat: 提供render钩子给主应用执行

* feat: to async

* feat: stream render 钩子

* fix: 修改render执行时机

* fix: 移出otherwise逻辑

---------

Co-authored-by: xiaoxiao <[email protected]>
Co-authored-by: Jinbao1001 <[email protected]>

* feat: qiankun plugin compatible with ssr runtime (#12295)

* feat: qiankun 插件支持 ssr

* fix: cr

* fix: 修改 external 的机制

* fix: 增加 ssr render 后,处理 qiankun 的生命周期

* feat: use prerender html directly in ssg (#12317)

* feat: use prerender html directly in ssg

* fix: ssg

* fix: add bootstrap script

* chore: 优先从环境变量读取 manifest 路径 (#12354)

* fix: ssr manifest 正确读取环境变量 (#12357)

* fix: ssr manifest 正确读取环境变量

* chore: 新增 ssr 黑盒变量 SSR_RESOURCE_DIR

* refactor: improve platform checking logic for qiankun slave (#12331)

* feat: qiankun 插件支持 ssr

* fix: cr

* fix: 修改 external 的机制

* fix: 增加 ssr render 后,处理 qiankun 的生命周期

* fix: qiankun slave ssr

* fix: change ssr to isServer

* chore: use process.env.SSR_RESOURCE_DIR replace SSR_RESOURCE_DIR (#12370)

* chore: use process.env.ssr_manifest

* chore: fomatcode

* feat: provide useLoaderData for fallback serverLoader (#12339)

* fix: ssr downgrade init

* feat: add deprecated

* chore: 代码优化

* fix: woker don't need to inject umi.js

* chore: renderFromRoot to __SPECIAL_HTML_DO_NOT_USE_OR_YOU_WILL_BE_FIRED (#12384)

* refactor: add renderFromRoot for tern theme (#12385)

* feat: mako for ssr (#12409)

* fix: ssr mako init

* chore: 删除冗余webpack配置代码

* feat: finish mako bundler for ssr

* feat: generator manifest

* refactor: mako outputpath use bundler-webpack default value

* feat: add mako hooks (#12412)

* refactor(preset-umi): handle illegal route absPath in route preload (#12363)

* refactor(preset-umi): handle unexpected route absPath in route preload

* chore: correct logic

* fix: renderClient opts miss internal vars (#12419)

* release: 4.2.6-alpha.1

* release: 4.2.6-alpha.2

* release: 4.2.6-alpha.3

* release: 4.2.6-alpha.4

* feat: mako build and ssr finished

* chore: delete code

* chore: update lock

* chore: update lock

* chore: update lock

* chore: update lock

* chore: change plugins to makoPlugins

* chore(deps): update mako version

---------

Co-authored-by: Peach <[email protected]>
Co-authored-by: MadCcc <[email protected]>
Co-authored-by: xiaoxiao <[email protected]>
Co-authored-by: Jinbao1001 <[email protected]>
Co-authored-by: Bravepg <[email protected]>
  • Loading branch information
6 people authored Jun 27, 2024
1 parent 7201754 commit b50da63
Show file tree
Hide file tree
Showing 52 changed files with 7,455 additions and 2,482 deletions.
4 changes: 2 additions & 2 deletions examples/max/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"@umijs/max": "workspace:*",
"antd": "^4.23.2",
"dayjs": "^1.11.7",
"react": "18.1.0",
"react-dom": "18.1.0"
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"cross-env": "^7.0.3",
Expand Down
4 changes: 2 additions & 2 deletions examples/mf-host/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
},
"dependencies": {
"@umijs/max": "workspace:*",
"react": "18.1.0",
"react-dom": "18.1.0"
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"cross-env": "^7.0.3",
Expand Down
4 changes: 2 additions & 2 deletions examples/mf-remote/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
},
"dependencies": {
"@umijs/max": "workspace:*",
"react": "18.1.0",
"react-dom": "18.1.0"
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"cross-env": "^7.0.3",
Expand Down
4 changes: 2 additions & 2 deletions examples/qiankun-master/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"dependencies": {
"@umijs/max": "workspace:*",
"qiankun": "^2.10.1",
"react": "18.1.0",
"react-dom": "18.1.0"
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"cross-env": "^7.0.3"
Expand Down
4 changes: 2 additions & 2 deletions examples/qiankun-slave-app2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"dependencies": {
"@umijs/max": "workspace:*",
"react": "18.1.0",
"react-dom": "18.1.0"
"react": "18.3.1",
"react-dom": "18.3.1"
}
}
4 changes: 2 additions & 2 deletions examples/qiankun-slave/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
},
"dependencies": {
"@umijs/max": "workspace:*",
"react": "18.1.0",
"react-dom": "18.1.0"
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"cross-env": "^7.0.3",
Expand Down
19 changes: 18 additions & 1 deletion examples/ssr-demo/.umirc.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
export default {
svgr: {},
hash: true,
mfsu: false,
routePrefetch: {},
manifest: {},
clientLoader: {},
mako: {
plugins: [
{
load: () => {},
},
],
},
ssr: {
serverBuildPath: './umi.server.js',
builder: 'mako',
},
exportStatic: {},
styles: [`body { color: red; }`],

metas: [
{
name: 'test',
content: 'content',
},
],
};
6 changes: 6 additions & 0 deletions examples/ssr-demo/mako.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"optimization": {
"skipModules": true,
"concatenateModules": false
}
}
2 changes: 2 additions & 0 deletions examples/ssr-demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"start:prod": "node ./production-server.js"
},
"dependencies": {
"@ant-design/cssinjs": "^1.18.5",
"antd": "^5",
"express": "4.18.2",
"umi": "workspace:*"
}
Expand Down
23 changes: 23 additions & 0 deletions examples/ssr-demo/src/layouts/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs';
import { useState } from 'react';
import { Outlet, useServerInsertedHTML } from 'umi';

export default function Layout() {
const [cssCache] = useState(() => createCache());

useServerInsertedHTML(() => {
const style = extractStyle(cssCache, { plain: true });
return (
<style
id="antd-cssinjs"
dangerouslySetInnerHTML={{ __html: style }}
></style>
);
});

return (
<StyleProvider cache={cssCache}>
<Outlet />
</StyleProvider>
);
}
29 changes: 23 additions & 6 deletions examples/ssr-demo/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Input } from 'antd';
import { useId } from 'react';
import {
ClientLoader,
Link,
MetadataLoader,
ServerLoader,
useClientLoaderData,
useLoaderData,
useServerInsertedHTML,
useServerLoaderData,
} from 'umi';
Expand All @@ -20,18 +24,29 @@ import umiLogo from './umi.png';
export default function HomePage() {
const clientLoaderData = useClientLoaderData();
const serverLoaderData = useServerLoaderData<typeof serverLoader>();
const loaderData = useLoaderData<typeof serverLoader>();

useServerInsertedHTML(() => {
return <div>inserted html</div>;
return (
<style
dangerouslySetInnerHTML={{
__html: `.server_inserted_style { color: #1677ff }`,
}}
></style>
);
});

const id = useId();

return (
<div>
<h1 className="title">Hello~</h1>
<p className="server_inserted_style">id: {id}</p>
<p className={styles.blue}>This is index.tsx</p>
<p className={cssStyle.title}>I should be pink</p>
<p className={cssStyle.blue}>I should be cyan</p>
<Button />
<Input placeholder="这个样式不应该闪烁" />
<img src={bigImage} alt="" />
<img src={umiLogo} alt="umi" />
<Link to="/users/user">/users/user</Link>
Expand All @@ -43,19 +58,21 @@ export default function HomePage() {
</div>
<p>client loader data: {JSON.stringify(clientLoaderData)}</p>
<p>server loader data: {JSON.stringify(serverLoaderData)}</p>
<p>merge loader data: {JSON.stringify(loaderData)}</p>
</div>
);
}

export async function clientLoader() {
export const clientLoader: ClientLoader = async ({}) => {
await new Promise((resolve) => setTimeout(resolve, Math.random() * 1000));
return { message: 'data from client loader of index.tsx' };
}
return { clientMessage: 'data from client loader of index.tsx' };
};
clientLoader.hydrate = true;

export const serverLoader: ServerLoader = async (req) => {
const url = req!.request.url;
const url = req?.request?.url;
await new Promise((resolve) => setTimeout(resolve, Math.random() * 1000));
return { message: `data from server loader of index.tsx, url: ${url}` };
return { serverMessage: `data from server loader of index.tsx, url: ${url}` };
};

// SEO-设置页面的TDK
Expand Down
Empty file added index.js
Empty file.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
"@types/jest": "^29.2.5",
"@types/node": "^18.11.18",
"@types/qs": "^6.9.7",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/resolve": "^1.20.2",
"@types/rimraf": "3.0.2",
"@types/tunnel": "^0.0.3",
Expand Down Expand Up @@ -101,8 +101,8 @@
"prettier-plugin-organize-imports": "^3.2.2",
"prettier-plugin-packagejson": "^2.4.3",
"qs": "^6.11.0",
"react": "18.1.0",
"react-dom": "18.1.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-text-loop-next": "0.0.3",
"regenerator-runtime": "^0.13.11",
"resolve": "^1.22.0",
Expand Down Expand Up @@ -142,8 +142,8 @@
]
},
"overrides": {
"browserslist": "$browserslist",
"@parcel/watcher": "2.1.0"
"@parcel/watcher": "2.1.0",
"browserslist": "$browserslist"
}
},
"_local": "This flag is used to check if the development in local, Please do not delete."
Expand Down
2 changes: 2 additions & 0 deletions packages/bundler-webpack/src/config/definePlugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ test('normal', () => {
NODE_ENV: '"test"',
PUBLIC_PATH: '"/"',
},
'process.env.SSR_MANIFEST': 'process.env.SSR_MANIFEST',
});
});

Expand All @@ -31,6 +32,7 @@ test('env variables', () => {
UMI_APP_FOO: '"BAR"',
PUBLIC_PATH: '"/"',
},
'process.env.SSR_MANIFEST': 'process.env.SSR_MANIFEST',
});
});

Expand Down
1 change: 1 addition & 0 deletions packages/bundler-webpack/src/config/definePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export function resolveDefine(opts: IOpts) {

return {
'process.env': env,
'process.env.SSR_MANIFEST': 'process.env.SSR_MANIFEST',
...define,
};
}
Expand Down
4 changes: 2 additions & 2 deletions packages/mfsu/src/mfsu/strategyStaticAnalyze.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { logger, printHelp, winPath } from '@umijs/utils';
import type { Configuration } from 'webpack';
import { checkMatch } from '../babelPlugins/awaitImport/checkMatch';
import mfImport from '../babelPlugins/awaitImport/MFImport';
import { StaticDepInfo } from '../staticDepInfo/staticDepInfo';
import { extractBabelPluginImportOptions } from '../utils/webpackUtils';
import { IBuildDepPluginOpts } from '../webpackPlugins/buildDepPlugin';
import type { IMFSUStrategy, MFSU } from './mfsu';
import type { Configuration } from 'webpack';
import { extractBabelPluginImportOptions } from '../utils/webpackUtils';

export class StaticAnalyzeStrategy implements IMFSUStrategy {
private readonly mfsu: MFSU;
Expand Down
8 changes: 8 additions & 0 deletions packages/plugins/libs/qiankun/master/masterRuntimePlugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ function patchMicroAppRouteComponent(routes: any[]) {
}

export async function render(oldRender: typeof noop) {
// 在 ssr 的场景下,直接返回旧的 render
if (typeof window === 'undefined') {
return oldRender();
}
const runtimeOptions = await getMasterRuntime();
let masterOptions: MasterOptions = {
...getMasterOptions(),
Expand Down Expand Up @@ -138,6 +142,10 @@ export async function render(oldRender: typeof noop) {
}

export function patchClientRoutes({ routes }: { routes: any[] }) {
// 在 ssr 的场景下,不执行主应用的 patchClientRoutes
if (typeof window === 'undefined') {
return;
}
const microAppRoutes = [].concat(
deepFilterLeafRoutes(routes),
deepFilterLeafRoutes(microAppRuntimeRoutes),
Expand Down
4 changes: 4 additions & 0 deletions packages/plugins/libs/qiankun/slave/slaveRuntimePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { createHistory } from '@@/core/history';
import qiankunRender, { contextOptsStack } from './lifecycles';

export function render(oldRender: any) {
// 在 ssr 的场景下,直接返回旧的 render
if (typeof window === 'undefined') {
return oldRender();
}
return qiankunRender().then(oldRender);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/src/initial-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default function InitialStateProvider(props: any) {
appLoaded.current = true;
}
}, [loading]);
if (loading && !appLoaded.current) {
if (loading && !appLoaded.current && typeof window !== 'undefined') {
return <Loading />;
}
return props.children;
Expand Down
14 changes: 14 additions & 0 deletions packages/plugins/src/qiankun/master.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,18 @@ export { MicroAppWithMemoHistory } from './MicroAppWithMemoHistory';
`,
});
});

api.chainWebpack((config, { ssr }) => {
// 在 ssr 的场景下,把 qiankun external 到一个任意模块
// 这样就不会把 qiankun 的依赖构建进产物中
if (ssr) {
const originalExternals = config.get('externals');
config.externals({
...originalExternals,
qiankun: 'fs',
});
}

return config;
});
};
19 changes: 13 additions & 6 deletions packages/plugins/src/qiankun/slave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ export interface IRuntimeConfig {
];
});

api.chainWebpack((config) => {
api.chainWebpack((config, { ssr }) => {
// ssr 场景下,通过 cjs 的方式来使用模块,跳过 umd方式的构建
if (ssr) {
return;
}
assert(api.pkg.name, 'You should have name in package.json.');
// 默认不修改 library chunk 的 name,从而确保可以通过 window[appName] 访问到导出
// mfsu 关闭的时候才可以修改,否则可能导致配合 mfsu 时,子应用的 umd chunk 无法被正确加载
Expand Down Expand Up @@ -223,11 +227,14 @@ export interface IRuntimeConfig {

api.addEntryCode(() => [
`
export const bootstrap = qiankun_genBootstrap(render);
export const mount = qiankun_genMount('${api.config.mountElementId}');
export const unmount = qiankun_genUnmount('${api.config.mountElementId}');
export const update = qiankun_genUpdate();
if (!window.__POWERED_BY_QIANKUN__) {
const qiankun_noop = () => new Error('qiankun lifecycle is not available for server runtime!');
const isServer = typeof window === 'undefined';
export const bootstrap = isServer ? qiankun_noop: qiankun_genBootstrap(render);
export const mount = isServer ? qiankun_noop : qiankun_genMount('${api.config.mountElementId}');
export const unmount = isServer ? qiankun_noop : qiankun_genUnmount('${api.config.mountElementId}');
export const update = isServer ? qiankun_noop : qiankun_genUpdate();
// 增加 ssr 的判断
if (!isServer && !window.__POWERED_BY_QIANKUN__) {
bootstrap().then(mount);
}
`,
Expand Down
Loading

0 comments on commit b50da63

Please sign in to comment.