From baaeab0a67534f9c199afcdaee23e5de92e79d7d Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Thu, 29 Jun 2023 21:19:43 +0800 Subject: [PATCH] Refactor component and renderers loading flow (#7518) --- packages/astro/src/core/endpoint/dev/index.ts | 10 ++--- packages/astro/src/core/render/dev/index.ts | 40 +++++++----------- packages/astro/src/core/render/index.ts | 2 +- packages/astro/src/core/render/renderer.ts | 42 +++++++------------ packages/astro/src/prerender/routing.ts | 13 ++---- .../src/vite-plugin-astro-server/route.ts | 16 +++---- packages/astro/test/units/render/jsx.test.js | 2 +- 7 files changed, 43 insertions(+), 82 deletions(-) diff --git a/packages/astro/src/core/endpoint/dev/index.ts b/packages/astro/src/core/endpoint/dev/index.ts index 04e11b578..1f0917166 100644 --- a/packages/astro/src/core/endpoint/dev/index.ts +++ b/packages/astro/src/core/endpoint/dev/index.ts @@ -5,12 +5,8 @@ import { createRenderContext } from '../../render/index.js'; import { callEndpoint } from '../index.js'; export async function call(options: SSROptions, logging: LogOptions) { - const { - env, - preload: [, mod], - middleware, - } = options; - const endpointHandler = mod as unknown as EndpointHandler; + const { env, preload, middleware } = options; + const endpointHandler = preload as unknown as EndpointHandler; const ctx = await createRenderContext({ request: options.request, @@ -18,7 +14,7 @@ export async function call(options: SSROptions, logging: LogOptions) { pathname: options.pathname, route: options.route, env, - mod: endpointHandler as any, + mod: preload, }); return await callEndpoint(endpointHandler, env, ctx, logging, middleware?.onRequest); diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts index 67d0b0581..5995bb711 100644 --- a/packages/astro/src/core/render/dev/index.ts +++ b/packages/astro/src/core/render/dev/index.ts @@ -5,17 +5,14 @@ import type { MiddlewareResponseHandler, RouteData, SSRElement, - SSRLoadedRenderer, } from '../../../@types/astro'; import { PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js'; import { createAPIContext } from '../../endpoint/index.js'; import { enhanceViteSSRError } from '../../errors/dev/index.js'; import { AggregateError, CSSError, MarkdownError } from '../../errors/index.js'; import { callMiddleware } from '../../middleware/callMiddleware.js'; -import type { ModuleLoader } from '../../module-loader/index'; import { isPage, resolveIdToUrl, viteID } from '../../util.js'; -import { createRenderContext, renderPage as coreRenderPage } from '../index.js'; -import { filterFoundRenderers, loadRenderer } from '../renderer.js'; +import { createRenderContext, renderPage as coreRenderPage, loadRenderers } from '../index.js'; import { getStylesForURL } from './css.js'; import type { DevelopmentEnvironment } from './environment'; import { getComponentMetadata } from './metadata.js'; @@ -32,8 +29,8 @@ export interface SSROptions { origin: string; /** the web request (needed for dynamic routes) */ pathname: string; - /** The renderers and instance */ - preload: ComponentPreload; + /** The runtime component instance */ + preload: ComponentInstance; /** Request */ request: Request; /** optional, in case we need to render something outside of a dev server */ @@ -44,36 +41,31 @@ export interface SSROptions { middleware?: AstroMiddlewareInstance; } -export type ComponentPreload = [SSRLoadedRenderer[], ComponentInstance]; - -export async function loadRenderers( - moduleLoader: ModuleLoader, - settings: AstroSettings -): Promise { - const loader = (entry: string) => moduleLoader.import(entry); - const renderers = await Promise.all(settings.renderers.map((r) => loadRenderer(r, loader))); - return filterFoundRenderers(renderers); -} - export async function preload({ env, filePath, -}: Pick): Promise { +}: { + env: DevelopmentEnvironment; + filePath: URL; +}): Promise { // Important: This needs to happen first, in case a renderer provides polyfills. - const renderers = await loadRenderers(env.loader, env.settings); + const renderers = await loadRenderers(env.settings, env.loader); + // Override the environment's renderers. This ensures that if renderers change (HMR) + // The new instances are passed through. + env.renderers = renderers; try { // Load the module from the Vite SSR Runtime. const mod = (await env.loader.import(viteID(filePath))) as ComponentInstance; - return [renderers, mod]; + return mod; } catch (error) { // If the error came from Markdown or CSS, we already handled it and there's no need to enhance it if (MarkdownError.is(error) || CSSError.is(error) || AggregateError.is(error)) { throw error; } - throw enhanceViteSSRError({ error, filePath, loader: env.loader, renderers }); + throw enhanceViteSSRError({ error, filePath, loader: env.loader }); } } @@ -156,11 +148,7 @@ async function getScriptsAndStyles({ env, filePath }: GetScriptsAndStylesParams) } export async function renderPage(options: SSROptions): Promise { - const [renderers, mod] = options.preload; - - // Override the environment's renderers. This ensures that if renderers change (HMR) - // The new instances are passed through. - options.env.renderers = renderers; + const mod = options.preload; const { scripts, links, styles, metadata } = await getScriptsAndStyles({ env: options.env, diff --git a/packages/astro/src/core/render/index.ts b/packages/astro/src/core/render/index.ts index 4e4df8239..372454f26 100644 --- a/packages/astro/src/core/render/index.ts +++ b/packages/astro/src/core/render/index.ts @@ -8,4 +8,4 @@ export { } from './core.js'; export type { Environment } from './environment'; export { createBasicEnvironment, createEnvironment } from './environment.js'; -export { loadRenderer } from './renderer.js'; +export { loadRenderer, loadRenderers } from './renderer.js'; diff --git a/packages/astro/src/core/render/renderer.ts b/packages/astro/src/core/render/renderer.ts index 3585a08c2..8e5e97202 100644 --- a/packages/astro/src/core/render/renderer.ts +++ b/packages/astro/src/core/render/renderer.ts @@ -1,36 +1,24 @@ -import type { AstroRenderer, SSRLoadedRenderer } from '../../@types/astro'; +import type { AstroRenderer, AstroSettings, SSRLoadedRenderer } from '../../@types/astro'; +import type { ModuleLoader } from '../module-loader/index.js'; -export type RendererServerEntrypointModule = { - default: SSRLoadedRenderer['ssr']; -}; -export type MaybeRendererServerEntrypointModule = Partial; -export type RendererLoader = (entryPoint: string) => Promise; +export async function loadRenderers( + settings: AstroSettings, + moduleLoader: ModuleLoader +): Promise { + const renderers = await Promise.all(settings.renderers.map((r) => loadRenderer(r, moduleLoader))); + return renderers.filter(Boolean) as SSRLoadedRenderer[]; +} export async function loadRenderer( renderer: AstroRenderer, - loader: RendererLoader + moduleLoader: ModuleLoader ): Promise { - const mod = await loader(renderer.serverEntrypoint); + const mod = await moduleLoader.import(renderer.serverEntrypoint); if (typeof mod.default !== 'undefined') { - return createLoadedRenderer(renderer, mod as RendererServerEntrypointModule); + return { + ...renderer, + ssr: mod.default, + }; } return undefined; } - -export function filterFoundRenderers( - renderers: Array -): SSRLoadedRenderer[] { - return renderers.filter((renderer): renderer is SSRLoadedRenderer => { - return !!renderer; - }); -} - -export function createLoadedRenderer( - renderer: AstroRenderer, - mod: RendererServerEntrypointModule -): SSRLoadedRenderer { - return { - ...renderer, - ssr: mod.default, - }; -} diff --git a/packages/astro/src/prerender/routing.ts b/packages/astro/src/prerender/routing.ts index fc01b0480..0282a12b4 100644 --- a/packages/astro/src/prerender/routing.ts +++ b/packages/astro/src/prerender/routing.ts @@ -1,10 +1,6 @@ -import type { AstroSettings, RouteData } from '../@types/astro'; +import type { AstroSettings, ComponentInstance, RouteData } from '../@types/astro'; import { RedirectComponentInstance, routeIsRedirect } from '../core/redirects/index.js'; -import { - preload, - type ComponentPreload, - type DevelopmentEnvironment, -} from '../core/render/dev/index.js'; +import { preload, type DevelopmentEnvironment } from '../core/render/dev/index.js'; import { getPrerenderStatus } from './metadata.js'; type GetSortedPreloadedMatchesParams = { @@ -35,7 +31,7 @@ type PreloadAndSetPrerenderStatusParams = { type PreloadAndSetPrerenderStatusResult = { filePath: URL; route: RouteData; - preloadedComponent: ComponentPreload; + preloadedComponent: ComponentInstance; }; async function preloadAndSetPrerenderStatus({ @@ -48,9 +44,8 @@ async function preloadAndSetPrerenderStatus({ const filePath = new URL(`./${route.component}`, settings.config.root); if (routeIsRedirect(route)) { - const preloadedComponent: ComponentPreload = [[], RedirectComponentInstance]; return { - preloadedComponent, + preloadedComponent: RedirectComponentInstance, route, filePath, }; diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index a610b4b74..f7d8ba23f 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -7,11 +7,7 @@ import { throwIfRedirectNotAllowed } from '../core/endpoint/index.js'; import { AstroErrorData } from '../core/errors/index.js'; import { warn } from '../core/logger/core.js'; import { loadMiddleware } from '../core/middleware/loadMiddleware.js'; -import type { - ComponentPreload, - DevelopmentEnvironment, - SSROptions, -} from '../core/render/dev/index'; +import type { DevelopmentEnvironment, SSROptions } from '../core/render/dev/index'; import { preload, renderPage } from '../core/render/dev/index.js'; import { getParamsAndProps, GetParamsAndPropsError } from '../core/render/index.js'; import { createRequest } from '../core/request.js'; @@ -33,7 +29,7 @@ interface MatchedRoute { route: RouteData; filePath: URL; resolvedPathname: string; - preloadedComponent: ComponentPreload; + preloadedComponent: ComponentInstance; mod: ComponentInstance; } @@ -54,9 +50,8 @@ export async function matchRoute( for await (const { preloadedComponent, route: maybeRoute, filePath } of preloadedMatches) { // attempt to get static paths // if this fails, we have a bad URL match! - const [, mod] = preloadedComponent; const paramsAndPropsRes = await getParamsAndProps({ - mod, + mod: preloadedComponent, route: maybeRoute, routeCache, pathname: pathname, @@ -70,7 +65,7 @@ export async function matchRoute( filePath, resolvedPathname: pathname, preloadedComponent, - mod, + mod: preloadedComponent, }; } } @@ -101,14 +96,13 @@ export async function matchRoute( if (custom404) { const filePath = new URL(`./${custom404.component}`, settings.config.root); const preloadedComponent = await preload({ env, filePath }); - const [, mod] = preloadedComponent; return { route: custom404, filePath, resolvedPathname: pathname, preloadedComponent, - mod, + mod: preloadedComponent, }; } diff --git a/packages/astro/test/units/render/jsx.test.js b/packages/astro/test/units/render/jsx.test.js index c249bcbd5..09cf79239 100644 --- a/packages/astro/test/units/render/jsx.test.js +++ b/packages/astro/test/units/render/jsx.test.js @@ -16,7 +16,7 @@ import { createAstroJSXComponent, renderer as jsxRenderer } from '../../../dist/ import { defaultLogging as logging } from '../../test-utils.js'; const createAstroModule = (AstroComponent) => ({ default: AstroComponent }); -const loadJSXRenderer = () => loadRenderer(jsxRenderer, (s) => import(s)); +const loadJSXRenderer = () => loadRenderer(jsxRenderer, { import: (s) => import(s) }); describe('core/render', () => { describe('Astro JSX components', () => {