Skip to content

Commit e5fb82d

Browse files
committed
refactor(dev): use entry point to bootstrap the app
1 parent 5c41688 commit e5fb82d

5 files changed

Lines changed: 140 additions & 133 deletions

File tree

packages/astro/src/core/create-vite.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export async function createVite(
151151
astroScriptsPlugin({ settings }),
152152
// The server plugin is for dev only and having it run during the build causes
153153
// the build to run very slow as the filewatcher is triggered often.
154-
command === 'dev' && vitePluginAstroServer({ settings, logger, fs }), // manifest is only required in dev mode, where it gets created before a Vite instance is created, and get passed to this function
154+
command === 'dev' && vitePluginAstroServer({ settings, logger }),
155155
importMetaEnv({ envLoader }),
156156
astroEnv({ settings, sync, envLoader }),
157157
markdownVitePlugin({ settings, logger }),

packages/astro/src/manifest/serialized.ts

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
import type { Plugin } from 'vite';
2+
import { toFallbackType } from '../core/app/common.js';
3+
import { toRoutingStrategy } from '../core/app/index.js';
4+
import type { SerializedSSRManifest, SSRManifestCSP, SSRManifestI18n } from '../core/app/types.js';
5+
import {
6+
getAlgorithm,
7+
getDirectives,
8+
getScriptHashes,
9+
getScriptResources,
10+
getStrictDynamic,
11+
getStyleHashes,
12+
getStyleResources,
13+
shouldTrackCspHashes,
14+
} from '../core/csp/common.js';
15+
import { createKey, encodeKey, getEnvironmentKey, hasEnvironmentKey } from '../core/encryption.js';
216
import type { AstroSettings } from '../types/astro.js';
3-
import { createSerializedManifest } from '../vite-plugin-astro-server/plugin.js';
417

518
export const SERIALIZED_MANIFEST_ID = 'astro:serialized-manifest';
619
const SERIALIZED_MANIFEST_RESOLVED_ID = '\0' + SERIALIZED_MANIFEST_ID;
@@ -32,3 +45,67 @@ export async function serializedManifestPlugin({
3245
},
3346
};
3447
}
48+
49+
export async function createSerializedManifest(
50+
settings: AstroSettings,
51+
): Promise<SerializedSSRManifest> {
52+
let i18nManifest: SSRManifestI18n | undefined;
53+
let csp: SSRManifestCSP | undefined;
54+
if (settings.config.i18n) {
55+
i18nManifest = {
56+
fallback: settings.config.i18n.fallback,
57+
strategy: toRoutingStrategy(settings.config.i18n.routing, settings.config.i18n.domains),
58+
defaultLocale: settings.config.i18n.defaultLocale,
59+
locales: settings.config.i18n.locales,
60+
domainLookupTable: {},
61+
fallbackType: toFallbackType(settings.config.i18n.routing),
62+
};
63+
}
64+
65+
if (shouldTrackCspHashes(settings.config.experimental.csp)) {
66+
csp = {
67+
cspDestination: settings.adapter?.adapterFeatures?.experimentalStaticHeaders
68+
? 'adapter'
69+
: undefined,
70+
scriptHashes: getScriptHashes(settings.config.experimental.csp),
71+
scriptResources: getScriptResources(settings.config.experimental.csp),
72+
styleHashes: getStyleHashes(settings.config.experimental.csp),
73+
styleResources: getStyleResources(settings.config.experimental.csp),
74+
algorithm: getAlgorithm(settings.config.experimental.csp),
75+
directives: getDirectives(settings),
76+
isStrictDynamic: getStrictDynamic(settings.config.experimental.csp),
77+
};
78+
}
79+
80+
return {
81+
hrefRoot: settings.config.root.toString(),
82+
srcDir: settings.config.srcDir,
83+
cacheDir: settings.config.cacheDir,
84+
outDir: settings.config.outDir,
85+
buildServerDir: settings.config.build.server,
86+
buildClientDir: settings.config.build.client,
87+
publicDir: settings.config.publicDir,
88+
trailingSlash: settings.config.trailingSlash,
89+
buildFormat: settings.config.build.format,
90+
compressHTML: settings.config.compressHTML,
91+
assets: [],
92+
entryModules: {},
93+
routes: [],
94+
adapterName: settings?.adapter?.name ?? '',
95+
clientDirectives: Array.from(settings.clientDirectives.entries()),
96+
renderers: [],
97+
base: settings.config.base,
98+
userAssetsBase: settings.config?.vite?.base,
99+
assetsPrefix: settings.config.build.assetsPrefix,
100+
site: settings.config.site,
101+
componentMetadata: [],
102+
inlinedScripts: [],
103+
i18n: i18nManifest,
104+
checkOrigin:
105+
(settings.config.security?.checkOrigin && settings.buildOutput === 'server') ?? false,
106+
key: await encodeKey(hasEnvironmentKey() ? await getEnvironmentKey() : await createKey()),
107+
sessionConfig: settings.config.session,
108+
csp,
109+
serverIslandNameMap: [],
110+
};
111+
}

