astro 2.7.4 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/@types/astro.d.ts +47 -13
  2. package/dist/cli/index.js +54 -5
  3. package/dist/core/app/index.js +4 -8
  4. package/dist/core/app/types.d.ts +2 -2
  5. package/dist/core/build/generate.d.ts +9 -1
  6. package/dist/core/build/generate.js +45 -46
  7. package/dist/core/build/index.d.ts +1 -1
  8. package/dist/core/build/index.js +19 -1
  9. package/dist/core/build/internal.d.ts +1 -0
  10. package/dist/core/build/plugins/index.js +1 -1
  11. package/dist/core/build/plugins/plugin-middleware.d.ts +3 -2
  12. package/dist/core/build/plugins/plugin-middleware.js +22 -3
  13. package/dist/core/build/plugins/plugin-pages.js +6 -4
  14. package/dist/core/build/plugins/plugin-ssr.js +4 -2
  15. package/dist/core/build/static-build.js +0 -3
  16. package/dist/core/config/schema.d.ts +12 -0
  17. package/dist/core/config/schema.js +6 -3
  18. package/dist/core/constants.js +1 -1
  19. package/dist/core/dev/dev.js +1 -1
  20. package/dist/core/endpoint/dev/index.d.ts +1 -2
  21. package/dist/core/endpoint/dev/index.js +2 -3
  22. package/dist/core/endpoint/index.d.ts +9 -4
  23. package/dist/core/endpoint/index.js +3 -3
  24. package/dist/core/messages.js +2 -2
  25. package/dist/core/middleware/index.d.ts +31 -2
  26. package/dist/core/middleware/index.js +47 -1
  27. package/dist/core/render/context.d.ts +2 -6
  28. package/dist/core/render/context.js +2 -6
  29. package/dist/core/render/core.d.ts +1 -2
  30. package/dist/core/render/core.js +2 -11
  31. package/dist/core/render/dev/environment.js +1 -0
  32. package/dist/core/render/dev/index.d.ts +0 -2
  33. package/dist/core/render/dev/index.js +0 -1
  34. package/dist/core/render/environment.d.ts +1 -0
  35. package/dist/core/render/result.d.ts +2 -4
  36. package/dist/core/render/result.js +10 -11
  37. package/dist/integrations/index.d.ts +8 -4
  38. package/dist/integrations/index.js +8 -8
  39. package/dist/runtime/server/hydration.d.ts +1 -1
  40. package/dist/runtime/server/jsx.js +1 -1
  41. package/dist/runtime/server/render/astro/instance.js +2 -2
  42. package/dist/runtime/server/render/component.js +1 -1
  43. package/dist/runtime/server/render/head.d.ts +3 -9
  44. package/dist/runtime/server/render/head.js +6 -9
  45. package/dist/runtime/server/render/page.d.ts +1 -1
  46. package/dist/runtime/server/render/page.js +9 -9
  47. package/dist/runtime/server/render/types.d.ts +0 -5
  48. package/dist/runtime/server/scripts.js +1 -1
  49. package/dist/vite-plugin-astro-server/route.js +1 -2
  50. package/package.json +2 -1
