From d25d94beb7050d307e1dc98ac8451ece314d3acb Mon Sep 17 00:00:00 2001 From: answershuto Date: Wed, 22 Nov 2023 16:24:00 +0800 Subject: [PATCH] feat: get assets --- packages/runtime/src/Document.tsx | 30 ++++---------------- packages/runtime/src/runServerApp.tsx | 12 +++++--- packages/runtime/src/server/streamRender.tsx | 29 ++++++++++++++++++- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/packages/runtime/src/Document.tsx b/packages/runtime/src/Document.tsx index 78380fda89..740b36d2a6 100644 --- a/packages/runtime/src/Document.tsx +++ b/packages/runtime/src/Document.tsx @@ -18,20 +18,6 @@ const Context = React.createContext(undefined); Context.displayName = 'DocumentContext'; -// Collect render assets for SSR preRender. -function pushRenderAssets(asset: Array | string) { - if (typeof window === 'undefined') return; - if (!window.renderAssets) { - window.renderAssets = []; - } - - if (Array.isArray(asset)) { - window.renderAssets.push(...asset); - } else { - window.renderAssets.push(asset); - } -} - function useDocumentContext() { const value = React.useContext(Context); return value; @@ -97,10 +83,6 @@ export const Links: LinksType = (props: LinksProps) => { const entryAssets = getEntryAssets(assetsManifest); const styles = entryAssets.concat(pageAssets).filter(path => path.indexOf('.css') > -1); - // Collect styles. - pushRenderAssets(styles); - pushRenderAssets(routeLinks.map(routeLink => routeLink.href)); - return ( <> { @@ -144,10 +126,6 @@ export const Scripts: ScriptsType = (props: ScriptsProps) => { return true; }); - // Collect scripts. - pushRenderAssets(routeScripts.map(routeScriptProps => routeScriptProps.src)); - pushRenderAssets(scripts); - return ( <> @@ -165,8 +143,7 @@ export const Scripts: ScriptsType = (props: ScriptsProps) => { ); }; -export function usePageAssets() { - const { loaderData, matches, assetsManifest } = useAppContext(); +export function getAllAssets(loaderData, matches, assetsManifest): Array { const routeLinks = getLinks(matches, loaderData); const routeScripts = getScripts(matches, loaderData); const pageAssets = getPageAssets(matches, assetsManifest); @@ -181,6 +158,11 @@ export function usePageAssets() { return assets; } +export function usePageAssets() { + const { loaderData, matches, assetsManifest } = useAppContext(); + return getAllAssets(loaderData, matches, assetsManifest); +} + interface DataProps { ScriptElement?: React.ComponentType> | string; } diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index 65dcfbf9fe..f7604f52a1 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -7,7 +7,8 @@ import { isFunction } from '@ice/shared'; import type { RenderToPipeableStreamOptions, OnAllReadyParams } from './server/streamRender.js'; import type { AppContext, RouteItem, ServerContext, - AppExport, AssetsManifest, + AppExport, + AssetsManifest, RouteMatch, PageConfig, RenderMode, @@ -21,7 +22,7 @@ import Runtime from './runtime.js'; import { AppContextProvider } from './AppContext.js'; import { getAppData } from './appData.js'; import getAppConfig from './appConfig.js'; -import { DocumentContextProvider } from './Document.js'; +import { DocumentContextProvider, usePageAssets } from './Document.js'; import { loadRouteModules } from './routes.js'; import type { RouteLoaderOptions } from './routes.js'; import { pipeToString, renderToNodeStream } from './server/streamRender.js'; @@ -34,7 +35,7 @@ import { renderHTMLToJS } from './renderHTMLToJS.js'; import addLeadingSlash from './utils/addLeadingSlash.js'; -interface RenderOptions { +export interface RenderOptions { app: AppExport; assetsManifest: AssetsManifest; createRoutes: (options: Pick) => RouteItem[]; @@ -416,7 +417,10 @@ async function renderServerEntry( ); - const pipe = renderToNodeStream(element); + const pipe = renderToNodeStream(element, { + renderOptions, + routerContext, + }); const fallback = () => { return renderDocument({ diff --git a/packages/runtime/src/server/streamRender.tsx b/packages/runtime/src/server/streamRender.tsx index 04de8bb396..f26855468d 100644 --- a/packages/runtime/src/server/streamRender.tsx +++ b/packages/runtime/src/server/streamRender.tsx @@ -1,6 +1,9 @@ import * as Stream from 'stream'; import type * as StreamType from 'stream'; import * as ReactDOMServer from 'react-dom/server'; +import { getAllAssets } from '../Document.js'; +import type { RenderOptions } from '../runServerApp.js'; +import type { ServerAppRouterProps } from '../types.js'; const { Writable } = Stream; @@ -20,8 +23,13 @@ export type NodeWritablePiper = ( options?: RenderToPipeableStreamOptions, ) => void; +export type RenderToNodeStreamOptions = { + renderOptions: RenderOptions; + routerContext: ServerAppRouterProps['routerContext']; +}; export function renderToNodeStream( element: React.ReactElement, + renderToNodeStreamOptions: RenderToNodeStreamOptions, ): NodeWritablePiper { return (res, options) => { const { pipe } = ReactDOMServer.renderToPipeableStream(element, { @@ -36,8 +44,27 @@ export function renderToNodeStream( options?.onError && options?.onError(error); }, onAllReady() { + const { + renderOptions, + routerContext, + } = renderToNodeStreamOptions; + + const { + assetsManifest, + } = renderOptions; + + const { + matches, + loaderData, + } = routerContext; + + const renderAssets = getAllAssets(loaderData, matches, assetsManifest); + if (typeof window !== 'undefined' && window.renderAssets) { + renderAssets.concat(window.renderAssets); + } + options?.onAllReady && options?.onAllReady({ - renderAssets: (typeof window === 'undefined') ? [] : (window.renderAssets || []), + renderAssets, }); }, });