Skip to content

Commit

Permalink
refactor: use pipeline in Development mode (#8115)
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Aug 17, 2023
1 parent cdebbde commit bbf0b74
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 196 deletions.
13 changes: 2 additions & 11 deletions packages/astro/src/core/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ import {
removeTrailingForwardSlash,
} from '../path.js';
import { RedirectSinglePageBuiltModule } from '../redirects/index.js';
import {
createEnvironment,
createRenderContext,
tryRenderRoute,
type RenderContext,
} from '../render/index.js';
import { createEnvironment, createRenderContext, type RenderContext } from '../render/index.js';
import { RouteCache } from '../render/route-cache.js';
import {
createAssetLink,
Expand Down Expand Up @@ -282,11 +277,7 @@ export class App {
status
);
const page = (await mod.page()) as any;
const response = (await tryRenderRoute(
newRenderContext,
this.#pipeline.env,
page
)) as Response;
const response = await this.#pipeline.renderRoute(newRenderContext, page);
return this.#mergeResponses(response, originalResponse);
} catch {}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class Pipeline {
/**
* Returns the current environment
*/
getEnvironment() {
getEnvironment(): Readonly<Environment> {
return this.env;
}

Expand Down
8 changes: 1 addition & 7 deletions packages/astro/src/core/render/environment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { AstroSettings, RuntimeMode, SSRLoadedRenderer } from '../../@types/astro';
import type { RuntimeMode, SSRLoadedRenderer } from '../../@types/astro';
import type { LogOptions } from '../logger/core.js';
import type { ModuleLoader } from '../module-loader';
import type { RouteCache } from './route-cache.js';

/**
Expand Down Expand Up @@ -38,8 +37,3 @@ export type CreateEnvironmentArgs = Environment;
export function createEnvironment(options: CreateEnvironmentArgs): Environment {
return options;
}

export type DevelopmentEnvironment = Environment & {
loader: ModuleLoader;
settings: AstroSettings;
};
11 changes: 5 additions & 6 deletions packages/astro/src/core/render/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import type { AstroMiddlewareInstance, ComponentInstance, RouteData } from '../../@types/astro';
import type { DevelopmentEnvironment } from './environment';

export { createRenderContext } from './context.js';
export type { RenderContext } from './context.js';
export { tryRenderRoute } from './core.js';
export type { Environment } from './environment';
import type { Environment } from './environment';
export { createEnvironment } from './environment.js';
export { getParamsAndProps } from './params-and-props.js';
export { loadRenderer, loadRenderers } from './renderer.js';
export type { DevelopmentEnvironment };
export { loadRenderer } from './renderer.js';

export type { Environment };

export interface SSROptions {
/** The environment instance */
env: DevelopmentEnvironment;
env: Environment;
/** location of file on disk */
filePath: URL;
/** the web request (needed for dynamic routes) */
Expand Down
10 changes: 1 addition & 9 deletions packages/astro/src/core/render/renderer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import type { AstroRenderer, AstroSettings, SSRLoadedRenderer } from '../../@types/astro';
import type { AstroRenderer, SSRLoadedRenderer } from '../../@types/astro';
import type { ModuleLoader } from '../module-loader/index.js';

export async function loadRenderers(
settings: AstroSettings,
moduleLoader: ModuleLoader
): Promise<SSRLoadedRenderer[]> {
const renderers = await Promise.all(settings.renderers.map((r) => loadRenderer(r, moduleLoader)));
return renderers.filter(Boolean) as SSRLoadedRenderer[];
}

export async function loadRenderer(
renderer: AstroRenderer,
moduleLoader: ModuleLoader
Expand Down
16 changes: 8 additions & 8 deletions packages/astro/src/prerender/routing.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import type { AstroSettings, ComponentInstance, RouteData } from '../@types/astro';
import { RedirectComponentInstance, routeIsRedirect } from '../core/redirects/index.js';
import type { DevelopmentEnvironment } from '../core/render';
import { preload } from '../vite-plugin-astro-server/index.js';
import { getPrerenderStatus } from './metadata.js';
import type DevPipeline from '../vite-plugin-astro-server/devPipeline';

type GetSortedPreloadedMatchesParams = {
env: DevelopmentEnvironment;
pipeline: DevPipeline;
matches: RouteData[];
settings: AstroSettings;
};
export async function getSortedPreloadedMatches({
env,
pipeline,
matches,
settings,
}: GetSortedPreloadedMatchesParams) {
return (
await preloadAndSetPrerenderStatus({
env,
pipeline,
matches,
settings,
})
).sort((a, b) => prioritizePrerenderedMatchesComparator(a.route, b.route));
}

type PreloadAndSetPrerenderStatusParams = {
env: DevelopmentEnvironment;
pipeline: DevPipeline;
matches: RouteData[];
settings: AstroSettings;
};
Expand All @@ -36,7 +36,7 @@ type PreloadAndSetPrerenderStatusResult = {
};

async function preloadAndSetPrerenderStatus({
env,
pipeline,
matches,
settings,
}: PreloadAndSetPrerenderStatusParams): Promise<PreloadAndSetPrerenderStatusResult[]> {
Expand All @@ -52,12 +52,12 @@ async function preloadAndSetPrerenderStatus({
};
}

const preloadedComponent = await preload({ env, filePath });
const preloadedComponent = await preload({ pipeline, filePath });

// gets the prerender metadata set by the `astro:scanner` vite plugin
const prerenderStatus = getPrerenderStatus({
filePath,
loader: env.loader,
loader: pipeline.getModuleLoader(),
});

if (prerenderStatus !== undefined) {
Expand Down
128 changes: 128 additions & 0 deletions packages/astro/src/vite-plugin-astro-server/devPipeline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Pipeline } from '../core/pipeline.js';
import type { AstroConfig, AstroSettings, RouteData } from '../@types/astro';
import type { ModuleLoader } from '../core/module-loader';
import type { Environment } from '../core/render';
import { createEnvironment, loadRenderer } from '../core/render/index.js';
import { createResolve } from './resolve.js';
import { RouteCache } from '../core/render/route-cache.js';
import { isServerLikeOutput } from '../prerender/utils.js';
import type { RuntimeMode, SSRManifest, SSRLoadedRenderer } from '../@types/astro';
import type { LogOptions } from '../core/logger/core';
import { Logger } from '../core/logger/core.js';
import type { EndpointCallResult } from '../core/endpoint/index.js';
import mime from 'mime';
import { attachCookiesToResponse } from '../core/cookies/index.js';

export default class DevPipeline extends Pipeline {
#settings: AstroSettings;
#loader: ModuleLoader;
#devLogger: Logger;
#currentMatchedRoute: RouteData | undefined;

constructor({
manifest,
logging,
settings,
loader,
}: {
manifest: SSRManifest;
logging: LogOptions;
settings: AstroSettings;
loader: ModuleLoader;
}) {
const env = DevPipeline.createDevelopmentEnvironment(manifest, settings, logging, loader);
super(env);
this.#devLogger = new Logger(logging);
this.#settings = settings;
this.#loader = loader;
this.setEndpointHandler(this.#handleEndpointResult);
}

setCurrentMatchedRoute(route: RouteData) {
this.#currentMatchedRoute = route;
}

clearRouteCache() {
this.env.routeCache.clearAll();
}

getSettings(): Readonly<AstroSettings> {
return this.#settings;
}

getConfig(): Readonly<AstroConfig> {
return this.#settings.config;
}

getModuleLoader(): Readonly<ModuleLoader> {
return this.#loader;
}

get logger(): Readonly<Logger> {
return this.#devLogger;
}

async loadRenderers() {
const renderers = await Promise.all(
this.#settings.renderers.map((r) => loadRenderer(r, this.#loader))
);
this.env.renderers = renderers.filter(Boolean) as SSRLoadedRenderer[];
}

static createDevelopmentEnvironment(
manifest: SSRManifest,
settings: AstroSettings,
logging: LogOptions,
loader: ModuleLoader
): Environment {
const mode: RuntimeMode = 'development';

return createEnvironment({
adapterName: manifest.adapterName,
logging,
mode,
// This will be overridden in the dev server
renderers: [],
clientDirectives: manifest.clientDirectives,
compressHTML: manifest.compressHTML,
resolve: createResolve(loader, settings.config.root),
routeCache: new RouteCache(logging, mode),
site: manifest.site,
ssr: isServerLikeOutput(settings.config),
streaming: true,
});
}

async #handleEndpointResult(_: Request, result: EndpointCallResult): Promise<Response> {
if (result.type === 'simple') {
if (!this.#currentMatchedRoute) {
throw new Error(
'In development mode, you must set the current matched route before handling a endpoint.'
);
}
let contentType = 'text/plain';
// Dynamic routes don't include `route.pathname`, so synthesize a path for these (e.g. 'src/pages/[slug].svg')
const filepath =
this.#currentMatchedRoute.pathname ||
this.#currentMatchedRoute.segments
.map((segment) => segment.map((p) => p.content).join(''))
.join('/');
const computedMimeType = mime.getType(filepath);
if (computedMimeType) {
contentType = computedMimeType;
}
const response = new Response(
result.encoding !== 'binary' ? Buffer.from(result.body, result.encoding) : result.body,
{
status: 200,
headers: {
'Content-Type': `${contentType};charset=utf-8`,
},
}
);
attachCookiesToResponse(response, result.cookies);
return response;
}
return result.response;
}
}
12 changes: 3 additions & 9 deletions packages/astro/src/vite-plugin-astro-server/environment.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { AstroSettings, RuntimeMode, SSRManifest } from '../@types/astro.js';
import type { LogOptions } from '../core/logger/core.js';
import type { ModuleLoader } from '../core/module-loader';
import type { DevelopmentEnvironment } from '../core/render';
import type { Environment } from '../core/render';
import { createEnvironment } from '../core/render/index.js';
import { RouteCache } from '../core/render/route-cache.js';
import { isServerLikeOutput } from '../prerender/utils.js';
Expand All @@ -12,9 +12,9 @@ export function createDevelopmentEnvironment(
settings: AstroSettings,
logging: LogOptions,
loader: ModuleLoader
): DevelopmentEnvironment {
): Environment {
const mode: RuntimeMode = 'development';
let env = createEnvironment({
return createEnvironment({
adapterName: manifest.adapterName,
logging,
mode,
Expand All @@ -28,10 +28,4 @@ export function createDevelopmentEnvironment(
ssr: isServerLikeOutput(settings.config),
streaming: true,
});

return {
...env,
loader,
settings,
};
}
16 changes: 6 additions & 10 deletions packages/astro/src/vite-plugin-astro-server/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
import type { ComponentInstance } from '../@types/astro.js';
import { enhanceViteSSRError } from '../core/errors/dev/index.js';
import { AggregateError, CSSError, MarkdownError } from '../core/errors/index.js';
import type { DevelopmentEnvironment } from '../core/render/environment';
import { loadRenderers } from '../core/render/index.js';
import { viteID } from '../core/util.js';
import type DevPipeline from './devPipeline';

export async function preload({
env,
pipeline,
filePath,
}: {
env: DevelopmentEnvironment;
pipeline: DevPipeline;
filePath: URL;
}): Promise<ComponentInstance> {
// Important: This needs to happen first, in case a renderer provides polyfills.
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;
await pipeline.loadRenderers();

try {
// Load the module from the Vite SSR Runtime.
const mod = (await env.loader.import(viteID(filePath))) as ComponentInstance;
const mod = (await pipeline.getModuleLoader().import(viteID(filePath))) as ComponentInstance;

return mod;
} catch (error) {
Expand All @@ -29,7 +25,7 @@ export async function preload({
throw error;
}

throw enhanceViteSSRError({ error, filePath, loader: env.loader });
throw enhanceViteSSRError({ error, filePath, loader: pipeline.getModuleLoader() });
}
}

Expand Down
8 changes: 4 additions & 4 deletions packages/astro/src/vite-plugin-astro-server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { createViteLoader } from '../core/module-loader/index.js';
import { createRouteManifest } from '../core/routing/index.js';
import { baseMiddleware } from './base.js';
import { createController } from './controller.js';
import { createDevelopmentEnvironment } from './environment.js';
import { handleRequest } from './request.js';
import DevPipeline from './devPipeline.js';

export interface AstroPluginOptions {
settings: AstroSettings;
Expand All @@ -26,13 +26,13 @@ export default function createVitePluginAstroServer({
configureServer(viteServer) {
const loader = createViteLoader(viteServer);
const manifest = createDevelopmentManifest(settings);
const env = createDevelopmentEnvironment(manifest, settings, logging, loader);
const pipeline = new DevPipeline({ logging, manifest, settings, loader });
let manifestData: ManifestData = createRouteManifest({ settings, fsMod }, logging);
const controller = createController({ loader });

/** rebuild the route cache + manifest, as needed. */
function rebuildManifest(needsManifestRebuild: boolean) {
env.routeCache.clearAll();
pipeline.clearRouteCache();
if (needsManifestRebuild) {
manifestData = createRouteManifest({ settings }, logging);
}
Expand All @@ -57,7 +57,7 @@ export default function createVitePluginAstroServer({
return;
}
handleRequest({
env,
pipeline,
manifestData,
controller,
incomingRequest: request,
Expand Down
Loading

0 comments on commit bbf0b74

Please sign in to comment.