@@ -784,6 +784,26 @@ export interface AstroUserConfig {
784
784
  * ```
785
785
  */
786
786
  split?: boolean;
787
+ /**
788
+ * @docs
789
+ * @name build.excludeMiddleware
790
+ * @type {boolean}
791
+ * @default {false}
792
+ * @version 2.8.0
793
+ * @description
794
+ * Defines whether or not any SSR middleware code will be bundled when built.
795
+ *
796
+ * When enabled, middleware code is not bundled and imported by all pages during the build. To instead execute and import middleware code manually, set `build.excludeMiddleware: true`:
797
+ *
798
+ * ```js
799
+ * {
800
+ * build: {
801
+ * excludeMiddleware: true
802
+ * }
803
+ * }
804
+ * ```
805
+ */
806
+ excludeMiddleware?: boolean;
787
807
  };
788
808
  /**
789
809
  * @docs
@@ -1665,6 +1685,10 @@ export interface AstroIntegration {
1665
1685
  * the physical file you should import.
1666
1686
  */
1667
1687
  entryPoints: Map<RouteData, URL>;
1688
+ /**
1689
+ * File path of the emitted middleware
1690
+ */
1691
+ middlewareEntryPoint: URL | undefined;
1668
1692
  }) => void | Promise<void>;
1669
1693
  'astro:build:start'?: () => void | Promise<void>;
1670
1694
  'astro:build:setup'?: (options: {
@@ -1737,15 +1761,6 @@ export interface SSRElement {
1737
1761
  props: Record<string, any>;
1738
1762
  children: string;
1739
1763
  }
1740
- export interface SSRMetadata {
1741
- renderers: SSRLoadedRenderer[];
1742
- pathname: string;
1743
- hasHydrationScript: boolean;
1744
- hasDirectives: Set<string>;
1745
- hasRenderedHead: boolean;
1746
- headInTree: boolean;
1747
- clientDirectives: Map<string, string>;
1748
- }
1749
1764
  /**
1750
1765
  * A hint on whether the Astro runtime needs to wait on a component to render head
1751
1766
  * content. The meanings:
@@ -1766,15 +1781,34 @@ export interface SSRResult {
1766
1781
  scripts: Set<SSRElement>;
1767
1782
  links: Set<SSRElement>;
1768
1783
  componentMetadata: Map<string, SSRComponentMetadata>;
1769
- propagators: Map<AstroComponentFactory, AstroComponentInstance>;
1770
- extraHead: Array<string>;
1771
- cookies: AstroCookies | undefined;
1772
1784
  createAstro(Astro: AstroGlobalPartial, props: Record<string, any>, slots: Record<string, any> | null): AstroGlobal;
1773
1785
  resolve: (s: string) => Promise<string>;
1774
1786
  response: ResponseInit;
1775
- scope: number;
1787
+ renderers: SSRLoadedRenderer[];
1788
+ /**
1789
+ * Map of directive name (e.g. `load`) to the directive script code
1790
+ */
1791
+ clientDirectives: Map<string, string>;
1792
+ compressHTML: boolean;
1793
+ /**
1794
+ * Only used for logging
1795
+ */
1796
+ pathname: string;
1797
+ cookies: AstroCookies | undefined;
1776
1798
  _metadata: SSRMetadata;
1777
1799
  }
1800
+ /**
1801
+ * Ephemeral and mutable state during rendering that doesn't rely
1802
+ * on external configuration
1803
+ */
1804
+ export interface SSRMetadata {
1805
+ hasHydrationScript: boolean;
1806
+ hasDirectives: Set<string>;
1807
+ hasRenderedHead: boolean;
1808
+ headInTree: boolean;
1809
+ extraHead: string[];
1810
+ propagators: Map<AstroComponentFactory, AstroComponentInstance>;
1811
+ }
1778
1812
  export interface PreviewServer {
1779
1813
  host?: string;
1780
1814
  port: number;
package/dist/cli/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import fs from "fs";
2
2
  import * as colors from "kleur/colors";
3
+ import { arch, platform } from "node:os";
3
4
  import yargs from "yargs-parser";
4
5
  import { ZodError } from "zod";
5
6
  import {
@@ -29,6 +30,7 @@ function printAstroHelp() {
29
30
  ["check", "Check your project for errors."],
30
31
  ["dev", "Start the development server."],
31
32
  ["docs", "Open documentation in your web browser."],
33
+ ["info", "List info about your current Astro setup."],
32
34
  ["preview", "Preview your build locally."],
33
35
  ["sync", "Generate content collection types."],
34
36
  ["telemetry", "Configure telemetry settings."]
@@ -50,6 +52,48 @@ async function printVersion() {
50
52
  console.log();
51
53
  console.log(` ${colors.bgGreen(colors.black(` astro `))} ${colors.green(`v${ASTRO_VERSION}`)}`);
52
54
  }
55
+ async function printInfo({
56
+ cwd,
57
+ flags,
58
+ logging
59
+ }) {
60
+ var _a;
61
+ const whichPm = await import("which-pm");
62
+ const packageManager = await whichPm.default(process.cwd());
63
+ let adapter = "Couldn't determine.";
64
+ let integrations = [];
65
+ const MAX_PADDING = 25;
66
+ function printRow(label, value) {
67
+ const padding = MAX_PADDING - label.length;
68
+ console.log(`${colors.bold(label)}` + " ".repeat(padding) + `${colors.green(value)}`);
69
+ }
70
+ try {
71
+ const { userConfig } = await openConfig({
72
+ cwd,
73
+ flags,
74
+ cmd: "info",
75
+ logging
76
+ });
77
+ if ((_a = userConfig.adapter) == null ? void 0 : _a.name) {
78
+ adapter = userConfig.adapter.name;
79
+ }
80
+ if (userConfig.integrations) {
81
+ integrations = ((userConfig == null ? void 0 : userConfig.integrations) ?? []).filter(Boolean).flat().map((i) => i == null ? void 0 : i.name);
82
+ }
83
+ } catch (_e) {
84
+ }
85
+ console.log();
86
+ printRow("Astro version", `v${ASTRO_VERSION}`);
87
+ printRow("Package manager", packageManager.name);
88
+ printRow("Platform", platform());
89
+ printRow("Architecture", arch());
90
+ printRow("Adapter", adapter);
91
+ let integrationsString = "None or couldn't determine.";
92
+ if (integrations.length > 0) {
93
+ integrationsString = integrations.join(", ");
94
+ }
95
+ printRow("Integrations", integrationsString);
96
+ }
53
97
  function resolveCommand(flags) {
54
98
  const cmd = flags._[2];
55
99
  if (flags.version)
@@ -62,7 +106,8 @@ function resolveCommand(flags) {
62
106
  "build",
63
107
  "preview",
64
108
  "check",
65
- "docs"
109
+ "docs",
110
+ "info"
66
111
  ]);
67
112
  if (supportedCommands.has(cmd)) {
68
113
  return cmd;
@@ -86,6 +131,10 @@ async function handleConfigError(e, { cmd, cwd, flags, logging }) {
86
131
  async function runCommand(cmd, flags) {
87
132
  var _a;
88
133
  const root = flags.root;
134
+ let logging = {
135
+ dest: nodeLogDestination,
136
+ level: "info"
137
+ };
89
138
  switch (cmd) {
90
139
  case "help":
91
140
  printAstroHelp();
@@ -93,11 +142,11 @@ async function runCommand(cmd, flags) {
93
142
  case "version":
94
143
  await printVersion();
95
144
  return process.exit(0);
145
+ case "info": {
146
+ await printInfo({ cwd: root, flags, logging });
147
+ return process.exit(0);
148
+ }
96
149
  }
97
- let logging = {
98
- dest: nodeLogDestination,
99
- level: "info"
100
- };
101
150
  if (flags.verbose) {
102
151
  logging.level = "debug";
103
152
  enableVerboseLogging();
@@ -44,6 +44,7 @@ class App {
44
44
  logging: this.#logging,
45
45
  markdown: manifest.markdown,
46
46
  mode: "production",
47
+ compressHTML: manifest.compressHTML,
47
48
  renderers: manifest.renderers,
48
49
  clientDirectives: manifest.clientDirectives,
49
50
  async resolve(specifier) {
@@ -170,7 +171,6 @@ class App {
170
171
  const url = new URL(request.url);
171
172
  const pathname = prependForwardSlash(this.removeBase(url.pathname));
172
173
  const info = this.#routeDataToRouteInfo.get(routeData);
173
- const isCompressHTML = this.#manifest.compressHTML ?? false;
174
174
  const links = /* @__PURE__ */ new Set();
175
175
  const styles = createStylesheetElementSet(info.styles);
176
176
  let scripts = /* @__PURE__ */ new Set();
@@ -190,7 +190,6 @@ class App {
190
190
  const mod = await page.page();
191
191
  const renderContext = await createRenderContext({
192
192
  request,
193
- origin: url.origin,
194
193
  pathname,
195
194
  componentMetadata: this.#manifest.componentMetadata,
196
195
  scripts,
@@ -219,8 +218,7 @@ class App {
219
218
  mod,
220
219
  renderContext,
221
220
  env: this.#env,
222
- cookies: apiContext.cookies,
223
- isCompressHTML
221
+ cookies: apiContext.cookies
224
222
  });
225
223
  }
226
224
  );
@@ -229,8 +227,7 @@ class App {
229
227
  mod,
230
228
  renderContext,
231
229
  env: this.#env,
232
- cookies: apiContext.cookies,
233
- isCompressHTML
230
+ cookies: apiContext.cookies
234
231
  });
235
232
  }
236
233
  Reflect.set(request, responseSentSymbol, true);
@@ -250,14 +247,13 @@ class App {
250
247
  const handler = mod;
251
248
  const ctx = await createRenderContext({
252
249
  request,
253
- origin: url.origin,
254
250
  pathname,
255
251
  route: routeData,
256
252
  status,
257
253
  env: this.#env,
258
254
  mod: handler
259
255
  });
260
- const result = await callEndpoint(handler, this.#env, ctx, this.#logging, page.onRequest);
256
+ const result = await callEndpoint(handler, this.#env, ctx, page.onRequest);
261
257
  if (result.type === "response") {
262
258
  if (result.response.headers.get("X-Astro-Response") === "Not-Found") {
263
259
  const fourOhFourRequest = new Request(new URL("/404", request.url));
@@ -30,8 +30,8 @@ export type SSRManifest = {
30
30
  adapterName: string;
31
31
  routes: RouteInfo[];
32
32
  site?: string;
33
- base?: string;
34
- compressHTML?: boolean;
33
+ base: string;
34
+ compressHTML: boolean;
35
35
  assetsPrefix?: string;
36
36
  markdown: MarkdownRenderingOptions;
37
37
  renderers: SSRLoadedRenderer[];
@@ -1,7 +1,15 @@
1
1
  import type { OutputAsset, OutputChunk } from 'rollup';
2
- import type { AstroSettings } from '../../@types/astro';
2
+ import type { AstroSettings, SSRLoadedRenderer, SSRManifest } from '../../@types/astro';
3
3
  import { type BuildInternals } from '../../core/build/internal.js';
4
4
  import type { StaticBuildOptions } from './types';
5
5
  export declare function rootRelativeFacadeId(facadeId: string, settings: AstroSettings): string;
6
6
  export declare function chunkIsPage(settings: AstroSettings, output: OutputAsset | OutputChunk, internals: BuildInternals): boolean;
7
7
  export declare function generatePages(opts: StaticBuildOptions, internals: BuildInternals): Promise<void>;
8
+ /**
9
+ * It creates a `SSRManifest` from the `AstroSettings`.
10
+ *
11
+ * Renderers needs to be pulled out from the page module emitted during the build.
12
+ * @param settings
13
+ * @param renderers
14
+ */
15
+ export declare function generateRuntimeManifest(settings: AstroSettings, internals: BuildInternals, renderers: SSRLoadedRenderer[]): SSRManifest;
@@ -107,36 +107,35 @@ ${bgGreen(black(` ${verb} static routes `))}`);
107
107
  const manifest = ssrEntryPage.manifest;
