@umijs/renderer-react
Advanced tools
Comparing version 4.2.15 to 4.3.0
@@ -26,2 +26,3 @@ import React from 'react'; | ||
}; | ||
export declare function useLoaderData<T extends ServerLoaderFunc = any>(): Awaited<ReturnType<T>>; | ||
export {}; |
@@ -0,1 +1,2 @@ | ||
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; | ||
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; | ||
@@ -28,2 +29,3 @@ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; | ||
} | ||
// @deprecated Please use `useLoaderData` instead. | ||
export function useServerLoaderData() { | ||
@@ -51,3 +53,2 @@ var routes = useSelectedRoutes(); | ||
React.useEffect(function () { | ||
// @ts-ignore | ||
if (!window.__UMI_LOADER_DATA__) { | ||
@@ -80,2 +81,4 @@ // 支持 ssr 降级,客户端兜底加载 serverLoader 数据 | ||
} | ||
// @deprecated Please use `useLoaderData` instead. | ||
export function useClientLoaderData() { | ||
@@ -87,2 +90,9 @@ var route = useRouteData(); | ||
}; | ||
} | ||
export function useLoaderData() { | ||
var serverLoaderData = useServerLoaderData(); | ||
var clientLoaderData = useClientLoaderData(); | ||
return { | ||
data: _objectSpread(_objectSpread({}, serverLoaderData.data), clientLoaderData.data) | ||
}; | ||
} |
@@ -22,2 +22,7 @@ import { History } from 'history'; | ||
/** | ||
* react dom 渲染的的目标节点 id | ||
* @doc 一般不需要改,微前端的时候会变化 | ||
*/ | ||
mountElementId?: string; | ||
/** | ||
* react dom 渲染的的目标 dom | ||
@@ -27,2 +32,12 @@ * @doc 一般不需要改,微前端的时候会变化 | ||
rootElement?: HTMLElement; | ||
__INTERNAL_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { | ||
/** | ||
* 内部流程, 渲染特殊 app 节点, 不要使用!!! | ||
*/ | ||
pureApp?: boolean; | ||
/** | ||
* 内部流程, 渲染特殊 html 节点, 不要使用!!! | ||
*/ | ||
pureHtml?: boolean; | ||
}; | ||
/** | ||
@@ -78,2 +93,2 @@ * 当前的路由配置 | ||
*/ | ||
export declare function renderClient(opts: RenderClientOpts): (() => JSX.Element) | undefined; | ||
export declare function renderClient(opts: RenderClientOpts): (() => React.JSX.Element) | undefined; |
@@ -10,2 +10,3 @@ import _defineProperty from "@babel/runtime/helpers/esm/defineProperty"; | ||
import { fetchServerLoader } from "./dataFetcher"; | ||
import { Html } from "./html"; | ||
import { createClientRoutes } from "./routes"; | ||
@@ -134,5 +135,3 @@ var root = null; | ||
setClientLoaderData = _useState2[1]; | ||
var _useState3 = useState( | ||
// @ts-ignore | ||
window.__UMI_LOADER_DATA__ || {}), | ||
var _useState3 = useState(window.__UMI_LOADER_DATA__ || {}), | ||
_useState4 = _slicedToArray(_useState3, 2), | ||
@@ -185,5 +184,9 @@ serverLoaderData = _useState4[0], | ||
} | ||
var clientLoader = (_opts$routes$id = opts.routes[id]) === null || _opts$routes$id === void 0 ? void 0 : _opts$routes$id.clientLoader; | ||
var hasClientLoader = !!clientLoader; | ||
var hasServerLoader = (_opts$routes$id2 = opts.routes[id]) === null || _opts$routes$id2 === void 0 ? void 0 : _opts$routes$id2.hasServerLoader; | ||
// server loader | ||
// use ?. since routes patched with patchClientRoutes is not exists in opts.routes | ||
if (!isFirst && (_opts$routes$id = opts.routes[id]) !== null && _opts$routes$id !== void 0 && _opts$routes$id.hasServerLoader) { | ||
if (!isFirst && hasServerLoader && !hasClientLoader && !window.__UMI_LOADER_DATA__) { | ||
fetchServerLoader({ | ||
@@ -205,5 +208,28 @@ id: id, | ||
// onPatchClientRoutes 添加的 route 在 opts.routes 里是不存在的 | ||
var clientLoader = (_opts$routes$id2 = opts.routes[id]) === null || _opts$routes$id2 === void 0 ? void 0 : _opts$routes$id2.clientLoader; | ||
if (clientLoader && !clientLoaderData[id]) { | ||
clientLoader().then(function (data) { | ||
var hasClientLoaderDataInRoute = !!clientLoaderData[id]; | ||
// Check if hydration is needed or there's no server loader for the current route | ||
var shouldHydrateOrNoServerLoader = hasClientLoader && clientLoader.hydrate || !hasServerLoader; | ||
// Check if server loader data is missing in the global window object | ||
var isServerLoaderDataMissing = hasServerLoader && !window.__UMI_LOADER_DATA__; | ||
if (hasClientLoader && !hasClientLoaderDataInRoute && (shouldHydrateOrNoServerLoader || isServerLoaderDataMissing)) { | ||
// ... | ||
clientLoader({ | ||
serverLoader: function serverLoader() { | ||
return fetchServerLoader({ | ||
id: id, | ||
basename: basename, | ||
cb: function cb(data) { | ||
// setServerLoaderData when startTransition because if ssr is enabled, | ||
// the component may being hydrated and setLoaderData will break the hydration | ||
React.startTransition(function () { | ||
setServerLoaderData(function (d) { | ||
return _objectSpread(_objectSpread({}, d), {}, _defineProperty({}, id, data)); | ||
}); | ||
}); | ||
} | ||
}); | ||
} | ||
}).then(function (data) { | ||
setClientLoaderData(function (d) { | ||
@@ -254,3 +280,11 @@ return _objectSpread(_objectSpread({}, d), {}, _defineProperty({}, id, data)); | ||
if (opts.hydrate) { | ||
ReactDOM.hydrateRoot(rootElement, /*#__PURE__*/React.createElement(Browser, null)); | ||
var loaderData = window.__UMI_LOADER_DATA__ || {}; | ||
var metadata = window.__UMI_METADATA_LOADER_DATA__ || {}; | ||
var hydtateHtmloptions = { | ||
metadata: metadata, | ||
loaderData: loaderData, | ||
mountElementId: opts.mountElementId | ||
}; | ||
var _isInternal = opts.__INTERNAL_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.pureApp || opts.__INTERNAL_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.pureHtml; | ||
ReactDOM.hydrateRoot(_isInternal ? rootElement : document, _isInternal ? /*#__PURE__*/React.createElement(Browser, null) : /*#__PURE__*/React.createElement(Html, hydtateHtmloptions, /*#__PURE__*/React.createElement(Browser, null))); | ||
return; | ||
@@ -257,0 +291,0 @@ } |
export { createBrowserHistory, createHashHistory, createMemoryHistory, type History, } from 'history'; | ||
export { Helmet, HelmetProvider } from 'react-helmet-async'; | ||
export { createSearchParams, generatePath, matchPath, matchRoutes, Navigate, NavLink, Outlet, resolvePath, useLocation, useMatch, useNavigate, useOutlet, useOutletContext, useParams, useResolvedPath, useRoutes, useSearchParams, } from 'react-router-dom'; | ||
export { useAppData, useClientLoaderData, useRouteProps, useSelectedRoutes, useServerLoaderData, } from './appContext'; | ||
export { useAppData, useClientLoaderData, useLoaderData, useRouteProps, useSelectedRoutes, useServerLoaderData, } from './appContext'; | ||
export { renderClient, __getRoot } from './browser'; | ||
export { LinkWithPrefetch as Link } from './link'; | ||
export { useRouteData } from './routeContext'; | ||
export type { ClientLoader } from './types'; | ||
export { __useFetcher } from './useFetcher'; | ||
export { withRouter, type RouteComponentProps } from './withRouter'; |
export { createBrowserHistory, createHashHistory, createMemoryHistory } from 'history'; | ||
export { Helmet, HelmetProvider } from 'react-helmet-async'; | ||
export { createSearchParams, generatePath, matchPath, matchRoutes, Navigate, NavLink, Outlet, resolvePath, useLocation, useMatch, useNavigate, useOutlet, useOutletContext, useParams, useResolvedPath, useRoutes, useSearchParams } from 'react-router-dom'; | ||
export { useAppData, useClientLoaderData, useRouteProps, useSelectedRoutes, useServerLoaderData } from "./appContext"; | ||
export { useAppData, useClientLoaderData, useLoaderData, useRouteProps, useSelectedRoutes, useServerLoaderData } from "./appContext"; | ||
export { renderClient, __getRoot } from "./browser"; | ||
@@ -6,0 +6,0 @@ export { LinkWithPrefetch as Link } from "./link"; |
@@ -5,2 +5,2 @@ import React, { PropsWithChildren } from 'react'; | ||
prefetch?: boolean; | ||
} & LinkProps & React.RefAttributes<HTMLAnchorElement>>): JSX.Element | null; | ||
} & LinkProps & React.RefAttributes<HTMLAnchorElement>>): React.JSX.Element | null; |
@@ -1,15 +0,3 @@ | ||
import type { IMetadata } from '@umijs/server/dist/types'; | ||
import { IRouteComponents, IRoutesById } from './types'; | ||
interface IHtmlProps { | ||
routes: IRoutesById; | ||
routeComponents: IRouteComponents; | ||
pluginManager: any; | ||
location: string; | ||
loaderData: { | ||
[routeKey: string]: any; | ||
}; | ||
manifest: any; | ||
metadata?: IMetadata; | ||
} | ||
export declare function getClientRootComponent(opts: IHtmlProps): Promise<JSX.Element>; | ||
export {}; | ||
import React from 'react'; | ||
import { IRootComponentOptions } from './types'; | ||
export declare function getClientRootComponent(opts: IRootComponentOptions): Promise<React.JSX.Element>; |
@@ -8,2 +8,3 @@ import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime"; | ||
import { Routes } from "./browser"; | ||
import { Html } from "./html"; | ||
import { createClientRoutes } from "./routes"; | ||
@@ -21,3 +22,3 @@ // Get the root React component for ReactDOMServer.renderToString | ||
basename = '/'; | ||
components = _objectSpread({}, opts.routeComponents); | ||
components = _objectSpread({}, opts.routeComponents); // todo 参数对齐 | ||
clientRoutes = createClientRoutes({ | ||
@@ -27,2 +28,9 @@ routesById: opts.routes, | ||
}); | ||
opts.pluginManager.applyPlugins({ | ||
key: 'patchClientRoutes', | ||
type: 'event', | ||
args: { | ||
routes: clientRoutes | ||
} | ||
}); | ||
rootContainer = /*#__PURE__*/React.createElement(StaticRouter, { | ||
@@ -55,3 +63,3 @@ basename: basename, | ||
return _context.abrupt("return", /*#__PURE__*/React.createElement(Html, opts, app)); | ||
case 7: | ||
case 8: | ||
case "end": | ||
@@ -63,45 +71,2 @@ return _context.stop(); | ||
return _getClientRootComponent.apply(this, arguments); | ||
} | ||
function Html(_ref) { | ||
var _metadata$keywords, _metadata$metas; | ||
var children = _ref.children, | ||
loaderData = _ref.loaderData, | ||
manifest = _ref.manifest, | ||
metadata = _ref.metadata; | ||
// TODO: 处理 head 标签,比如 favicon.ico 的一致性 | ||
// TODO: root 支持配置 | ||
return /*#__PURE__*/React.createElement("html", { | ||
lang: (metadata === null || metadata === void 0 ? void 0 : metadata.lang) || 'en' | ||
}, /*#__PURE__*/React.createElement("head", null, /*#__PURE__*/React.createElement("meta", { | ||
charSet: "utf-8" | ||
}), /*#__PURE__*/React.createElement("meta", { | ||
name: "viewport", | ||
content: "width=device-width, initial-scale=1" | ||
}), (metadata === null || metadata === void 0 ? void 0 : metadata.title) && /*#__PURE__*/React.createElement("title", null, metadata.title), (metadata === null || metadata === void 0 ? void 0 : metadata.description) && /*#__PURE__*/React.createElement("meta", { | ||
name: "description", | ||
content: metadata.description | ||
}), (metadata === null || metadata === void 0 || (_metadata$keywords = metadata.keywords) === null || _metadata$keywords === void 0 ? void 0 : _metadata$keywords.length) && /*#__PURE__*/React.createElement("meta", { | ||
name: "keywords", | ||
content: metadata.keywords.join(',') | ||
}), metadata === null || metadata === void 0 || (_metadata$metas = metadata.metas) === null || _metadata$metas === void 0 ? void 0 : _metadata$metas.map(function (em) { | ||
return /*#__PURE__*/React.createElement("meta", { | ||
key: em.name, | ||
name: em.name, | ||
content: em.content | ||
}); | ||
}), manifest.assets['umi.css'] && /*#__PURE__*/React.createElement("link", { | ||
rel: "stylesheet", | ||
href: manifest.assets['umi.css'] | ||
})), /*#__PURE__*/React.createElement("body", null, /*#__PURE__*/React.createElement("noscript", { | ||
dangerouslySetInnerHTML: { | ||
__html: "<b>Enable JavaScript to run this app.</b>" | ||
} | ||
}), /*#__PURE__*/React.createElement("div", { | ||
id: "root" | ||
}, children), /*#__PURE__*/React.createElement("script", { | ||
dangerouslySetInnerHTML: { | ||
__html: "window.__UMI_LOADER_DATA__ = ".concat(JSON.stringify(loaderData)) | ||
} | ||
}))); | ||
} |
/// <reference types="react" /> | ||
import type { IhtmlPageOpts, ServerLoader } from '@umijs/server/dist/types'; | ||
import type { RouteMatch, RouteObject } from 'react-router-dom'; | ||
declare global { | ||
interface Window { | ||
__UMI_LOADER_DATA__: any; | ||
__UMI_METADATA_LOADER_DATA__: any; | ||
__UMI_BUILD_ClIENT_CSS__: any; | ||
} | ||
} | ||
declare type ClientLoaderFunctionArgs = { | ||
serverLoader: ServerLoader; | ||
}; | ||
export declare type ClientLoader = ((args: ClientLoaderFunctionArgs) => Promise<any>) & { | ||
hydrate?: boolean; | ||
}; | ||
export interface IRouteSSRProps { | ||
clientLoader?: () => Promise<any>; | ||
clientLoader?: ClientLoader; | ||
hasServerLoader?: boolean; | ||
@@ -36,1 +50,36 @@ } | ||
} | ||
interface IHtmlHydrateOptions { | ||
htmlPageOpts?: IhtmlPageOpts; | ||
__INTERNAL_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?: { | ||
pureApp: boolean; | ||
pureHtml: boolean; | ||
}; | ||
mountElementId?: string; | ||
} | ||
export interface IRootComponentOptions extends IHtmlHydrateOptions { | ||
routes: IRoutesById; | ||
routeComponents: IRouteComponents; | ||
pluginManager: any; | ||
location: string; | ||
loaderData: { | ||
[routeKey: string]: any; | ||
}; | ||
manifest: any; | ||
} | ||
export interface IHtmlProps extends IHtmlHydrateOptions { | ||
children?: React.ReactNode; | ||
loaderData?: { | ||
[routeKey: string]: any; | ||
}; | ||
manifest?: any; | ||
} | ||
export declare type IScript = Partial<{ | ||
async: boolean; | ||
charset: string; | ||
content: string; | ||
crossOrigin: string | null; | ||
defer: boolean; | ||
src: string; | ||
type: string; | ||
}> | string; | ||
export {}; |
@@ -17,2 +17,2 @@ import React from 'react'; | ||
} | ||
export declare function withRouter<P extends RouteComponentProps<P>>(Component: React.ComponentType<P>): (props: P) => JSX.Element; | ||
export declare function withRouter<P extends RouteComponentProps<P>>(Component: React.ComponentType<P>): (props: P) => React.JSX.Element; |
{ | ||
"name": "@umijs/renderer-react", | ||
"version": "4.2.15", | ||
"version": "4.3.0", | ||
"description": "@umijs/renderer-react", | ||
@@ -26,4 +26,4 @@ "homepage": "https://github.com/umijs/umi/tree/master/packages/renderer-react#readme", | ||
"devDependencies": { | ||
"react": "18.1.0", | ||
"react-dom": "18.1.0" | ||
"react": "18.3.1", | ||
"react-dom": "18.3.1" | ||
}, | ||
@@ -30,0 +30,0 @@ "peerDependencies": { |
45501
27
1088