Skip to content

Commit

Permalink
Refactor SSRResult and RenderContext (#7575)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy authored Jul 5, 2023
1 parent 44e56bb commit 30d04db
Show file tree
Hide file tree
Showing 19 changed files with 59 additions and 77 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-nails-arrive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/markdoc': patch
---

Handle internal access change
40 changes: 23 additions & 17 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1957,16 +1957,6 @@ export interface SSRElement {
children: string;
}

export interface SSRMetadata {
renderers: SSRLoadedRenderer[];
pathname: string;
hasHydrationScript: boolean;
hasDirectives: Set<string>;
hasRenderedHead: boolean;
headInTree: boolean;
clientDirectives: Map<string, string>;
}

/**
* A hint on whether the Astro runtime needs to wait on a component to render head
* content. The meanings:
Expand All @@ -1989,23 +1979,39 @@ export interface SSRResult {
scripts: Set<SSRElement>;
links: Set<SSRElement>;
componentMetadata: Map<string, SSRComponentMetadata>;
propagators: Map<AstroComponentFactory, AstroComponentInstance>;
extraHead: Array<string>;
cookies: AstroCookies | undefined;
createAstro(
Astro: AstroGlobalPartial,
props: Record<string, any>,
slots: Record<string, any> | null
): AstroGlobal;
resolve: (s: string) => Promise<string>;
response: ResponseInit;
// Bits 1 = astro, 2 = jsx, 4 = slot
// As rendering occurs these bits are manipulated to determine where content
// is within a slot. This is used for head injection.
scope: number;
renderers: SSRLoadedRenderer[];
/**
* Map of directive name (e.g. `load`) to the directive script code
*/
clientDirectives: Map<string, string>;
/**
* Only used for logging
*/
pathname: string;
cookies: AstroCookies | undefined;
_metadata: SSRMetadata;
}

/**
* Ephemeral and mutable state during rendering that doesn't rely
* on external configuration
*/
export interface SSRMetadata {
hasHydrationScript: boolean;
hasDirectives: Set<string>;
hasRenderedHead: boolean;
headInTree: boolean;
extraHead: string[];
propagators: Map<AstroComponentFactory, AstroComponentInstance>;
}