108
108
  const ssrEntry = manifest == null ? void 0 : manifest.pageModule;
109
109
  if (ssrEntry) {
110
- await generatePage(opts, internals, pageData, ssrEntry, builtPaths);
110
+ await generatePage(opts, internals, pageData, ssrEntry, builtPaths, manifest);
111
111
  } else {
112
112
  throw new Error(
113
113
  `Unable to find the manifest for the module ${ssrEntryURLPage.toString()}. This is unexpected and likely a bug in Astro, please report.`
114
114
  );
115
115
  }
116
116
  } else {
117
- await generatePage(
118
- opts,
119
- internals,
120
- pageData,
121
- ssrEntryPage,
122
- builtPaths
123
- );
117
+ const ssrEntry = ssrEntryPage;
118
+ const manifest = generateRuntimeManifest(opts.settings, internals, ssrEntry.renderers);
119
+ await generatePage(opts, internals, pageData, ssrEntry, builtPaths, manifest);
124
120
  }
125
121
  }
126
122
  }
127
123
  for (const pageData of eachRedirectPageData(internals)) {
128
124
  const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
129
- await generatePage(opts, internals, pageData, entry, builtPaths);
125
+ const manifest = generateRuntimeManifest(opts.settings, internals, entry.renderers);
126
+ await generatePage(opts, internals, pageData, entry, builtPaths, manifest);
130
127
  }