packages/astro/src/vite-plugin-astro-server/app.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ export class DevApp extends BaseApp<DevPipeline> {
5858
}
5959

6060
static async create(
61+
manifest: SSRManifest,
6162
routesList: RoutesList,
6263
settings: AstroSettings,
6364
logger: Logger,
6465
loader: ModuleLoader,
6566
): Promise<DevApp> {
66-
const { manifest } = await loader.import('astro:serialized-manifest');
67-
return new DevApp(manifest as SSRManifest, true, settings, logger, loader, routesList);
67+
return new DevApp(manifest, true, settings, logger, loader, routesList);
6868
}
6969

7070
createPipeline(
@@ -96,9 +96,10 @@ export class DevApp extends BaseApp<DevPipeline> {
9696
controller,
9797
incomingRequest,
9898
incomingResponse,
99+
isHttps,
99100
}: HandleRequest): Promise<void> {
100-
const { config, loader } = this.pipeline;
101-
const origin = `${loader.isHttps() ? 'https' : 'http'}://${
101+
const { config } = this.pipeline;
102+
const origin = `${isHttps ? 'https' : 'http'}://${
102103
incomingRequest.headers[':authority'] ?? incomingRequest.headers.host
103104
}`;
104105

@@ -150,8 +151,13 @@ export class DevApp extends BaseApp<DevPipeline> {
150151
});
151152
},
152153
onError(_err) {
153-
const { error, errorWithMetadata } = recordServerError(loader, config, self.logger, _err);
154-
handle500Response(loader, incomingResponse, errorWithMetadata);
154+
const { error, errorWithMetadata } = recordServerError(
155+
self.loader,
156+
config,
157+
self.logger,
158+
_err,
159+
);
160+
handle500Response(self.loader, incomingResponse, errorWithMetadata);
155161
return error;
156162
},
157163
});
@@ -439,6 +445,7 @@ type HandleRequest = {
439445
controller: DevServerController;
440446
incomingRequest: http.IncomingMessage;
441447
incomingResponse: http.ServerResponse;
448+
isHttps: boolean;
442449
};
443450

444451
type AsyncReturnType<T extends (...args: any) => Promise<any>> = T extends (
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// @ts-expect-error
2+
import { routes } from 'astro:routes';
3+
// @ts-expect-error
4+
import { manifest } from 'astro:serialized-manifest';
5+
import type http from 'node:http';
6+
import type { RouteInfo } from '../core/app/types.js';
7+
import { Logger } from '../core/logger/core.js';
8+
import { nodeLogDestination } from '../core/logger/node.js';
9+
import type { ModuleLoader } from '../core/module-loader/index.js';
10+
import type { AstroSettings, RoutesList } from '../types/astro.js';
11+
import { DevApp } from './app.js';
12+
import type { DevServerController } from './controller.js';
13+
14+
export default async function createExports(
15+
settings: AstroSettings,
16+
controller: DevServerController,
17+
loader: ModuleLoader,
18+
) {
19+
const logger = new Logger({
20+
dest: nodeLogDestination,
21+
level: 'info',
22+
});
23+
const routesList: RoutesList = { routes: routes.map((r: RouteInfo) => r.routeData) };
24+
const app = await DevApp.create(manifest, routesList, settings, logger, loader);
25+
26+
return {
27+
handler(incomingRequest: http.IncomingMessage, incomingResponse: http.ServerResponse) {
28+
app.handleRequest({
29+
controller,
30+
incomingRequest,
31+
incomingResponse,
32+
isHttps: loader.isHttps(),
33+
});
34+
},
35+
};
36+
}

packages/astro/src/vite-plugin-astro-server/plugin.ts

Lines changed: 12 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
import { AsyncLocalStorage } from 'node:async_hooks';
22
import { randomUUID } from 'node:crypto';
3-
import type fs from 'node:fs';
43
import { existsSync } from 'node:fs';
54
import { mkdir, readFile, writeFile } from 'node:fs/promises';
65
import { IncomingMessage } from 'node:http';
7-
import { fileURLToPath } from 'node:url';
6+
import { fileURLToPath, pathToFileURL } from 'node:url';
87
import type * as vite from 'vite';
9-
import { normalizePath } from 'vite';
108
import { toFallbackType } from '../core/app/common.js';
119
import { toRoutingStrategy } from '../core/app/index.js';
12-
import type {
13-
RouteInfo,
14-
SerializedSSRManifest,
15-
SSRManifest,
16-
SSRManifestCSP,
17-
SSRManifestI18n,
18-
} from '../core/app/types.js';
10+
import type { SSRManifest, SSRManifestCSP, SSRManifestI18n } from '../core/app/types.js';
1911
import {
2012
getAlgorithm,
2113
getDirectives,
@@ -26,18 +18,15 @@ import {
2618
getStyleResources,
2719
shouldTrackCspHashes,
2820
} from '../core/csp/common.js';
29-
import { warnMissingAdapter } from '../core/dev/adapter-validation.js';
30-
import { createKey, encodeKey, getEnvironmentKey, hasEnvironmentKey } from '../core/encryption.js';
21+
import { createKey, getEnvironmentKey, hasEnvironmentKey } from '../core/encryption.js';
3122
import { getViteErrorPayload } from '../core/errors/dev/index.js';
3223
import { AstroError, AstroErrorData } from '../core/errors/index.js';
3324
import { patchOverlay } from '../core/errors/overlay.js';
3425
import type { Logger } from '../core/logger/core.js';
3526
import { NOOP_MIDDLEWARE_FN } from '../core/middleware/noop-middleware.js';
3627
import { createViteLoader } from '../core/module-loader/index.js';
37-
import { getRoutePrerenderOption } from '../core/routing/manifest/prerender.js';
38-
import { runHookRoutesResolved } from '../integrations/hooks.js';
39-
import type { AstroSettings, RoutesList } from '../types/astro.js';
40-
import { DevApp } from './app.js';
28+
import { viteID } from '../core/util.js';
29+
import type { AstroSettings } from '../types/astro.js';
4130
import { baseMiddleware } from './base.js';
4231
import { createController } from './controller.js';
4332
import { recordServerError } from './error.js';
@@ -47,58 +36,24 @@ import { trailingSlashMiddleware } from './trailing-slash.js';
4736
interface AstroPluginOptions {
4837
settings: AstroSettings;
4938
logger: Logger;
50-
fs: typeof fs;
5139
}
5240

5341
export default function createVitePluginAstroServer({
5442
settings,
5543
logger,
56-
fs: fsMod,
5744
}: AstroPluginOptions): vite.Plugin {
5845
return {
5946
name: 'astro:server',
6047
async configureServer(viteServer) {
6148
const loader = createViteLoader(viteServer);
62-
const { routes } = await loader.import('astro:routes');
63-
const routesList: RoutesList = { routes: routes.map((r: RouteInfo) => r.routeData) };
64-
65-
const app = await DevApp.create(routesList, settings, logger, loader);
66-
49+
// NOTE: this is temporary, we will use the configuration and proper loading later
50+
// @ts-expect-error
51+
const url = pathToFileURL(import.meta.dirname + '/entrypoint.js');
52+
const createExports = await loader.import(viteID(url));
6753
const controller = createController({ loader });
68-
const localStorage = new AsyncLocalStorage();
54+
const { handler } = await createExports.default(settings, controller, loader);
6955

70-
/** rebuild the route cache + manifest */
71-
async function rebuildManifest(path: string | null = null) {
72-
app.clearRouteCache();
73-
74-
// If a route changes, we check if it's part of the manifest and check for its prerender value
75-
if (path !== null) {
76-
const route = routesList.routes.find(
77-
(r) =>
78-
normalizePath(path) ===
79-
normalizePath(fileURLToPath(new URL(r.component, settings.config.root))),
80-
);
81-
if (!route) {
82-
return;
83-
}
84-
if (route.type !== 'page' && route.type !== 'endpoint') return;
85-
86-
const routePath = fileURLToPath(new URL(route.component, settings.config.root));
87-
try {
88-
const content = await fsMod.promises.readFile(routePath, 'utf-8');
89-
await getRoutePrerenderOption(content, route, settings, logger);
90-
await runHookRoutesResolved({ routes: routesList.routes, settings, logger });
91-
} catch (_) {}
92-
}
93-
94-
warnMissingAdapter(logger, settings);
95-
app.setManifestData = routesList;
96-
}
97-
98-
// Rebuild route manifest on file change
99-
viteServer.watcher.on('add', rebuildManifest.bind(null, null));
100-
viteServer.watcher.on('unlink', rebuildManifest.bind(null, null));
101-
viteServer.watcher.on('change', rebuildManifest);
56+
const localStorage = new AsyncLocalStorage();
10257

10358
function handleUnhandledRejection(rejection: any) {
10459
const error = AstroError.is(rejection)
@@ -186,11 +141,7 @@ export default function createVitePluginAstroServer({
186141
return;
187142
}
188143
localStorage.run(request, () => {
189-
app.handleRequest({
190-
controller,
191-
incomingRequest: request,
192-
incomingResponse: response,
193-
});
144+
handler(request, response);
194145
});
195146
});
196147
};
@@ -281,67 +232,3 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest
281232
csp,
282233
};
283234
}
284-
285-
export async function createSerializedManifest(
286-
settings: AstroSettings,
287-
): Promise<SerializedSSRManifest> {
288-
let i18nManifest: SSRManifestI18n | undefined;
289-
let csp: SSRManifestCSP | undefined;
290-
if (settings.config.i18n) {
291-
i18nManifest = {
292-
fallback: settings.config.i18n.fallback,
293-
strategy: toRoutingStrategy(settings.config.i18n.routing, settings.config.i18n.domains),
294-
defaultLocale: settings.config.i18n.defaultLocale,
295-
locales: settings.config.i18n.locales,
296-
domainLookupTable: {},
297-
fallbackType: toFallbackType(settings.config.i18n.routing),
298-
};
299-
}
300-
301-
if (shouldTrackCspHashes(settings.config.experimental.csp)) {
302-
csp = {
303-
cspDestination: settings.adapter?.adapterFeatures?.experimentalStaticHeaders
304-
? 'adapter'
305-
: undefined,
306-
scriptHashes: getScriptHashes(settings.config.experimental.csp),
307-
scriptResources: getScriptResources(settings.config.experimental.csp),
308-
styleHashes: getStyleHashes(settings.config.experimental.csp),
309-
styleResources: getStyleResources(settings.config.experimental.csp),
310-
algorithm: getAlgorithm(settings.config.experimental.csp),
311-
directives: getDirectives(settings),
312-
isStrictDynamic: getStrictDynamic(settings.config.experimental.csp),
313-
};
314-
}
315-
316-
return {
317-
hrefRoot: settings.config.root.toString(),
318-
srcDir: settings.config.srcDir,
319-
cacheDir: settings.config.cacheDir,
320-
outDir: settings.config.outDir,
321-
buildServerDir: settings.config.build.server,
322-
buildClientDir: settings.config.build.client,
323-
publicDir: settings.config.publicDir,
324-
trailingSlash: settings.config.trailingSlash,
325-
buildFormat: settings.config.build.format,
326-
compressHTML: settings.config.compressHTML,
327-
assets: [],
328-
entryModules: {},
329-
routes: [],
330-
adapterName: settings?.adapter?.name ?? '',
331-
clientDirectives: Array.from(settings.clientDirectives.entries()),
332-
renderers: [],
333-
base: settings.config.base,
334-
userAssetsBase: settings.config?.vite?.base,
335-
assetsPrefix: settings.config.build.assetsPrefix,
336-
site: settings.config.site,
337-
componentMetadata: [],
338-
inlinedScripts: [],
339-
i18n: i18nManifest,
340-
checkOrigin:
341-
(settings.config.security?.checkOrigin && settings.buildOutput === 'server') ?? false,
342-
key: await encodeKey(hasEnvironmentKey() ? await getEnvironmentKey() : await createKey()),
343-
sessionConfig: settings.config.session,
344-
csp,
345-
serverIslandNameMap: [],
346-
};
347-
}

0 commit comments

Comments
 (0)