/* Preview server stuff */
export interface PreviewServer {
host?: string;
Expand Down
2 changes: 0 additions & 2 deletions packages/astro/src/core/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ export class App {
const mod = (await page.page()) as any;
const renderContext = await createRenderContext({
request,
origin: url.origin,
pathname,
componentMetadata: this.#manifest.componentMetadata,
scripts,
Expand Down Expand Up @@ -295,7 +294,6 @@ export class App {

const ctx = await createRenderContext({
request,
origin: url.origin,
pathname,
route: routeData,
status,
Expand Down
1 change: 0 additions & 1 deletion packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,6 @@ async function generatePath(
});

const renderContext = await createRenderContext({
origin,
pathname,
request: createRequest({ url, headers: new Headers(), logging, ssr }),
componentMetadata: manifest.componentMetadata,
Expand Down
1 change: 0 additions & 1 deletion packages/astro/src/core/endpoint/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export async function call(options: SSROptions, logging: LogOptions) {

const ctx = await createRenderContext({
request: options.request,
origin: options.origin,
pathname: options.pathname,
route: options.route,
env,
Expand Down
17 changes: 5 additions & 12 deletions packages/astro/src/core/render/context.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {
AstroCookies,
ComponentInstance,
Params,
Props,
Expand All @@ -18,23 +17,21 @@ const clientLocalsSymbol = Symbol.for('astro.locals');
*/
export interface RenderContext {
request: Request;
origin: string;
pathname: string;
url: URL;
scripts?: Set<SSRElement>;
links?: Set<SSRElement>;
styles?: Set<SSRElement>;
componentMetadata?: SSRResult['componentMetadata'];
route?: RouteData;
status?: number;
cookies?: AstroCookies;
params: Params;
props: Props;
locals?: object;
}

export type CreateRenderContextArgs = Partial<RenderContext> & {
origin?: string;
export type CreateRenderContextArgs = Partial<
Omit<RenderContext, 'params' | 'props' | 'locals'>
> & {
request: RenderContext['request'];
mod: ComponentInstance;
env: Environment;
Expand All @@ -44,9 +41,7 @@ export async function createRenderContext(
options: CreateRenderContextArgs
): Promise<RenderContext> {
const request = options.request;
const url = new URL(request.url);
const origin = options.origin ?? url.origin;
const pathname = options.pathname ?? url.pathname;
const pathname = options.pathname ?? new URL(request.url).pathname;
const [params, props] = await getParamsAndProps({
mod: options.mod as any,
route: options.route,
Expand All @@ -56,11 +51,9 @@ export async function createRenderContext(
ssr: options.env.ssr,
});

let context = {
const context: RenderContext = {
...options,
origin,
pathname,
url,
params,
props,
};
Expand Down
3 changes: 0 additions & 3 deletions packages/astro/src/core/render/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ export async function renderPage({
styles: renderContext.styles,
logging: env.logging,
markdown: env.markdown,
mode: env.mode,
origin: renderContext.origin,
params: renderContext.params,
props: renderContext.props,
pathname: renderContext.pathname,
componentMetadata: renderContext.componentMetadata,
resolve: env.resolve,
Expand Down
3 changes: 0 additions & 3 deletions packages/astro/src/core/render/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ export interface SSROptions {
env: DevelopmentEnvironment;
/** location of file on disk */
filePath: URL;
/** production website */
origin: string;
/** the web request (needed for dynamic routes) */
pathname: string;
/** The runtime component instance */
Expand Down Expand Up @@ -157,7 +155,6 @@ export async function renderPage(options: SSROptions): Promise<Response> {

const renderContext = await createRenderContext({
request: options.request,
origin: options.origin,
pathname: options.pathname,
scripts,
links,
Expand Down
18 changes: 6 additions & 12 deletions packages/astro/src/core/render/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import type {
AstroGlobal,
AstroGlobalPartial,
Params,
Props,
RuntimeMode,
SSRElement,
SSRLoadedRenderer,
SSRResult,
Expand Down Expand Up @@ -33,15 +31,12 @@ export interface CreateResultArgs {
*/
ssr: boolean;
logging: LogOptions;
origin: string;
/**
* Used to support `Astro.__renderMarkdown` for legacy `<Markdown />` component
*/
markdown: MarkdownRenderingOptions;
mode: RuntimeMode;
params: Params;
pathname: string;
props: Props;
renderers: SSRLoadedRenderer[];
clientDirectives: Map<string, string>;
resolve: (s: string) => Promise<string>;
Expand Down Expand Up @@ -170,9 +165,9 @@ export function createResult(args: CreateResultArgs): SSRResult {
scripts: args.scripts ?? new Set<SSRElement>(),
links: args.links ?? new Set<SSRElement>(),
componentMetadata,
propagators: new Map(),
extraHead: [],
scope: 0,
renderers,
clientDirectives,
pathname,
cookies,
/** This function returns the `Astro` faux-global */
createAstro(
Expand Down Expand Up @@ -259,16 +254,15 @@ export function createResult(args: CreateResultArgs): SSRResult {
return Astro;
},
resolve,
response,
_metadata: {
renderers,
pathname,
hasHydrationScript: false,
hasRenderedHead: false,
hasDirectives: new Set(),
headInTree: false,
clientDirectives,
extraHead: [],
propagators: new Map(),
},
response,
};

return result;
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/runtime/server/hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface ExtractedProps {
// Finds these special props and removes them from what gets passed into the component.
export function extractDirectives(
inputProps: Record<string | number | symbol, any>,
clientDirectives: SSRResult['_metadata']['clientDirectives']
clientDirectives: SSRResult['clientDirectives']
): ExtractedProps {
let extracted: ExtractedProps = {
isPage: false,
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/runtime/server/jsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async function renderJSXVNode(result: SSRResult, vnode: AstroVNode, skip: Skip):
if (isVNode(vnode)) {
switch (true) {
case !vnode.type: {
throw new Error(`Unable to render ${result._metadata.pathname} because it contains an undefined Component!
throw new Error(`Unable to render ${result.pathname} because it contains an undefined Component!
Did you forget to import the component or is it possible there is a typo?`);
}
case (vnode.type as any) === Symbol.for('astro:fragment'):
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/runtime/server/render/astro/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ export function createAstroComponentInstance(
) {
validateComponentProps(props, displayName);
const instance = new AstroComponentInstance(result, props, slots, factory);
if (isAPropagatingComponent(result, factory) && !result.propagators.has(factory)) {
result.propagators.set(factory, instance);
if (isAPropagatingComponent(result, factory) && !result._metadata.propagators.has(factory)) {
result._metadata.propagators.set(factory, instance);
}
return instance;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/runtime/server/render/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async function renderFrameworkComponent(
);
}

const { renderers, clientDirectives } = result._metadata;
const { renderers, clientDirectives } = result;
const metadata: AstroComponentMetadata = {
astroStaticSlot: true,
displayName,
Expand Down
17 changes: 7 additions & 10 deletions packages/astro/src/runtime/server/render/head.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SSRResult } from '../../../@types/astro';

import { markHTMLString } from '../escape.js';
import type { MaybeRenderHeadInstruction, RenderHeadInstruction } from './types';
import { renderElement } from './util.js';

// Filter out duplicate elements in our set
Expand Down Expand Up @@ -34,29 +35,25 @@ export function renderAllHeadContent(result: SSRResult) {

let content = links.join('\n') + styles.join('\n') + scripts.join('\n');

if (result.extraHead.length > 0) {
for (const part of result.extraHead) {
if (result._metadata.extraHead.length > 0) {
for (const part of result._metadata.extraHead) {
content += part;
}
}

return markHTMLString(content);
}

export function* renderHead(result: SSRResult) {
yield { type: 'head', result } as const;
export function* renderHead(): Generator<RenderHeadInstruction> {
yield { type: 'head' };
}

// This function is called by Astro components that do not contain a <head> component
// This accommodates the fact that using a <head> is optional in Astro, so this
// is called before a component's first non-head HTML element. If the head was
// already injected it is a noop.
export function* maybeRenderHead(result: SSRResult) {
if (result._metadata.hasRenderedHead) {
return;
}

export function* maybeRenderHead(): Generator<MaybeRenderHeadInstruction> {
// This is an instruction informing the page rendering that head might need rendering.
// This allows the page to deduplicate head injections.
yield { type: 'maybe-head', result, scope: result.scope } as const;
yield { type: 'maybe-head' };
}
6 changes: 3 additions & 3 deletions packages/astro/src/runtime/server/render/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ async function iterableToHTMLBytes(
// Recursively calls component instances that might have head content
// to be propagated up.
async function bufferHeadContent(result: SSRResult) {
const iterator = result.propagators.values();
const iterator = result._metadata.propagators.values();
while (true) {
const { value, done } = iterator.next();
if (done) {
break;
}
const returnValue = await value.init(result);
if (isHeadAndContent(returnValue)) {
result.extraHead.push(returnValue.head);
result._metadata.extraHead.push(returnValue.head);
}
}
}
Expand All @@ -86,7 +86,7 @@ export async function renderPage(
try {
if (nonAstroPageNeedsHeadInjection(componentFactory)) {
const parts = new HTMLParts();
for await (const chunk of maybeRenderHead(result)) {
for await (const chunk of maybeRenderHead()) {
parts.append(chunk, result);
}
head = parts.toString();
Expand Down
5 changes: 0 additions & 5 deletions packages/astro/src/runtime/server/render/types.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import type { SSRResult } from '../../../@types/astro';
import type { HydrationMetadata } from '../hydration.js';

export type RenderDirectiveInstruction = {
type: 'directive';
result: SSRResult;
hydration: HydrationMetadata;
};

export type RenderHeadInstruction = {
type: 'head';
result: SSRResult;
};

export type MaybeRenderHeadInstruction = {
type: 'maybe-head';
result: SSRResult;
scope: number;
};

export type RenderInstruction =
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/runtime/server/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function determinesIfNeedsDirectiveScript(result: SSRResult, directive: s
export type PrescriptType = null | 'both' | 'directive';

function getDirectiveScriptText(result: SSRResult, directive: string): string {
const clientDirectives = result._metadata.clientDirectives;
const clientDirectives = result.clientDirectives;
const clientDirective = clientDirectives.get(directive);
if (!clientDirective) {
throw new Error(`Unknown directive: ${directive}`);
Expand Down
1 change: 0 additions & 1 deletion packages/astro/src/vite-plugin-astro-server/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export async function handleRoute(
const options: SSROptions = {
env,
filePath,
origin,
preload: preloadedComponent,
pathname,
request,
Expand Down
Loading

0 comments on commit 30d04db

Please sign in to comment.