refactor: use pipeline in Development mode (#8115)
This commit is contained in:
parent
cdebbded0c
commit
bbf0b7470b
14 changed files with 254 additions and 195 deletions
|
@ -16,12 +16,7 @@ import {
|
||||||
removeTrailingForwardSlash,
|
removeTrailingForwardSlash,
|
||||||
} from '../path.js';
|
} from '../path.js';
|
||||||
import { RedirectSinglePageBuiltModule } from '../redirects/index.js';
|
import { RedirectSinglePageBuiltModule } from '../redirects/index.js';
|
||||||
import {
|
import { createEnvironment, createRenderContext, type RenderContext } from '../render/index.js';
|
||||||
createEnvironment,
|
|
||||||
createRenderContext,
|
|
||||||
tryRenderRoute,
|
|
||||||
type RenderContext,
|
|
||||||
} from '../render/index.js';
|
|
||||||
import { RouteCache } from '../render/route-cache.js';
|
import { RouteCache } from '../render/route-cache.js';
|
||||||
import {
|
import {
|
||||||
createAssetLink,
|
createAssetLink,
|
||||||
|
@ -282,11 +277,7 @@ export class App {
|
||||||
status
|
status
|
||||||
);
|
);
|
||||||
const page = (await mod.page()) as any;
|
const page = (await mod.page()) as any;
|
||||||
const response = (await tryRenderRoute(
|
const response = await this.#pipeline.renderRoute(newRenderContext, page);
|
||||||
newRenderContext,
|
|
||||||
this.#pipeline.env,
|
|
||||||
page
|
|
||||||
)) as Response;
|
|
||||||
return this.#mergeResponses(response, originalResponse);
|
return this.#mergeResponses(response, originalResponse);
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ export class Pipeline {
|
||||||
/**
|
/**
|
||||||
* Returns the current environment
|
* Returns the current environment
|
||||||
*/
|
*/
|
||||||
getEnvironment() {
|
getEnvironment(): Readonly<Environment> {
|
||||||
return this.env;
|
return this.env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 { LogOptions } from '../logger/core.js';
|
||||||
import type { ModuleLoader } from '../module-loader';
|
|
||||||
import type { RouteCache } from './route-cache.js';
|
import type { RouteCache } from './route-cache.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,8 +37,3 @@ export type CreateEnvironmentArgs = Environment;
|
||||||
export function createEnvironment(options: CreateEnvironmentArgs): Environment {
|
export function createEnvironment(options: CreateEnvironmentArgs): Environment {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DevelopmentEnvironment = Environment & {
|
|
||||||
loader: ModuleLoader;
|
|
||||||
settings: AstroSettings;
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
import type { AstroMiddlewareInstance, ComponentInstance, RouteData } from '../../@types/astro';
|
import type { AstroMiddlewareInstance, ComponentInstance, RouteData } from '../../@types/astro';
|
||||||
import type { DevelopmentEnvironment } from './environment';
|
|
||||||
|
|
||||||
export { createRenderContext } from './context.js';
|
export { createRenderContext } from './context.js';
|
||||||
export type { RenderContext } from './context.js';
|
export type { RenderContext } from './context.js';
|
||||||
export { tryRenderRoute } from './core.js';
|
export { tryRenderRoute } from './core.js';
|
||||||
export type { Environment } from './environment';
|
import type { Environment } from './environment';
|
||||||
export { createEnvironment } from './environment.js';
|
export { createEnvironment } from './environment.js';
|
||||||
export { getParamsAndProps } from './params-and-props.js';
|
export { getParamsAndProps } from './params-and-props.js';
|
||||||
export { loadRenderer, loadRenderers } from './renderer.js';
|
export { loadRenderer } from './renderer.js';
|
||||||
export type { DevelopmentEnvironment };
|
|
||||||
|
export type { Environment };
|
||||||
|
|
||||||
export interface SSROptions {
|
export interface SSROptions {
|
||||||
/** The environment instance */
|
/** The environment instance */
|
||||||
env: DevelopmentEnvironment;
|
env: Environment;
|
||||||
/** location of file on disk */
|
/** location of file on disk */
|
||||||
filePath: URL;
|
filePath: URL;
|
||||||
/** the web request (needed for dynamic routes) */
|
/** the web request (needed for dynamic routes) */
|
||||||
|
|
|
@ -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';
|
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(
|
export async function loadRenderer(
|
||||||
renderer: AstroRenderer,
|
renderer: AstroRenderer,
|
||||||
moduleLoader: ModuleLoader
|
moduleLoader: ModuleLoader
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import type { AstroSettings, ComponentInstance, RouteData } from '../@types/astro';
|
import type { AstroSettings, ComponentInstance, RouteData } from '../@types/astro';
|
||||||
import { RedirectComponentInstance, routeIsRedirect } from '../core/redirects/index.js';
|
import { RedirectComponentInstance, routeIsRedirect } from '../core/redirects/index.js';
|
||||||
import type { DevelopmentEnvironment } from '../core/render';
|
|
||||||
import { preload } from '../vite-plugin-astro-server/index.js';
|
import { preload } from '../vite-plugin-astro-server/index.js';
|
||||||
import { getPrerenderStatus } from './metadata.js';
|
import { getPrerenderStatus } from './metadata.js';
|
||||||
|
import type DevPipeline from '../vite-plugin-astro-server/devPipeline';
|
||||||
|
|
||||||
type GetSortedPreloadedMatchesParams = {
|
type GetSortedPreloadedMatchesParams = {
|
||||||
env: DevelopmentEnvironment;
|
pipeline: DevPipeline;
|
||||||
matches: RouteData[];
|
matches: RouteData[];
|
||||||
settings: AstroSettings;
|
settings: AstroSettings;
|
||||||
};
|
};
|
||||||
export async function getSortedPreloadedMatches({
|
export async function getSortedPreloadedMatches({
|
||||||
env,
|
pipeline,
|
||||||
matches,
|
matches,
|
||||||
settings,
|
settings,
|
||||||
}: GetSortedPreloadedMatchesParams) {
|
}: GetSortedPreloadedMatchesParams) {
|
||||||
return (
|
return (
|
||||||
await preloadAndSetPrerenderStatus({
|
await preloadAndSetPrerenderStatus({
|
||||||
env,
|
pipeline,
|
||||||
matches,
|
matches,
|
||||||
settings,
|
settings,
|
||||||
})
|
})
|
||||||
|
@ -24,7 +24,7 @@ export async function getSortedPreloadedMatches({
|
||||||
}
|
}
|
||||||
|
|
||||||
type PreloadAndSetPrerenderStatusParams = {
|
type PreloadAndSetPrerenderStatusParams = {
|
||||||
env: DevelopmentEnvironment;
|
pipeline: DevPipeline;
|
||||||
matches: RouteData[];
|
matches: RouteData[];
|
||||||
settings: AstroSettings;
|
settings: AstroSettings;
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,7 @@ type PreloadAndSetPrerenderStatusResult = {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function preloadAndSetPrerenderStatus({
|
async function preloadAndSetPrerenderStatus({
|
||||||
env,
|
pipeline,
|
||||||
matches,
|
matches,
|
||||||
settings,
|
settings,
|
||||||
}: PreloadAndSetPrerenderStatusParams): Promise<PreloadAndSetPrerenderStatusResult[]> {
|
}: PreloadAndSetPrerenderStatusParams): Promise<PreloadAndSetPrerenderStatusResult[]> {
|
||||||
|
@ -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
|
// gets the prerender metadata set by the `astro:scanner` vite plugin
|
||||||
const prerenderStatus = getPrerenderStatus({
|
const prerenderStatus = getPrerenderStatus({
|
||||||
filePath,
|
filePath,
|
||||||
loader: env.loader,
|
loader: pipeline.getModuleLoader(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (prerenderStatus !== undefined) {
|
if (prerenderStatus !== undefined) {
|
||||||
|
|
128
packages/astro/src/vite-plugin-astro-server/devPipeline.ts
Normal file
128
packages/astro/src/vite-plugin-astro-server/devPipeline.ts
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import type { AstroSettings, RuntimeMode, SSRManifest } from '../@types/astro.js';
|
import type { AstroSettings, RuntimeMode, SSRManifest } from '../@types/astro.js';
|
||||||
import type { LogOptions } from '../core/logger/core.js';
|
import type { LogOptions } from '../core/logger/core.js';
|
||||||
import type { ModuleLoader } from '../core/module-loader';
|
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 { createEnvironment } from '../core/render/index.js';
|
||||||
import { RouteCache } from '../core/render/route-cache.js';
|
import { RouteCache } from '../core/render/route-cache.js';
|
||||||
import { isServerLikeOutput } from '../prerender/utils.js';
|
import { isServerLikeOutput } from '../prerender/utils.js';
|
||||||
|
@ -12,9 +12,9 @@ export function createDevelopmentEnvironment(
|
||||||
settings: AstroSettings,
|
settings: AstroSettings,
|
||||||
logging: LogOptions,
|
logging: LogOptions,
|
||||||
loader: ModuleLoader
|
loader: ModuleLoader
|
||||||
): DevelopmentEnvironment {
|
): Environment {
|
||||||
const mode: RuntimeMode = 'development';
|
const mode: RuntimeMode = 'development';
|
||||||
let env = createEnvironment({
|
return createEnvironment({
|
||||||
adapterName: manifest.adapterName,
|
adapterName: manifest.adapterName,
|
||||||
logging,
|
logging,
|
||||||
mode,
|
mode,
|
||||||
|
@ -28,10 +28,4 @@ export function createDevelopmentEnvironment(
|
||||||
ssr: isServerLikeOutput(settings.config),
|
ssr: isServerLikeOutput(settings.config),
|
||||||
streaming: true,
|
streaming: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
|
||||||
...env,
|
|
||||||
loader,
|
|
||||||
settings,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,22 @@
|
||||||
import type { ComponentInstance } from '../@types/astro.js';
|
import type { ComponentInstance } from '../@types/astro.js';
|
||||||
import { enhanceViteSSRError } from '../core/errors/dev/index.js';
|
import { enhanceViteSSRError } from '../core/errors/dev/index.js';
|
||||||
import { AggregateError, CSSError, MarkdownError } from '../core/errors/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 { viteID } from '../core/util.js';
|
||||||
|
import type DevPipeline from './devPipeline';
|
||||||
|
|
||||||
export async function preload({
|
export async function preload({
|
||||||
env,
|
pipeline,
|
||||||
filePath,
|
filePath,
|
||||||
}: {
|
}: {
|
||||||
env: DevelopmentEnvironment;
|
pipeline: DevPipeline;
|
||||||
filePath: URL;
|
filePath: URL;
|
||||||
}): Promise<ComponentInstance> {
|
}): Promise<ComponentInstance> {
|
||||||
// Important: This needs to happen first, in case a renderer provides polyfills.
|
// Important: This needs to happen first, in case a renderer provides polyfills.
|
||||||
const renderers = await loadRenderers(env.settings, env.loader);
|
await pipeline.loadRenderers();
|
||||||
// Override the environment's renderers. This ensures that if renderers change (HMR)
|
|
||||||
// The new instances are passed through.
|
|
||||||
env.renderers = renderers;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Load the module from the Vite SSR Runtime.
|
// 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;
|
return mod;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -29,7 +25,7 @@ export async function preload({
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw enhanceViteSSRError({ error, filePath, loader: env.loader });
|
throw enhanceViteSSRError({ error, filePath, loader: pipeline.getModuleLoader() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ import { createViteLoader } from '../core/module-loader/index.js';
|
||||||
import { createRouteManifest } from '../core/routing/index.js';
|
import { createRouteManifest } from '../core/routing/index.js';
|
||||||
import { baseMiddleware } from './base.js';
|
import { baseMiddleware } from './base.js';
|
||||||
import { createController } from './controller.js';
|
import { createController } from './controller.js';
|
||||||
import { createDevelopmentEnvironment } from './environment.js';
|
|
||||||
import { handleRequest } from './request.js';
|
import { handleRequest } from './request.js';
|
||||||
|
import DevPipeline from './devPipeline.js';
|
||||||
|
|
||||||
export interface AstroPluginOptions {
|
export interface AstroPluginOptions {
|
||||||
settings: AstroSettings;
|
settings: AstroSettings;
|
||||||
|
@ -26,13 +26,13 @@ export default function createVitePluginAstroServer({
|
||||||
configureServer(viteServer) {
|
configureServer(viteServer) {
|
||||||
const loader = createViteLoader(viteServer);
|
const loader = createViteLoader(viteServer);
|
||||||
const manifest = createDevelopmentManifest(settings);
|
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);
|
let manifestData: ManifestData = createRouteManifest({ settings, fsMod }, logging);
|
||||||
const controller = createController({ loader });
|
const controller = createController({ loader });
|
||||||
|
|
||||||
/** rebuild the route cache + manifest, as needed. */
|
/** rebuild the route cache + manifest, as needed. */
|
||||||
function rebuildManifest(needsManifestRebuild: boolean) {
|
function rebuildManifest(needsManifestRebuild: boolean) {
|
||||||
env.routeCache.clearAll();
|
pipeline.clearRouteCache();
|
||||||
if (needsManifestRebuild) {
|
if (needsManifestRebuild) {
|
||||||
manifestData = createRouteManifest({ settings }, logging);
|
manifestData = createRouteManifest({ settings }, logging);
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ export default function createVitePluginAstroServer({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handleRequest({
|
handleRequest({
|
||||||
env,
|
pipeline,
|
||||||
manifestData,
|
manifestData,
|
||||||
controller,
|
controller,
|
||||||
incomingRequest: request,
|
incomingRequest: request,
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import type http from 'node:http';
|
import type http from 'node:http';
|
||||||
import type { ManifestData, SSRManifest } from '../@types/astro';
|
import type { ManifestData, SSRManifest } from '../@types/astro';
|
||||||
import type { DevelopmentEnvironment } from '../core/render/index';
|
|
||||||
import type { DevServerController } from './controller';
|
import type { DevServerController } from './controller';
|
||||||
|
|
||||||
import { collectErrorMetadata } from '../core/errors/dev/index.js';
|
import { collectErrorMetadata } from '../core/errors/dev/index.js';
|
||||||
import { createSafeError } from '../core/errors/index.js';
|
import { createSafeError } from '../core/errors/index.js';
|
||||||
import { error } from '../core/logger/core.js';
|
|
||||||
import * as msg from '../core/messages.js';
|
import * as msg from '../core/messages.js';
|
||||||
import { collapseDuplicateSlashes, removeTrailingForwardSlash } from '../core/path.js';
|
import { collapseDuplicateSlashes, removeTrailingForwardSlash } from '../core/path.js';
|
||||||
import { eventError, telemetry } from '../events/index.js';
|
import { eventError, telemetry } from '../events/index.js';
|
||||||
|
@ -13,9 +10,10 @@ import { isServerLikeOutput } from '../prerender/utils.js';
|
||||||
import { runWithErrorHandling } from './controller.js';
|
import { runWithErrorHandling } from './controller.js';
|
||||||
import { handle500Response } from './response.js';
|
import { handle500Response } from './response.js';
|
||||||
import { handleRoute, matchRoute } from './route.js';
|
import { handleRoute, matchRoute } from './route.js';
|
||||||
|
import type DevPipeline from './devPipeline';
|
||||||
|
|
||||||
type HandleRequest = {
|
type HandleRequest = {
|
||||||
env: DevelopmentEnvironment;
|
pipeline: DevPipeline;
|
||||||
manifestData: ManifestData;
|
manifestData: ManifestData;
|
||||||
controller: DevServerController;
|
controller: DevServerController;
|
||||||
incomingRequest: http.IncomingMessage;
|
incomingRequest: http.IncomingMessage;
|
||||||
|
@ -25,15 +23,15 @@ type HandleRequest = {
|
||||||
|
|
||||||
/** The main logic to route dev server requests to pages in Astro. */
|
/** The main logic to route dev server requests to pages in Astro. */
|
||||||
export async function handleRequest({
|
export async function handleRequest({
|
||||||
env,
|
pipeline,
|
||||||
manifestData,
|
manifestData,
|
||||||
controller,
|
controller,
|
||||||
incomingRequest,
|
incomingRequest,
|
||||||
incomingResponse,
|
incomingResponse,
|
||||||
manifest,
|
manifest,
|
||||||
}: HandleRequest) {
|
}: HandleRequest) {
|
||||||
const { settings, loader: moduleLoader } = env;
|
const config = pipeline.getConfig();
|
||||||
const { config } = settings;
|
const moduleLoader = pipeline.getModuleLoader();
|
||||||
const origin = `${moduleLoader.isHttps() ? 'https' : 'http'}://${incomingRequest.headers.host}`;
|
const origin = `${moduleLoader.isHttps() ? 'https' : 'http'}://${incomingRequest.headers.host}`;
|
||||||
const buildingToSSR = isServerLikeOutput(config);
|
const buildingToSSR = isServerLikeOutput(config);
|
||||||
|
|
||||||
|
@ -75,7 +73,7 @@ export async function handleRequest({
|
||||||
controller,
|
controller,
|
||||||
pathname,
|
pathname,
|
||||||
async run() {
|
async run() {
|
||||||
const matchedRoute = await matchRoute(pathname, env, manifestData);
|
const matchedRoute = await matchRoute(pathname, manifestData, pipeline);
|
||||||
const resolvedPathname = matchedRoute?.resolvedPathname ?? pathname;
|
const resolvedPathname = matchedRoute?.resolvedPathname ?? pathname;
|
||||||
return await handleRoute({
|
return await handleRoute({
|
||||||
matchedRoute,
|
matchedRoute,
|
||||||
|
@ -83,7 +81,7 @@ export async function handleRequest({
|
||||||
pathname: resolvedPathname,
|
pathname: resolvedPathname,
|
||||||
body,
|
body,
|
||||||
origin,
|
origin,
|
||||||
env,
|
pipeline,
|
||||||
manifestData,
|
manifestData,
|
||||||
incomingRequest: incomingRequest,
|
incomingRequest: incomingRequest,
|
||||||
incomingResponse: incomingResponse,
|
incomingResponse: incomingResponse,
|
||||||
|
@ -95,7 +93,7 @@ export async function handleRequest({
|
||||||
|
|
||||||
// This could be a runtime error from Vite's SSR module, so try to fix it here
|
// This could be a runtime error from Vite's SSR module, so try to fix it here
|
||||||
try {
|
try {
|
||||||
env.loader.fixStacktrace(err);
|
moduleLoader.fixStacktrace(err);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
// This is our last line of defense regarding errors where we still might have some information about the request
|
// This is our last line of defense regarding errors where we still might have some information about the request
|
||||||
|
@ -104,7 +102,7 @@ export async function handleRequest({
|
||||||
|
|
||||||
telemetry.record(eventError({ cmd: 'dev', err: errorWithMetadata, isFatal: false }));
|
telemetry.record(eventError({ cmd: 'dev', err: errorWithMetadata, isFatal: false }));
|
||||||
|
|
||||||
error(env.logging, null, msg.formatErrorMessage(errorWithMetadata));
|
pipeline.logger.error(null, msg.formatErrorMessage(errorWithMetadata));
|
||||||
handle500Response(moduleLoader, incomingResponse, errorWithMetadata);
|
handle500Response(moduleLoader, incomingResponse, errorWithMetadata);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -1,25 +1,15 @@
|
||||||
import mime from 'mime';
|
|
||||||
import type http from 'node:http';
|
import type http from 'node:http';
|
||||||
import type {
|
import type {
|
||||||
ComponentInstance,
|
ComponentInstance,
|
||||||
ManifestData,
|
ManifestData,
|
||||||
MiddlewareResponseHandler,
|
MiddlewareEndpointHandler,
|
||||||
RouteData,
|
RouteData,
|
||||||
SSRElement,
|
SSRElement,
|
||||||
SSRManifest,
|
SSRManifest,
|
||||||
} from '../@types/astro';
|
} from '../@types/astro';
|
||||||
import { attachCookiesToResponse } from '../core/cookies/index.js';
|
|
||||||
import { AstroErrorData, isAstroError } from '../core/errors/index.js';
|
import { AstroErrorData, isAstroError } from '../core/errors/index.js';
|
||||||
import { warn } from '../core/logger/core.js';
|
|
||||||
import { loadMiddleware } from '../core/middleware/loadMiddleware.js';
|
import { loadMiddleware } from '../core/middleware/loadMiddleware.js';
|
||||||
import { isEndpointResult } from '../core/render/core.js';
|
import { createRenderContext, getParamsAndProps, type SSROptions } from '../core/render/index.js';
|
||||||
import {
|
|
||||||
createRenderContext,
|
|
||||||
getParamsAndProps,
|
|
||||||
tryRenderRoute,
|
|
||||||
type DevelopmentEnvironment,
|
|
||||||
type SSROptions,
|
|
||||||
} from '../core/render/index.js';
|
|
||||||
import { createRequest } from '../core/request.js';
|
import { createRequest } from '../core/request.js';
|
||||||
import { matchAllRoutes } from '../core/routing/index.js';
|
import { matchAllRoutes } from '../core/routing/index.js';
|
||||||
import { isPage, resolveIdToUrl, viteID } from '../core/util.js';
|
import { isPage, resolveIdToUrl, viteID } from '../core/util.js';
|
||||||
|
@ -32,6 +22,7 @@ import { preload } from './index.js';
|
||||||
import { getComponentMetadata } from './metadata.js';
|
import { getComponentMetadata } from './metadata.js';
|
||||||
import { handle404Response, writeSSRResult, writeWebResponse } from './response.js';
|
import { handle404Response, writeSSRResult, writeWebResponse } from './response.js';
|
||||||
import { getScriptsForURL } from './scripts.js';
|
import { getScriptsForURL } from './scripts.js';
|
||||||
|
import type DevPipeline from './devPipeline.js';
|
||||||
|
|
||||||
const clientLocalsSymbol = Symbol.for('astro.locals');
|
const clientLocalsSymbol = Symbol.for('astro.locals');
|
||||||
|
|
||||||
|
@ -56,12 +47,17 @@ function getCustom404Route(manifestData: ManifestData): RouteData | undefined {
|
||||||
|
|
||||||
export async function matchRoute(
|
export async function matchRoute(
|
||||||
pathname: string,
|
pathname: string,
|
||||||
env: DevelopmentEnvironment,
|
manifestData: ManifestData,
|
||||||
manifestData: ManifestData
|
pipeline: DevPipeline
|
||||||
): Promise<MatchedRoute | undefined> {
|
): Promise<MatchedRoute | undefined> {
|
||||||
const { logging, settings, routeCache } = env;
|
const env = pipeline.getEnvironment();
|
||||||
|
const { routeCache, logging } = env;
|
||||||
const matches = matchAllRoutes(pathname, manifestData);
|
const matches = matchAllRoutes(pathname, manifestData);
|
||||||
const preloadedMatches = await getSortedPreloadedMatches({ env, matches, settings });
|
const preloadedMatches = await getSortedPreloadedMatches({
|
||||||
|
pipeline,
|
||||||
|
matches,
|
||||||
|
settings: pipeline.getSettings(),
|
||||||
|
});
|
||||||
|
|
||||||
for await (const { preloadedComponent, route: maybeRoute, filePath } of preloadedMatches) {
|
for await (const { preloadedComponent, route: maybeRoute, filePath } of preloadedMatches) {
|
||||||
// attempt to get static paths
|
// attempt to get static paths
|
||||||
|
@ -73,7 +69,7 @@ export async function matchRoute(
|
||||||
routeCache,
|
routeCache,
|
||||||
pathname: pathname,
|
pathname: pathname,
|
||||||
logging,
|
logging,
|
||||||
ssr: isServerLikeOutput(settings.config),
|
ssr: isServerLikeOutput(pipeline.getConfig()),
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
route: maybeRoute,
|
route: maybeRoute,
|
||||||
|
@ -96,14 +92,13 @@ export async function matchRoute(
|
||||||
// build formats, and is necessary based on how the manifest tracks build targets.
|
// build formats, and is necessary based on how the manifest tracks build targets.
|
||||||
const altPathname = pathname.replace(/(index)?\.html$/, '');
|
const altPathname = pathname.replace(/(index)?\.html$/, '');
|
||||||
if (altPathname !== pathname) {
|
if (altPathname !== pathname) {
|
||||||
return await matchRoute(altPathname, env, manifestData);
|
return await matchRoute(altPathname, manifestData, pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matches.length) {
|
if (matches.length) {
|
||||||
const possibleRoutes = matches.flatMap((route) => route.component);
|
const possibleRoutes = matches.flatMap((route) => route.component);
|
||||||
|
|
||||||
warn(
|
pipeline.logger.warn(
|
||||||
logging,
|
|
||||||
'getStaticPaths',
|
'getStaticPaths',
|
||||||
`${AstroErrorData.NoMatchingStaticPathFound.message(
|
`${AstroErrorData.NoMatchingStaticPathFound.message(
|
||||||
pathname
|
pathname
|
||||||
|
@ -115,8 +110,8 @@ export async function matchRoute(
|
||||||
const custom404 = getCustom404Route(manifestData);
|
const custom404 = getCustom404Route(manifestData);
|
||||||
|
|
||||||
if (custom404) {
|
if (custom404) {
|
||||||
const filePath = new URL(`./${custom404.component}`, settings.config.root);
|
const filePath = new URL(`./${custom404.component}`, pipeline.getConfig().root);
|
||||||
const preloadedComponent = await preload({ env, filePath });
|
const preloadedComponent = await preload({ pipeline, filePath });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
route: custom404,
|
route: custom404,
|
||||||
|
@ -136,12 +131,12 @@ type HandleRoute = {
|
||||||
pathname: string;
|
pathname: string;
|
||||||
body: ArrayBuffer | undefined;
|
body: ArrayBuffer | undefined;
|
||||||
origin: string;
|
origin: string;
|
||||||
env: DevelopmentEnvironment;
|
|
||||||
manifestData: ManifestData;
|
manifestData: ManifestData;
|
||||||
incomingRequest: http.IncomingMessage;
|
incomingRequest: http.IncomingMessage;
|
||||||
incomingResponse: http.ServerResponse;
|
incomingResponse: http.ServerResponse;
|
||||||
manifest: SSRManifest;
|
manifest: SSRManifest;
|
||||||
status?: 404 | 500;
|
status?: 404 | 500;
|
||||||
|
pipeline: DevPipeline;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function handleRoute({
|
export async function handleRoute({
|
||||||
|
@ -151,18 +146,21 @@ export async function handleRoute({
|
||||||
status = getStatus(matchedRoute),
|
status = getStatus(matchedRoute),
|
||||||
body,
|
body,
|
||||||
origin,
|
origin,
|
||||||
env,
|
pipeline,
|
||||||
manifestData,
|
manifestData,
|
||||||
incomingRequest,
|
incomingRequest,
|
||||||
incomingResponse,
|
incomingResponse,
|
||||||
manifest,
|
manifest,
|
||||||
}: HandleRoute): Promise<void> {
|
}: HandleRoute): Promise<void> {
|
||||||
const { logging, settings } = env;
|
const env = pipeline.getEnvironment();
|
||||||
|
const settings = pipeline.getSettings();
|
||||||
|
const config = pipeline.getConfig();
|
||||||
|
const moduleLoader = pipeline.getModuleLoader();
|
||||||
|
const { logging } = env;
|
||||||
if (!matchedRoute) {
|
if (!matchedRoute) {
|
||||||
return handle404Response(origin, incomingRequest, incomingResponse);
|
return handle404Response(origin, incomingRequest, incomingResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { config } = settings;
|
|
||||||
const filePath: URL | undefined = matchedRoute.filePath;
|
const filePath: URL | undefined = matchedRoute.filePath;
|
||||||
const { route, preloadedComponent } = matchedRoute;
|
const { route, preloadedComponent } = matchedRoute;
|
||||||
const buildingToSSR = isServerLikeOutput(config);
|
const buildingToSSR = isServerLikeOutput(config);
|
||||||
|
@ -192,14 +190,14 @@ export async function handleRoute({
|
||||||
request,
|
request,
|
||||||
route,
|
route,
|
||||||
};
|
};
|
||||||
const middleware = await loadMiddleware(env.loader, env.settings.config.srcDir);
|
const middleware = await loadMiddleware(moduleLoader, settings.config.srcDir);
|
||||||
if (middleware) {
|
if (middleware) {
|
||||||
options.middleware = middleware;
|
options.middleware = middleware;
|
||||||
}
|
}
|
||||||
const mod = options.preload;
|
const mod = options.preload;
|
||||||
|
|
||||||
const { scripts, links, styles, metadata } = await getScriptsAndStyles({
|
const { scripts, links, styles, metadata } = await getScriptsAndStyles({
|
||||||
env: options.env,
|
pipeline,
|
||||||
filePath: options.filePath,
|
filePath: options.filePath,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -214,70 +212,32 @@ export async function handleRoute({
|
||||||
mod,
|
mod,
|
||||||
env,
|
env,
|
||||||
});
|
});
|
||||||
const onRequest = options.middleware?.onRequest as MiddlewareResponseHandler | undefined;
|
const onRequest = options.middleware?.onRequest as MiddlewareEndpointHandler | undefined;
|
||||||
|
if (onRequest) {
|
||||||
|
pipeline.setMiddlewareFunction(onRequest);
|
||||||
|
}
|
||||||
|
pipeline.setCurrentMatchedRoute(route);
|
||||||
|
|
||||||
const result = await tryRenderRoute(renderContext, env, mod, onRequest);
|
let response = await pipeline.renderRoute(renderContext, mod);
|
||||||
if (isEndpointResult(result, route.type)) {
|
if (response.status === 404) {
|
||||||
if (result.type === 'response') {
|
const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline);
|
||||||
if (result.response.headers.get('X-Astro-Response') === 'Not-Found') {
|
return handleRoute({
|
||||||
const fourOhFourRoute = await matchRoute('/404', env, manifestData);
|
...options,
|
||||||
return handleRoute({
|
matchedRoute: fourOhFourRoute,
|
||||||
matchedRoute: fourOhFourRoute,
|
url: new URL(pathname, url),
|
||||||
url: new URL('/404', url),
|
status: 404,
|
||||||
pathname: '/404',
|
body,
|
||||||
status: 404,
|
origin,
|
||||||
body,
|
pipeline,
|
||||||
origin,
|
manifestData,
|
||||||
env,
|
incomingRequest,
|
||||||
manifestData,
|
incomingResponse,
|
||||||
incomingRequest,
|
manifest,
|
||||||
incomingResponse,
|
});
|
||||||
manifest,
|
}
|
||||||
});
|
if (route.type === 'endpoint') {
|
||||||
}
|
await writeWebResponse(incomingResponse, response);
|
||||||
await writeWebResponse(incomingResponse, result.response);
|
|
||||||
} else {
|
|
||||||
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 =
|
|
||||||
route.pathname ||
|
|
||||||
route.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);
|
|
||||||
await writeWebResponse(incomingResponse, response);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (result.status === 404) {
|
|
||||||
const fourOhFourRoute = await matchRoute('/404', env, manifestData);
|
|
||||||
return handleRoute({
|
|
||||||
...options,
|
|
||||||
matchedRoute: fourOhFourRoute,
|
|
||||||
url: new URL(pathname, url),
|
|
||||||
status: 404,
|
|
||||||
body,
|
|
||||||
origin,
|
|
||||||
env,
|
|
||||||
manifestData,
|
|
||||||
incomingRequest,
|
|
||||||
incomingResponse,
|
|
||||||
manifest,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let response = result;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
// We are in a recursion, and it's possible that this function is called itself with a status code
|
// We are in a recursion, and it's possible that this function is called itself with a status code
|
||||||
// By default, the status code passed via parameters is computed by the matched route.
|
// By default, the status code passed via parameters is computed by the matched route.
|
||||||
|
@ -291,23 +251,26 @@ export async function handleRoute({
|
||||||
return;
|
return;
|
||||||
} else if (status && response.status !== status && (status === 404 || status === 500)) {
|
} else if (status && response.status !== status && (status === 404 || status === 500)) {
|
||||||
// Response.status is read-only, so a clone is required to override
|
// Response.status is read-only, so a clone is required to override
|
||||||
response = new Response(result.body, { ...result, status });
|
response = new Response(response.body, { ...response, status });
|
||||||
}
|
}
|
||||||
await writeSSRResult(request, response, incomingResponse);
|
await writeSSRResult(request, response, incomingResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetScriptsAndStylesParams {
|
interface GetScriptsAndStylesParams {
|
||||||
env: DevelopmentEnvironment;
|
pipeline: DevPipeline;
|
||||||
filePath: URL;
|
filePath: URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getScriptsAndStyles({ env, filePath }: GetScriptsAndStylesParams) {
|
async function getScriptsAndStyles({ pipeline, filePath }: GetScriptsAndStylesParams) {
|
||||||
|
const moduleLoader = pipeline.getModuleLoader();
|
||||||
|
const settings = pipeline.getSettings();
|
||||||
|
const mode = pipeline.getEnvironment().mode;
|
||||||
// Add hoisted script tags
|
// Add hoisted script tags
|
||||||
const scripts = await getScriptsForURL(filePath, env.settings.config.root, env.loader);
|
const scripts = await getScriptsForURL(filePath, settings.config.root, moduleLoader);
|
||||||
|
|
||||||
// Inject HMR scripts
|
// Inject HMR scripts
|
||||||
if (isPage(filePath, env.settings) && env.mode === 'development') {
|
if (isPage(filePath, settings) && mode === 'development') {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: { type: 'module', src: '/@vite/client' },
|
props: { type: 'module', src: '/@vite/client' },
|
||||||
children: '',
|
children: '',
|
||||||
|
@ -315,20 +278,20 @@ async function getScriptsAndStyles({ env, filePath }: GetScriptsAndStylesParams)
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: {
|
props: {
|
||||||
type: 'module',
|
type: 'module',
|
||||||
src: await resolveIdToUrl(env.loader, 'astro/runtime/client/hmr.js'),
|
src: await resolveIdToUrl(moduleLoader, 'astro/runtime/client/hmr.js'),
|
||||||
},
|
},
|
||||||
children: '',
|
children: '',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We should allow adding generic HTML elements to the head, not just scripts
|
// TODO: We should allow adding generic HTML elements to the head, not just scripts
|
||||||
for (const script of env.settings.scripts) {
|
for (const script of settings.scripts) {
|
||||||
if (script.stage === 'head-inline') {
|
if (script.stage === 'head-inline') {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: {},
|
props: {},
|
||||||
children: script.content,
|
children: script.content,
|
||||||
});
|
});
|
||||||
} else if (script.stage === 'page' && isPage(filePath, env.settings)) {
|
} else if (script.stage === 'page' && isPage(filePath, settings)) {
|
||||||
scripts.add({
|
scripts.add({
|
||||||
props: { type: 'module', src: `/@id/${PAGE_SCRIPT_ID}` },
|
props: { type: 'module', src: `/@id/${PAGE_SCRIPT_ID}` },
|
||||||
children: '',
|
children: '',
|
||||||
|
@ -337,7 +300,7 @@ async function getScriptsAndStyles({ env, filePath }: GetScriptsAndStylesParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass framework CSS in as style tags to be appended to the page.
|
// Pass framework CSS in as style tags to be appended to the page.
|
||||||
const { urls: styleUrls, stylesMap } = await getStylesForURL(filePath, env.loader, env.mode);
|
const { urls: styleUrls, stylesMap } = await getStylesForURL(filePath, moduleLoader, mode);
|
||||||
let links = new Set<SSRElement>();
|
let links = new Set<SSRElement>();
|
||||||
[...styleUrls].forEach((href) => {
|
[...styleUrls].forEach((href) => {
|
||||||
links.add({
|
links.add({
|
||||||
|
@ -364,13 +327,13 @@ async function getScriptsAndStyles({ env, filePath }: GetScriptsAndStylesParams)
|
||||||
props: {
|
props: {
|
||||||
type: 'text/css',
|
type: 'text/css',
|
||||||
// Track the ID so we can match it to Vite's injected style later
|
// Track the ID so we can match it to Vite's injected style later
|
||||||
'data-astro-dev-id': viteID(new URL(`.${url}`, env.settings.config.root)),
|
'data-astro-dev-id': viteID(new URL(`.${url}`, settings.config.root)),
|
||||||
},
|
},
|
||||||
children: content,
|
children: content,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const metadata = await getComponentMetadata(filePath, env.loader);
|
const metadata = await getComponentMetadata(filePath, moduleLoader);
|
||||||
|
|
||||||
return { scripts, styles, links, metadata };
|
return { scripts, styles, links, metadata };
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,8 @@ import { createContainer } from '../../../dist/core/dev/container.js';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import testAdapter from '../../test-adapter.js';
|
import testAdapter from '../../test-adapter.js';
|
||||||
import { getSortedPreloadedMatches } from '../../../dist/prerender/routing.js';
|
import { getSortedPreloadedMatches } from '../../../dist/prerender/routing.js';
|
||||||
import { createDevelopmentEnvironment } from '../../../dist/vite-plugin-astro-server/environment.js';
|
|
||||||
import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js';
|
import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js';
|
||||||
|
import DevPipeline from '../../../dist/vite-plugin-astro-server/devPipeline.js';
|
||||||
|
|
||||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||||
const fileSystem = {
|
const fileSystem = {
|
||||||
|
@ -124,7 +124,7 @@ const fileSystem = {
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Route matching', () => {
|
describe('Route matching', () => {
|
||||||
let env;
|
let pipeline;
|
||||||
let manifestData;
|
let manifestData;
|
||||||
let container;
|
let container;
|
||||||
let settings;
|
let settings;
|
||||||
|
@ -145,7 +145,7 @@ describe('Route matching', () => {
|
||||||
|
|
||||||
const loader = createViteLoader(container.viteServer);
|
const loader = createViteLoader(container.viteServer);
|
||||||
const manifest = createDevelopmentManifest(container.settings);
|
const manifest = createDevelopmentManifest(container.settings);
|
||||||
env = createDevelopmentEnvironment(manifest, container.settings, defaultLogging, loader);
|
pipeline = new DevPipeline({ manifest, logging: defaultLogging, settings, loader });
|
||||||
manifestData = createRouteManifest(
|
manifestData = createRouteManifest(
|
||||||
{
|
{
|
||||||
cwd: fileURLToPath(root),
|
cwd: fileURLToPath(root),
|
||||||
|
@ -163,7 +163,7 @@ describe('Route matching', () => {
|
||||||
describe('Matched routes', () => {
|
describe('Matched routes', () => {
|
||||||
it('should be sorted correctly', async () => {
|
it('should be sorted correctly', async () => {
|
||||||
const matches = matchAllRoutes('/try-matching-a-route', manifestData);
|
const matches = matchAllRoutes('/try-matching-a-route', manifestData);
|
||||||
const preloadedMatches = await getSortedPreloadedMatches({ env, matches, settings });
|
const preloadedMatches = await getSortedPreloadedMatches({ pipeline, matches, settings });
|
||||||
const sortedRouteNames = preloadedMatches.map((match) => match.route.route);
|
const sortedRouteNames = preloadedMatches.map((match) => match.route.route);
|
||||||
|
|
||||||
expect(sortedRouteNames).to.deep.equal([
|
expect(sortedRouteNames).to.deep.equal([
|
||||||
|
@ -177,7 +177,7 @@ describe('Route matching', () => {
|
||||||
});
|
});
|
||||||
it('nested should be sorted correctly', async () => {
|
it('nested should be sorted correctly', async () => {
|
||||||
const matches = matchAllRoutes('/nested/try-matching-a-route', manifestData);
|
const matches = matchAllRoutes('/nested/try-matching-a-route', manifestData);
|
||||||
const preloadedMatches = await getSortedPreloadedMatches({ env, matches, settings });
|
const preloadedMatches = await getSortedPreloadedMatches({ pipeline, matches, settings });
|
||||||
const sortedRouteNames = preloadedMatches.map((match) => match.route.route);
|
const sortedRouteNames = preloadedMatches.map((match) => match.route.route);
|
||||||
|
|
||||||
expect(sortedRouteNames).to.deep.equal([
|
expect(sortedRouteNames).to.deep.equal([
|
||||||
|
|
|
@ -1,31 +1,35 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import { createLoader } from '../../../dist/core/module-loader/index.js';
|
import { createLoader } from '../../../dist/core/module-loader/index.js';
|
||||||
import { createRouteManifest } from '../../../dist/core/routing/index.js';
|
import { createRouteManifest } from '../../../dist/core/routing/index.js';
|
||||||
import { createComponent, render } from '../../../dist/runtime/server/index.js';
|
import { createComponent, render } from '../../../dist/runtime/server/index.js';
|
||||||
import { createController, handleRequest } from '../../../dist/vite-plugin-astro-server/index.js';
|
import { createController, handleRequest } from '../../../dist/vite-plugin-astro-server/index.js';
|
||||||
import {
|
import {
|
||||||
createAstroModule,
|
createAstroModule,
|
||||||
createBasicEnvironment,
|
|
||||||
createBasicSettings,
|
createBasicSettings,
|
||||||
createFs,
|
createFs,
|
||||||
createRequestAndResponse,
|
createRequestAndResponse,
|
||||||
defaultLogging,
|
defaultLogging,
|
||||||
} from '../test-utils.js';
|
} from '../test-utils.js';
|
||||||
|
import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js';
|
||||||
|
import DevPipeline from '../../../dist/vite-plugin-astro-server/devPipeline.js';
|
||||||
|
|
||||||
async function createDevEnvironment(overrides = {}) {
|
async function createDevPipeline(overrides = {}) {
|
||||||
const env = createBasicEnvironment();
|
const settings = overrides.settings ?? (await createBasicSettings({ root: '/' }));
|
||||||
env.settings = await createBasicSettings({ root: '/' });
|
const loader = overrides.loader ?? createLoader();
|
||||||
env.settings.renderers = [];
|
const manifest = createDevelopmentManifest(settings);
|
||||||
env.loader = createLoader();
|
|
||||||
Object.assign(env, overrides);
|
return new DevPipeline({
|
||||||
return env;
|
manifest,
|
||||||
|
settings,
|
||||||
|
logging: defaultLogging,
|
||||||
|
loader,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('vite-plugin-astro-server', () => {
|
describe('vite-plugin-astro-server', () => {
|
||||||
describe('request', () => {
|
describe('request', () => {
|
||||||
it('renders a request', async () => {
|
it('renders a request', async () => {
|
||||||
const env = await createDevEnvironment({
|
const pipeline = await createDevPipeline({
|
||||||
loader: createLoader({
|
loader: createLoader({
|
||||||
import() {
|
import() {
|
||||||
const Page = createComponent(() => {
|
const Page = createComponent(() => {
|
||||||
|
@ -35,7 +39,7 @@ describe('vite-plugin-astro-server', () => {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const controller = createController({ loader: env.loader });
|
const controller = createController({ loader: pipeline.getModuleLoader() });
|
||||||
const { req, res, text } = createRequestAndResponse();
|
const { req, res, text } = createRequestAndResponse();
|
||||||
const fs = createFs(
|
const fs = createFs(
|
||||||
{
|
{
|
||||||
|
@ -47,14 +51,14 @@ describe('vite-plugin-astro-server', () => {
|
||||||
const manifestData = createRouteManifest(
|
const manifestData = createRouteManifest(
|
||||||
{
|
{
|
||||||
fsMod: fs,
|
fsMod: fs,
|
||||||
settings: env.settings,
|
settings: pipeline.getSettings(),
|
||||||
},
|
},
|
||||||
defaultLogging
|
defaultLogging
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await handleRequest({
|
await handleRequest({
|
||||||
env,
|
pipeline,
|
||||||
manifestData,
|
manifestData,
|
||||||
controller,
|
controller,
|
||||||
incomingRequest: req,
|
incomingRequest: req,
|
||||||
|
|
Loading…
Add table
Reference in a new issue