131
128
  } else {
132
129
  for (const [pageData, filePath] of eachPageDataFromEntryPoint(internals)) {
133
130
  const ssrEntryURLPage = createEntryURL(filePath, outFolder);
134
- const ssrEntryPage = await import(ssrEntryURLPage.toString());
135
- await generatePage(opts, internals, pageData, ssrEntryPage, builtPaths);
131
+ const entry = await import(ssrEntryURLPage.toString());
132
+ const manifest = generateRuntimeManifest(opts.settings, internals, entry.renderers);
133
+ await generatePage(opts, internals, pageData, entry, builtPaths, manifest);
136
134
  }
137
135
  for (const pageData of eachRedirectPageData(internals)) {
138
136
  const entry = await getEntryForRedirectRoute(pageData.route, internals, outFolder);
139
- await generatePage(opts, internals, pageData, entry, builtPaths);
137
+ const manifest = generateRuntimeManifest(opts.settings, internals, entry.renderers);
138
+ await generatePage(opts, internals, pageData, entry, builtPaths, manifest);
140
139
  }
141
140
  }
142
141
  if (opts.settings.config.experimental.assets) {
@@ -166,12 +165,11 @@ async function generateImage(opts, transform, path) {
166
165
  const statsText = generationData.cached ? `(reused cache entry)` : `(before: ${generationData.weight.before}kb, after: ${generationData.weight.after}kb)`;
167
166
  info(opts.logging, null, ` ${green("\u25B6")} ${path} ${dim(statsText)} ${dim(timeIncrease)}`);
168
167
  }
169
- async function generatePage(opts, internals, pageData, ssrEntry, builtPaths) {
168
+ async function generatePage(opts, internals, pageData, ssrEntry, builtPaths, manifest) {
170
169
  if (routeIsRedirect(pageData.route) && !opts.settings.config.experimental.redirects) {
171
170
  throw new Error(`To use redirects first set experimental.redirects to \`true\``);
172
171
  }
173
172
  let timeStart = performance.now();
174
- const renderers = ssrEntry.renderers;
175
173
  const pageInfo = getPageDataByComponent(internals, pageData.route.component);
176
174
  const linkIds = [];
177
175
  const scripts = (pageInfo == null ? void 0 : pageInfo.hoistedScript) ?? null;
@@ -194,8 +192,7 @@ async function generatePage(opts, internals, pageData, ssrEntry, builtPaths) {
194
192
  linkIds,
195
193
  scripts,
196
194
  styles,
197
- mod: pageModule,
198
- renderers
195
+ mod: pageModule
199
196
  };
200
197
  const icon = pageData.route.type === "page" ? green("\u25B6") : magenta("\u03BB");
201
198
  if (isRelativePath(pageData.route.component)) {
@@ -206,7 +203,7 @@ async function generatePage(opts, internals, pageData, ssrEntry, builtPaths) {
206
203
  const paths = await getPathsForRoute(pageData, pageModule, opts, builtPaths);
207
204
  for (let i = 0; i < paths.length; i++) {
208
205
  const path = paths[i];
209
- await generatePath(path, opts, generationOptions, onRequest);
206
+ await generatePath(path, opts, generationOptions, manifest, onRequest);
210
207
  const timeEnd = performance.now();
211
208
  const timeChange = getTimeStat(timeStart, timeEnd);
212
209
  const timeIncrease = `(+${timeChange})`;
@@ -326,9 +323,9 @@ function getUrlForPath(pathname, base, origin, format, routeType) {
326
323
  const url = new URL(buildPathname, origin);
327
324
  return url;
328
325
  }
329
- async function generatePath(pathname, opts, gopts, onRequest) {
326
+ async function generatePath(pathname, opts, gopts, manifest, onRequest) {
330
327
  const { settings, logging, origin, routeCache } = opts;
331
- const { mod, internals, scripts: hoistedScripts, styles: _styles, pageData, renderers } = gopts;
328
+ const { mod, internals, scripts: hoistedScripts, styles: _styles, pageData } = gopts;
332
329
  if (pageData.route.type === "page") {
333
330
  addPageName(pathname, opts);
334
331
  }
@@ -336,24 +333,16 @@ async function generatePath(pathname, opts, gopts, onRequest) {
336
333
  const links = /* @__PURE__ */ new Set();
337
334
  const scripts = createModuleScriptsSet(
338
335
  hoistedScripts ? [hoistedScripts] : [],
339
- settings.config.base,
340
- settings.config.build.assetsPrefix
341
- );
342
- const styles = createStylesheetElementSet(
343
- _styles,
344
- settings.config.base,
345
- settings.config.build.assetsPrefix
336
+ manifest.base,
337
+ manifest.assetsPrefix
346
338
  );
339
+ const styles = createStylesheetElementSet(_styles, manifest.base, manifest.assetsPrefix);
347
340
  if (settings.scripts.some((script) => script.stage === "page")) {
348
341
  const hashedFilePath = internals.entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID);
349
342
  if (typeof hashedFilePath !== "string") {
350
343
  throw new Error(`Cannot find the built path for ${PAGE_SCRIPT_ID}`);
351
344
  }
352
- const src = createAssetLink(
353
- hashedFilePath,
354
- settings.config.base,
355
- settings.config.build.assetsPrefix
356
- );
345
+ const src = createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
357
346
  scripts.add({
358
347
  props: { type: "module", src },
359
348
  children: ""
@@ -376,12 +365,13 @@ async function generatePath(pathname, opts, gopts, onRequest) {
376
365
  pageData.route.type
377
366
  );
378
367
  const env = createEnvironment({
379
- adapterName: void 0,
368
+ adapterName: manifest.adapterName,
380
369
  logging,
381
- markdown: settings.config.markdown,
370
+ markdown: manifest.markdown,
382
371
  mode: opts.mode,
383
- renderers,
384
- clientDirectives: settings.clientDirectives,
372
+ renderers: manifest.renderers,
373
+ clientDirectives: manifest.clientDirectives,
374
+ compressHTML: manifest.compressHTML,
385
375
  async resolve(specifier) {
386
376
  const hashedFilePath = internals.entrySpecifierToBundleMap.get(specifier);
387
377
  if (typeof hashedFilePath !== "string") {
@@ -390,22 +380,17 @@ async function generatePath(pathname, opts, gopts, onRequest) {
390
380
  }
391
381
  throw new Error(`Cannot find the built path for ${specifier}`);
392
382
  }
393
- return createAssetLink(
394
- hashedFilePath,
395
- settings.config.base,
396
- settings.config.build.assetsPrefix
397
- );
383
+ return createAssetLink(hashedFilePath, manifest.base, manifest.assetsPrefix);
398
384
  },
399
385
  routeCache,
400
- site: settings.config.site ? new URL(settings.config.base, settings.config.site).toString() : settings.config.site,
386
+ site: manifest.site,
401
387
  ssr,
402
388
  streaming: true
403
389
  });
404
390
  const renderContext = await createRenderContext({
405
- origin,
406
391
  pathname,
407
392
  request: createRequest({ url, headers: new Headers(), logging, ssr }),
408
- componentMetadata: internals.componentMetadata,
393
+ componentMetadata: manifest.componentMetadata,
409
394
  scripts,
410
395
  styles,
411
396
  links,
@@ -421,7 +406,6 @@ async function generatePath(pathname, opts, gopts, onRequest) {
421
406
  endpointHandler,
422
407
  env,
423
408
  renderContext,
424
- logging,
425
409
  onRequest
426
410
  );
427
411
  if (result.type === "response") {
@@ -454,7 +438,6 @@ async function generatePath(pathname, opts, gopts, onRequest) {
454
438
  mod,
455
439
  renderContext,
456
440
  env,
457
- isCompressHTML: settings.config.compressHTML,
458
441
  cookies: apiContext.cookies
459
442
  });
460
443
  }
@@ -464,7 +447,6 @@ async function generatePath(pathname, opts, gopts, onRequest) {
464
447
  mod,
465
448
  renderContext,
466
449
  env,
467
- isCompressHTML: settings.config.compressHTML,
468
450
  cookies: apiContext.cookies
469
451
  });
470
452
  }
@@ -497,8 +479,25 @@ async function generatePath(pathname, opts, gopts, onRequest) {
497
479
  await fs.promises.mkdir(outFolder, { recursive: true });
498
480
  await fs.promises.writeFile(outFile, body, encoding ?? "utf-8");
499
481
  }
482
+ function generateRuntimeManifest(settings, internals, renderers) {
483
+ return {
484
+ assets: /* @__PURE__ */ new Set(),
485
+ entryModules: {},
486
+ routes: [],
487
+ adapterName: "",
488
+ markdown: settings.config.markdown,
489
+ clientDirectives: settings.clientDirectives,
490
+ compressHTML: settings.config.compressHTML,
491
+ renderers,
492
+ base: settings.config.base,
493
+ assetsPrefix: settings.config.build.assetsPrefix,
494
+ site: settings.config.site ? new URL(settings.config.base, settings.config.site).toString() : settings.config.site,
495
+ componentMetadata: internals.componentMetadata
496
+ };
497
+ }
500
498
  export {
501
499
  chunkIsPage,
502
500
  generatePages,
501
+ generateRuntimeManifest,
503
502
  rootRelativeFacadeId
504
503
  };
@@ -1,5 +1,5 @@
1
- import type { AstroSettings, RuntimeMode } from '../../@types/astro';
2
1
  import type yargs from 'yargs-parser';
2
+ import type { AstroSettings, RuntimeMode } from '../../@types/astro';
3
3
  import { type LogOptions } from '../logger/core.js';
4
4
  export interface BuildOptions {
5
5
  mode?: RuntimeMode;
@@ -8,7 +8,7 @@ import {
8
8
  runHookConfigSetup
9
9
  } from "../../integrations/index.js";
10
10
  import { createVite } from "../create-vite.js";
11
- import { debug, info, levels, timerMessage } from "../logger/core.js";
11
+ import { debug, info, levels, timerMessage, warn } from "../logger/core.js";
12
12
  import { printHelp } from "../messages.js";
13
13
  import { apply as applyPolyfill } from "../polyfill.js";
14
14
  import { RouteCache } from "../render/route-cache.js";
@@ -158,6 +158,24 @@ class AstroBuilder {
158
158
  `the outDir cannot be the root folder. Please build to a folder such as dist.`
159
159
  );
160
160
  }
161
+ if (config.build.split === true) {
162
+ if (config.output === "static") {
163
+ warn(
164
+ this.logging,
165
+ "configuration",
166
+ 'The option `build.split` won\'t take effect, because `output` is not `"server"` or `"hybrid"`.'
167
+ );
168
+ }
169
+ }
170
+ if (config.build.excludeMiddleware === true) {
171
+ if (config.output === "static") {
172
+ warn(
173
+ this.logging,
174
+ "configuration",
175
+ 'The option `build.excludeMiddleware` won\'t take effect, because `output` is not `"server"` or `"hybrid"`.'
176
+ );
177
+ }
178
+ }
161
179
  }
162
180
  /** Stats */
163
181
  async printStats({
@@ -64,6 +64,7 @@ export interface BuildInternals {
64
64
  entryPoints: Map<RouteData, URL>;
65
65
  ssrSplitEntryChunks: Map<string, Rollup.OutputChunk>;
66
66
  componentMetadata: SSRResult['componentMetadata'];
67
+ middlewareEntryPoint?: URL;
67
68
  }
68
69
  /**
69
70
  * Creates internal maps used to coordinate the CSS and HTML plugins.
@@ -17,7 +17,7 @@ function registerAllPlugins({ internals, options, register }) {
17
17
  register(pluginAnalyzer(internals));
18
18
  register(pluginInternals(internals));
19
19
  register(pluginRenderers(options));
20
- register(pluginMiddleware(options));
20
+ register(pluginMiddleware(options, internals));
21
21
  register(pluginPages(options, internals));
22
22
  register(pluginCSS(options, internals));
23
23
  register(astroHeadBuildPlugin(internals));
@@ -1,6 +1,7 @@
1
1
  import type { Plugin as VitePlugin } from 'vite';
2
+ import type { BuildInternals } from '../internal';
2
3
  import type { AstroBuildPlugin } from '../plugin';
3
4
  import type { StaticBuildOptions } from '../types';
4
5
  export declare const MIDDLEWARE_MODULE_ID = "@astro-middleware";
5
- export declare function vitePluginMiddleware(opts: StaticBuildOptions): VitePlugin;
6
- export declare function pluginMiddleware(opts: StaticBuildOptions): AstroBuildPlugin;
6
+ export declare function vitePluginMiddleware(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin;
7
+ export declare function pluginMiddleware(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin;
@@ -2,7 +2,8 @@ import { MIDDLEWARE_PATH_SEGMENT_NAME } from "../../constants.js";
2
2
  import { addRollupInput } from "../add-rollup-input.js";
3
3
  const MIDDLEWARE_MODULE_ID = "@astro-middleware";
4
4
  const EMPTY_MIDDLEWARE = "\0empty-middleware";
5
- function vitePluginMiddleware(opts) {
5
+ function vitePluginMiddleware(opts, internals) {
6
+ let resolvedMiddlewareId;
6
7
  return {
7
8
  name: "@astro/plugin-middleware",
8
9
  options(options) {
@@ -14,6 +15,7 @@ function vitePluginMiddleware(opts) {
14
15
  `${opts.settings.config.srcDir.pathname}/${MIDDLEWARE_PATH_SEGMENT_NAME}`
15
16
  );
16
17
  if (middlewareId) {
18
+ resolvedMiddlewareId = middlewareId.id;
17
19
  return middlewareId.id;
18
20
  } else {
19
21
  return EMPTY_MIDDLEWARE;
@@ -26,17 +28,34 @@ function vitePluginMiddleware(opts) {
26
28
  load(id) {
27
29
  if (id === EMPTY_MIDDLEWARE) {
28
30
  return "export const onRequest = undefined";
31
+ } else if (id === resolvedMiddlewareId) {
32
+ this.emitFile({
33
+ type: "chunk",
34
+ preserveSignature: "strict",
35
+ fileName: "middleware.mjs",
36
+ id
37
+ });
38
+ }
39
+ },
40
+ writeBundle(_, bundle) {
41
+ for (const [chunkName, chunk] of Object.entries(bundle)) {
42
+ if (chunk.type === "asset") {
43
+ continue;
44
+ }
45
+ if (chunk.fileName === "middleware.mjs") {
46
+ internals.middlewareEntryPoint = new URL(chunkName, opts.settings.config.build.server);
47
+ }
29
48
  }
30
49
  }
31
50
  };
32
51
  }
33
- function pluginMiddleware(opts) {
52
+ function pluginMiddleware(opts, internals) {
34
53
  return {
35
54
  build: "ssr",
36
55
  hooks: {
37
56
  "build:before": () => {
38
57
  return {
39
- vitePlugin: vitePluginMiddleware(opts)
58
+ vitePlugin: vitePluginMiddleware(opts, internals)
40
59
  };
41
60
  }
42
61
  }
@@ -50,10 +50,12 @@ function vitePluginPages(opts, internals) {
50
50
  exports.push(`export { page }`);
51
51
  imports.push(`import { renderers } from "${RENDERERS_MODULE_ID}";`);
52
52
  exports.push(`export { renderers };`);
53
- const middlewareModule = await this.resolve(MIDDLEWARE_MODULE_ID);
54
- if (middlewareModule) {
55
- imports.push(`import { onRequest } from "${middlewareModule.id}";`);
56
- exports.push(`export { onRequest };`);
53
+ if (!opts.settings.config.build.excludeMiddleware) {
54
+ const middlewareModule = await this.resolve(MIDDLEWARE_MODULE_ID);
55
+ if (middlewareModule) {
56
+ imports.push(`import { onRequest } from "${middlewareModule.id}";`);
57
+ exports.push(`export { onRequest };`);
58
+ }
57
59
  }
58
60
  return `${imports.join("\n")}${exports.join("\n")}`;
59
61
  }
@@ -108,7 +108,8 @@ function pluginSSR(options, internals) {
108
108
  config: options.settings.config,
109
109
  manifest,
110
110
  logging: options.logging,
111
- entryPoints: internals.entryPoints
111
+ entryPoints: internals.entryPoints,
112
+ middlewareEntryPoint: internals.middlewareEntryPoint
112
113
  });
113
114
  const code = injectManifest(manifest, internals.ssrEntryChunk);
114
115
  mutate(internals.ssrEntryChunk, "server", code);
@@ -206,7 +207,8 @@ function pluginSSRSplit(options, internals) {
206
207
  config: options.settings.config,
207
208
  manifest,
208
209
  logging: options.logging,
209
- entryPoints: internals.entryPoints
210
+ entryPoints: internals.entryPoints,
211
+ middlewareEntryPoint: internals.middlewareEntryPoint
210
212
  });
211
213
  for (const [, chunk] of internals.ssrSplitEntryChunks) {
212
214
  const code = injectManifest(manifest, chunk);
@@ -24,7 +24,6 @@ import { generatePages } from "./generate.js";
24
24
  import { trackPageData } from "./internal.js";
25
25
  import { createPluginContainer } from "./plugin.js";
26
26
  import { registerAllPlugins } from "./plugins/index.js";
27
- import { MIDDLEWARE_MODULE_ID } from "./plugins/plugin-middleware.js";
28
27
  import { ASTRO_PAGE_RESOLVED_MODULE_ID } from "./plugins/plugin-pages.js";
29
28
  import { RESOLVED_RENDERERS_MODULE_ID } from "./plugins/plugin-renderers.js";
30
29
  import { RESOLVED_SPLIT_MODULE_ID, SSR_VIRTUAL_MODULE_ID } from "./plugins/plugin-ssr.js";
@@ -141,8 +140,6 @@ async function ssrBuild(opts, internals, input, container) {
141
140
  );
142
141
  } else if ((_b2 = chunkInfo.facadeModuleId) == null ? void 0 : _b2.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
143
142
  return makeSplitEntryPointFileName(chunkInfo.facadeModuleId, routes);
144
- } else if (chunkInfo.facadeModuleId === MIDDLEWARE_MODULE_ID) {
145
- return "middleware.mjs";
146
143
  } else if (chunkInfo.facadeModuleId === SSR_VIRTUAL_MODULE_ID) {
147
144
  return opts.settings.config.build.serverEntry;
148
145
  } else if (chunkInfo.facadeModuleId === RESOLVED_RENDERERS_MODULE_ID) {