astro 4.11.6 → 4.12.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 (100) hide show
  1. package/client.d.ts +1 -0
  2. package/components/Code.astro +12 -0
  3. package/dist/@types/astro.d.ts +154 -74
  4. package/dist/actions/index.d.ts +4 -1
  5. package/dist/actions/index.js +15 -10
  6. package/dist/assets/internal.js +5 -12
  7. package/dist/assets/utils/index.d.ts +2 -1
  8. package/dist/assets/utils/index.js +3 -1
  9. package/dist/assets/utils/{emitAsset.d.ts → node/emitAsset.d.ts} +1 -1
  10. package/dist/assets/utils/{emitAsset.js → node/emitAsset.js} +2 -2
  11. package/dist/assets/utils/remoteProbe.d.ts +2 -2
  12. package/dist/assets/utils/remoteProbe.js +13 -6
  13. package/dist/assets/vite-plugin-assets.js +2 -1
  14. package/dist/cli/check/index.js +7 -5
  15. package/dist/cli/sync/index.d.ts +1 -1
  16. package/dist/cli/sync/index.js +6 -3
  17. package/dist/container/index.js +3 -1
  18. package/dist/content/runtime-assets.js +1 -1
  19. package/dist/content/vite-plugin-content-virtual-mod.js +4 -8
  20. package/dist/core/app/common.js +3 -1
  21. package/dist/core/app/index.js +3 -2
  22. package/dist/core/app/pipeline.d.ts +1 -1
  23. package/dist/core/app/pipeline.js +11 -11
  24. package/dist/core/app/types.d.ts +6 -2
  25. package/dist/core/base-pipeline.d.ts +21 -1
  26. package/dist/core/base-pipeline.js +3 -1
  27. package/dist/core/build/generate.js +1 -0
  28. package/dist/core/build/index.js +10 -6
  29. package/dist/core/build/pipeline.d.ts +6 -0
  30. package/dist/core/build/pipeline.js +11 -8
  31. package/dist/core/build/plugins/plugin-manifest.js +3 -1
  32. package/dist/core/build/plugins/plugin-ssr.js +8 -4
  33. package/dist/core/build/static-build.js +5 -5
  34. package/dist/core/config/schema.d.ts +37 -0
  35. package/dist/core/config/schema.js +5 -2
  36. package/dist/core/config/settings.js +2 -0
  37. package/dist/core/constants.d.ts +7 -0
  38. package/dist/core/constants.js +5 -1
  39. package/dist/core/create-vite.js +2 -2
  40. package/dist/core/dev/container.js +8 -0
  41. package/dist/core/dev/dev.js +1 -1
  42. package/dist/core/errors/dev/vite.js +1 -2
  43. package/dist/core/errors/errors-data.d.ts +2 -10
  44. package/dist/core/errors/errors-data.js +0 -6
  45. package/dist/core/errors/overlay.js +6 -7
  46. package/dist/core/index.d.ts +1 -1
  47. package/dist/core/index.js +1 -1
  48. package/dist/core/messages.js +2 -2
  49. package/dist/core/middleware/callMiddleware.js +6 -6
  50. package/dist/core/redirects/render.js +1 -2
  51. package/dist/core/render/paginate.js +8 -1
  52. package/dist/core/render-context.js +8 -1
  53. package/dist/core/routing/astro-designed-error-pages.d.ts +2 -7
  54. package/dist/core/routing/astro-designed-error-pages.js +4 -1
  55. package/dist/core/routing/default.d.ts +10 -0
  56. package/dist/core/routing/default.js +38 -0
  57. package/dist/core/routing/manifest/create.d.ts +1 -2
  58. package/dist/core/routing/manifest/create.js +2 -34
  59. package/dist/core/routing/manifest/pattern.d.ts +2 -0
  60. package/dist/core/routing/manifest/pattern.js +35 -0
  61. package/dist/core/server-islands/endpoint.d.ts +8 -0
  62. package/dist/core/server-islands/endpoint.js +76 -0
  63. package/dist/core/server-islands/vite-plugin-server-islands.d.ts +7 -0
  64. package/dist/core/server-islands/vite-plugin-server-islands.js +82 -0
  65. package/dist/core/sync/index.d.ts +13 -5
  66. package/dist/core/sync/index.js +36 -23
  67. package/dist/core/sync/setup-env-ts.d.ts +8 -0
  68. package/dist/{vite-plugin-inject-env-ts/index.js → core/sync/setup-env-ts.js} +11 -28
  69. package/dist/env/errors.d.ts +7 -0
  70. package/dist/env/errors.js +16 -0
  71. package/dist/env/runtime.d.ts +4 -3
  72. package/dist/env/runtime.js +9 -5
  73. package/dist/env/validators.d.ts +5 -3
  74. package/dist/env/vite-plugin-env.js +2 -11
  75. package/dist/integrations/hooks.d.ts +3 -1
  76. package/dist/integrations/hooks.js +5 -4
  77. package/dist/jsx/babel.js +6 -8
  78. package/dist/jsx/rehype.js +4 -8
  79. package/dist/jsx-runtime/index.js +1 -2
  80. package/dist/runtime/client/dev-toolbar/entrypoint.js +3 -2
  81. package/dist/runtime/server/render/component.d.ts +2 -1
  82. package/dist/runtime/server/render/component.js +4 -0
  83. package/dist/runtime/server/render/server-islands.d.ts +5 -0
  84. package/dist/runtime/server/render/server-islands.js +73 -0
  85. package/dist/runtime/server/render/slot.d.ts +2 -1
  86. package/dist/runtime/server/render/slot.js +8 -1
  87. package/dist/vite-plugin-astro/index.js +3 -1
  88. package/dist/vite-plugin-astro/metadata.d.ts +1 -0
  89. package/dist/vite-plugin-astro/metadata.js +12 -0
  90. package/dist/vite-plugin-astro/types.d.ts +1 -0
  91. package/dist/vite-plugin-astro-server/pipeline.d.ts +7 -0
  92. package/dist/vite-plugin-astro-server/pipeline.js +20 -5
  93. package/dist/vite-plugin-astro-server/plugin.js +5 -3
  94. package/dist/vite-plugin-astro-server/route.js +13 -14
  95. package/dist/vite-plugin-markdown/index.js +2 -8
  96. package/dist/vite-plugin-utils/index.d.ts +5 -0
  97. package/dist/vite-plugin-utils/index.js +5 -0
  98. package/package.json +5 -4
  99. package/templates/env/module.mjs +5 -2
  100. package/dist/vite-plugin-inject-env-ts/index.d.ts +0 -17
@@ -6,6 +6,7 @@ import {
6
6
  VIRTUAL_MODULES_IDS,
7
7
  VIRTUAL_MODULES_IDS_VALUES
8
8
  } from "./constants.js";
9
+ import { invalidVariablesToError } from "./errors.js";
9
10
  import { getEnvFieldType, validateEnvVariable } from "./validators.js";
10
11
  function astroEnv({
11
12
  settings,
@@ -93,19 +94,9 @@ function validatePublicVariables({
93
94
  }
94
95
  }
95
96
  if (invalid.length > 0) {
96
- const _errors = [];
97
- for (const { key, type, errors } of invalid) {
98
- if (errors[0] === "missing") {
99
- _errors.push(`${key} is missing`);
100
- } else if (errors[0] === "type") {
101
- _errors.push(`${key}'s type is invalid, expected: ${type}`);
102
- } else {
103
- _errors.push(`The following constraints for ${key} are not met: ${errors.join(", ")}`);
104
- }
105
- }
106
97
  throw new AstroError({
107
98
  ...AstroErrorData.EnvInvalidVariables,
108
- message: AstroErrorData.EnvInvalidVariables.message(_errors)
99
+ message: AstroErrorData.EnvInvalidVariables.message(invalidVariablesToError(invalid))
109
100
  });
110
101
  }
111
102
  return valid;
@@ -1,3 +1,4 @@
1
+ import fsMod from 'node:fs';
1
2
  import type { AddressInfo } from 'node:net';
2
3
  import type { InlineConfig, ViteDevServer } from 'vite';
3
4
  import type { AstroAdapter, AstroConfig, AstroSettings, RouteData } from '../@types/astro.js';
@@ -32,11 +33,12 @@ export declare function getToolbarServerCommunicationHelpers(server: ViteDevServ
32
33
  state: boolean;
33
34
  }) => void) => void;
34
35
  };
35
- export declare function runHookConfigSetup({ settings, command, logger, isRestart, }: {
36
+ export declare function runHookConfigSetup({ settings, command, logger, isRestart, fs, }: {
36
37
  settings: AstroSettings;
37
38
  command: 'dev' | 'build' | 'preview';
38
39
  logger: Logger;
39
40
  isRestart?: boolean;
41
+ fs?: typeof fsMod;
40
42
  }): Promise<AstroSettings>;
41
43
  export declare function runHookConfigDone({ settings, logger, }: {
42
44
  settings: AstroSettings;
@@ -1,4 +1,4 @@
1
- import fs from "node:fs";
1
+ import fsMod from "node:fs";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { bold } from "kleur/colors";
4
4
  import { buildClientDirectiveEntrypoint } from "../core/client-directive/index.js";
@@ -74,14 +74,15 @@ async function runHookConfigSetup({
74
74
  settings,
75
75
  command,
76
76
  logger,
77
- isRestart = false
77
+ isRestart = false,
78
+ fs = fsMod
78
79
  }) {
79
80
  if (settings.config.adapter) {
80
81
  settings.config.integrations.push(settings.config.adapter);
81
82
  }
82
83
  if (settings.config.experimental?.actions) {
83
84
  const { default: actionsIntegration } = await import("../actions/index.js");
84
- settings.config.integrations.push(actionsIntegration());
85
+ settings.config.integrations.push(actionsIntegration({ fs }));
85
86
  }
86
87
  let updatedConfig = { ...settings.config };
87
88
  let updatedSettings = { ...settings, config: updatedConfig };
@@ -399,7 +400,7 @@ async function runHookBuildDone({
399
400
  cacheManifest
400
401
  }) {
401
402
  const dir = isServerLikeOutput(config) ? config.build.client : config.outDir;
402
- await fs.promises.mkdir(dir, { recursive: true });
403
+ await fsMod.promises.mkdir(dir, { recursive: true });
403
404
  for (const integration of config.integrations) {
404
405
  if (integration?.hooks?.["astro:build:done"]) {
405
406
  const logger = getLogger(integration, logging);
package/dist/jsx/babel.js CHANGED
@@ -2,6 +2,7 @@ import * as t from "@babel/types";
2
2
  import { AstroError } from "../core/errors/errors.js";
3
3
  import { AstroErrorData } from "../core/errors/index.js";
4
4
  import { resolvePath } from "../core/viteUtils.js";
5
+ import { createDefaultAstroMetadata } from "../vite-plugin-astro/metadata.js";
5
6
  const ClientOnlyPlaceholder = "astro-client-only";
6
7
  function isComponent(tagName) {
7
8
  return tagName[0] && tagName[0].toLowerCase() !== tagName[0] || tagName.includes(".") || /[^a-zA-Z]/.test(tagName[0]);
@@ -118,14 +119,7 @@ function astroJSX() {
118
119
  Program: {
119
120
  enter(path, state) {
120
121
  if (!state.file.metadata.astro) {
121
- state.file.metadata.astro = {
122
- clientOnlyComponents: [],
123
- hydratedComponents: [],
124
- scripts: [],
125
- containsHead: false,
126
- propagation: "none",
127
- pageOptions: {}
128
- };
122
+ state.file.metadata.astro = createDefaultAstroMetadata();
129
123
  }
130
124
  path.node.body.splice(
131
125
  0,
@@ -194,6 +188,7 @@ function astroJSX() {
194
188
  if (isClientOnly) {
195
189
  state.file.metadata.astro.clientOnlyComponents.push({
196
190
  exportName: meta.name,
191
+ localName: "",
197
192
  specifier: tagName,
198
193
  resolvedPath
199
194
  });
@@ -202,6 +197,7 @@ function astroJSX() {
202
197
  } else {
203
198
  state.file.metadata.astro.hydratedComponents.push({
204
199
  exportName: "*",
200
+ localName: "",
205
201
  specifier: tagName,
206
202
  resolvedPath
207
203
  });
@@ -260,6 +256,7 @@ function astroJSX() {
260
256
  if (isClientOnly) {
261
257
  state.file.metadata.astro.clientOnlyComponents.push({
262
258
  exportName: meta.name,
259
+ localName: "",
263
260
  specifier: meta.name,
264
261
  resolvedPath
265
262
  });
@@ -268,6 +265,7 @@ function astroJSX() {
268
265
  } else {
269
266
  state.file.metadata.astro.hydratedComponents.push({
270
267
  exportName: meta.name,
268
+ localName: "",
271
269
  specifier: meta.name,
272
270
  resolvedPath
273
271
  });
@@ -2,17 +2,11 @@ import { visit } from "unist-util-visit";
2
2
  import { AstroError } from "../core/errors/errors.js";
3
3
  import { AstroErrorData } from "../core/errors/index.js";
4
4
  import { resolvePath } from "../core/viteUtils.js";
5
+ import { createDefaultAstroMetadata } from "../vite-plugin-astro/metadata.js";
5
6
  const ClientOnlyPlaceholder = "astro-client-only";
6
7
  const rehypeAnalyzeAstroMetadata = () => {
7
8
  return (tree, file) => {
8
- const metadata = {
9
- clientOnlyComponents: [],
10
- hydratedComponents: [],
11
- scripts: [],
12
- containsHead: false,
13
- propagation: "none",
14
- pageOptions: {}
15
- };
9
+ const metadata = createDefaultAstroMetadata();
16
10
  const imports = parseImports(tree.children);
17
11
  visit(tree, (node) => {
18
12
  if (node.type !== "mdxJsxFlowElement" && node.type !== "mdxJsxTextElement") return;
@@ -39,6 +33,7 @@ const rehypeAnalyzeAstroMetadata = () => {
39
33
  if (hasClientOnlyDirective(node)) {
40
34
  metadata.clientOnlyComponents.push({
41
35
  exportName: matchedImport.name,
36
+ localName: "",
42
37
  specifier: tagName,
43
38
  resolvedPath
44
39
  });
@@ -46,6 +41,7 @@ const rehypeAnalyzeAstroMetadata = () => {
46
41
  } else {
47
42
  metadata.hydratedComponents.push({
48
43
  exportName: "*",
44
+ localName: "",
49
45
  specifier: tagName,
50
46
  resolvedPath
51
47
  });
@@ -17,8 +17,7 @@ function transformSlots(vnode) {
17
17
  slots[name]["$$slot"] = true;
18
18
  delete child.props.slot;
19
19
  delete vnode.props.children;
20
- }
21
- if (Array.isArray(vnode.props.children)) {
20
+ } else if (Array.isArray(vnode.props.children)) {
22
21
  vnode.props.children = vnode.props.children.map((child) => {
23
22
  if (!isVNode(child)) return child;
24
23
  if (!("slot" in child.props)) return child;
@@ -75,8 +75,9 @@ document.addEventListener("DOMContentLoaded", async () => {
75
75
  eventTarget.addEventListener("toggle-notification", (evt) => {
76
76
  if (!(evt instanceof CustomEvent)) return;
77
77
  const target = overlay.shadowRoot?.querySelector(`[data-app-id="${app.id}"]`);
78
- const notificationElement = target?.querySelector(".notification");
79
- if (!target || !notificationElement) return;
78
+ if (!target) return;
79
+ const notificationElement = target.querySelector(".notification");
80
+ if (!notificationElement) return;
80
81
  let newState = evt.detail.state ?? true;
81
82
  let level = notificationLevels.includes(evt?.detail?.level) ? evt.detail.level : "error";
82
83
  app.notification.state = newState;
@@ -2,9 +2,10 @@ import type { RouteData, SSRResult } from '../../../@types/astro.js';
2
2
  import { type RenderInstruction } from './instruction.js';
3
3
  import type { HTMLBytes } from '../escape.js';
4
4
  import { type RenderInstance } from './common.js';
5
+ import { type ComponentSlots } from './slot.js';
5
6
  declare const needsHeadRenderingSymbol: unique symbol;
6
7
  export type ComponentIterable = AsyncIterable<string | HTMLBytes | RenderInstruction>;
7
- export declare function renderComponent(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: any): Promise<RenderInstance>;
8
+ export declare function renderComponent(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: ComponentSlots): Promise<RenderInstance>;
8
9
  export declare function renderComponentToString(result: SSRResult, displayName: string, Component: unknown, props: Record<string | number, any>, slots?: any, isPage?: boolean, route?: RouteData): Promise<string>;
9
10
  export type NonAstroPageComponent = {
10
11
  name: string;
@@ -16,6 +16,7 @@ import {
16
16
  } from "./common.js";
17
17
  import { componentIsHTMLElement, renderHTMLElement } from "./dom.js";
18
18
  import { maybeRenderHead } from "./head.js";
19
+ import { containsServerDirective, renderServerIsland } from "./server-islands.js";
19
20
  import { renderSlotToString, renderSlots } from "./slot.js";
20
21
  import { formatList, internalSpreadAttributes, renderElement, voidElementNames } from "./util.js";
21
22
  const needsHeadRenderingSymbol = Symbol.for("astro.needsHeadRendering");
@@ -358,6 +359,9 @@ async function renderHTMLComponent(result, Component, _props, slots = {}) {
358
359
  };
359
360
  }
360
361
  function renderAstroComponent(result, displayName, Component, props, slots = {}) {
362
+ if (containsServerDirective(props)) {
363
+ return renderServerIsland(result, displayName, props, slots);
364
+ }
361
365
  const instance = createAstroComponentInstance(result, displayName, Component, props, slots);
362
366
  return {
363
367
  async render(destination) {
@@ -0,0 +1,5 @@
1
+ import type { SSRResult } from '../../../@types/astro.js';
2
+ import type { RenderInstance } from './common.js';
3
+ import { type ComponentSlots } from './slot.js';
4
+ export declare function containsServerDirective(props: Record<string | number, any>): boolean;
5
+ export declare function renderServerIsland(result: SSRResult, _displayName: string, props: Record<string | number, any>, slots: ComponentSlots): RenderInstance;
@@ -0,0 +1,73 @@
1
+ import { renderChild } from "./any.js";
2
+ import { renderSlotToString } from "./slot.js";
3
+ const internalProps = /* @__PURE__ */ new Set([
4
+ "server:component-path",
5
+ "server:component-export",
6
+ "server:component-directive",
7
+ "server:defer"
8
+ ]);
9
+ function containsServerDirective(props) {
10
+ return "server:component-directive" in props;
11
+ }
12
+ function renderServerIsland(result, _displayName, props, slots) {
13
+ return {
14
+ async render(destination) {
15
+ const componentPath = props["server:component-path"];
16
+ const componentExport = props["server:component-export"];
17
+ const componentId = result.serverIslandNameMap.get(componentPath);
18
+ if (!componentId) {
19
+ throw new Error(`Could not find server component name`);
20
+ }
21
+ for (const key of Object.keys(props)) {
22
+ if (internalProps.has(key)) {
23
+ delete props[key];
24
+ }
25
+ }
26
+ destination.write("<!--server-island-start-->");
27
+ const renderedSlots = {};
28
+ for (const name in slots) {
29
+ if (name !== "fallback") {
30
+ const content = await renderSlotToString(result, slots[name]);
31
+ renderedSlots[name] = content.toString();
32
+ } else {
33
+ await renderChild(destination, slots.fallback(result));
34
+ }
35
+ }
36
+ const hostId = crypto.randomUUID();
37
+ destination.write(`<script async type="module" data-island-id="${hostId}">
38
+ let componentId = ${JSON.stringify(componentId)};
39
+ let componentExport = ${JSON.stringify(componentExport)};
40
+ let script = document.querySelector('script[data-island-id="${hostId}"]');
41
+ let data = {
42
+ componentExport,
43
+ props: ${JSON.stringify(props)},
44
+ slots: ${JSON.stringify(renderedSlots)},
45
+ };
46
+
47
+ let response = await fetch('/_server-islands/${componentId}', {
48
+ method: 'POST',
49
+ body: JSON.stringify(data),
50
+ });
51
+
52
+ if(response.status === 200 && response.headers.get('content-type') === 'text/html') {
53
+ let html = await response.text();
54
+
55
+ // Swap!
56
+ while(script.previousSibling?.nodeType !== 8 &&
57
+ script.previousSibling?.data !== 'server-island-start') {
58
+ script.previousSibling?.remove();
59
+ }
60
+ script.previousSibling?.remove();
61
+
62
+ let frag = document.createRange().createContextualFragment(html);
63
+ script.before(frag);
64
+ }
65
+ script.remove();
66
+ </script>`);
67
+ }
68
+ };
69
+ }
70
+ export {
71
+ containsServerDirective,
72
+ renderServerIsland
73
+ };
@@ -1,5 +1,5 @@
1
1
  import type { SSRResult } from '../../../@types/astro.js';
2
- import type { renderTemplate } from './astro/render-template.js';
2
+ import { renderTemplate } from './astro/render-template.js';
3
3
  import type { RenderInstruction } from './instruction.js';
4
4
  import { HTMLString } from '../escape.js';
5
5
  import { type RenderInstance } from './common.js';
@@ -20,4 +20,5 @@ interface RenderSlotsResult {
20
20
  children: Record<string, string>;
21
21
  }
22
22
  export declare function renderSlots(result: SSRResult, slots?: ComponentSlots): Promise<RenderSlotsResult>;
23
+ export declare function createSlotValueFromString(content: string): ComponentSlotValue;
23
24
  export {};
@@ -1,4 +1,5 @@
1
- import { HTMLString, markHTMLString } from "../escape.js";
1
+ import { renderTemplate } from "./astro/render-template.js";
2
+ import { HTMLString, markHTMLString, unescapeHTML } from "../escape.js";
2
3
  import { renderChild } from "./any.js";
3
4
  import { chunkToString } from "./common.js";
4
5
  const slotString = Symbol.for("astro:slot-string");
@@ -70,8 +71,14 @@ async function renderSlots(result, slots = {}) {
70
71
  }
71
72
  return { slotInstructions, children };
72
73
  }
74
+ function createSlotValueFromString(content) {
75
+ return function() {
76
+ return renderTemplate`${unescapeHTML(content)}`;
77
+ };
78
+ }
73
79
  export {
74
80
  SlotString,
81
+ createSlotValueFromString,
75
82
  isSlotString,
76
83
  renderSlot,
77
84
  renderSlotToString,
@@ -1,5 +1,5 @@
1
1
  import { normalizePath } from "vite";
2
- import { normalizeFilename } from "../vite-plugin-utils/index.js";
2
+ import { hasSpecialQueries, normalizeFilename } from "../vite-plugin-utils/index.js";
3
3
  import { compileAstro } from "./compile.js";
4
4
  import { handleHotUpdate } from "./hmr.js";
5
5
  import { parseAstroRequest } from "./query.js";
@@ -147,6 +147,7 @@ File: ${id}`
147
147
  }
148
148
  },
149
149
  async transform(source, id) {
150
+ if (hasSpecialQueries(id)) return;
150
151
  const parsedId = parseAstroRequest(id);
151
152
  if (!parsedId.filename.endsWith(".astro") || parsedId.query.astro) {
152
153
  return;
@@ -156,6 +157,7 @@ File: ${id}`
156
157
  const astroMetadata = {
157
158
  clientOnlyComponents: transformResult.clientOnlyComponents,
158
159
  hydratedComponents: transformResult.hydratedComponents,
160
+ serverComponents: transformResult.serverComponents,
159
161
  scripts: transformResult.scripts,
160
162
  containsHead: transformResult.containsHead,
161
163
  propagation: transformResult.propagation ? "self" : "none",
@@ -1,3 +1,4 @@
1
1
  import type { ModuleInfo } from '../core/module-loader/index.js';
2
2
  import type { PluginMetadata } from './types.js';
3
3
  export declare function getAstroMetadata(modInfo: ModuleInfo): PluginMetadata['astro'] | undefined;
4
+ export declare function createDefaultAstroMetadata(): PluginMetadata['astro'];
@@ -4,6 +4,18 @@ function getAstroMetadata(modInfo) {
4
4
  }
5
5
  return void 0;
6
6
  }
7
+ function createDefaultAstroMetadata() {
8
+ return {
9
+ hydratedComponents: [],
10
+ clientOnlyComponents: [],
11
+ serverComponents: [],
12
+ scripts: [],
13
+ propagation: "none",
14
+ containsHead: false,
15
+ pageOptions: {}
16
+ };
17
+ }
7
18
  export {
19
+ createDefaultAstroMetadata,
8
20
  getAstroMetadata
9
21
  };
@@ -8,6 +8,7 @@ export interface PluginMetadata {
8
8
  astro: {
9
9
  hydratedComponents: TransformResult['hydratedComponents'];
10
10
  clientOnlyComponents: TransformResult['clientOnlyComponents'];
11
+ serverComponents: TransformResult['serverComponents'];
11
12
  scripts: TransformResult['scripts'];
12
13
  containsHead: TransformResult['containsHead'];
13
14
  propagation: PropagationHint;
@@ -9,6 +9,12 @@ export declare class DevPipeline extends Pipeline {
9
9
  readonly manifest: SSRManifest;
10
10
  readonly settings: AstroSettings;
11
11
  readonly config: import("../@types/astro.js").AstroConfig;
12
+ readonly defaultRoutes: {
13
+ instance: ComponentInstance;
14
+ matchesComponent(filePath: URL): boolean;
15
+ route: string;
16
+ component: string;
17
+ }[];
12
18
  renderers: SSRLoadedRenderer[];
13
19
  manifestData: ManifestData | undefined;
14
20
  componentInterner: WeakMap<RouteData, ComponentInstance>;
@@ -21,4 +27,5 @@ export declare class DevPipeline extends Pipeline {
21
27
  getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
22
28
  tryRewrite(payload: RewritePayload, request: Request, _sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
23
29
  setManifestData(manifestData: ManifestData): void;
30
+ rewriteKnownRoute(route: string, sourceRoute: RouteData): ComponentInstance;
24
31
  }
@@ -1,11 +1,11 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import { getInfoOutput } from "../cli/info/index.js";
3
3
  import {} from "../core/base-pipeline.js";
4
- import { ASTRO_VERSION, DEFAULT_404_COMPONENT } from "../core/constants.js";
4
+ import { ASTRO_VERSION } from "../core/constants.js";
5
5
  import { enhanceViteSSRError } from "../core/errors/dev/index.js";
6
6
  import { AggregateError, CSSError, MarkdownError } from "../core/errors/index.js";
7
7
  import { Pipeline, loadRenderer } from "../core/render/index.js";
8
- import { default404Page } from "../core/routing/astro-designed-error-pages.js";
8
+ import { createDefaultRoutes } from "../core/routing/default.js";
9
9
  import { findRouteToRewrite } from "../core/routing/rewrite.js";
10
10
  import { isPage, isServerLikeOutput, viteID } from "../core/util.js";
11
11
  import { resolveIdToUrl } from "../core/viteUtils.js";
@@ -15,7 +15,7 @@ import { getComponentMetadata } from "./metadata.js";
15
15
  import { createResolve } from "./resolve.js";
16
16
  import { getScriptsForURL } from "./scripts.js";
17
17
  class DevPipeline extends Pipeline {
18
- constructor(loader, logger, manifest, settings, config = settings.config) {
18
+ constructor(loader, logger, manifest, settings, config = settings.config, defaultRoutes = createDefaultRoutes(manifest)) {
19
19
  const mode = "development";
20
20
  const resolve = createResolve(loader, config.root);
21
21
  const serverLike = isServerLikeOutput(config);
@@ -26,6 +26,9 @@ class DevPipeline extends Pipeline {
26
26
  this.manifest = manifest;
27
27
  this.settings = settings;
28
28
  this.config = config;
29
+ this.defaultRoutes = defaultRoutes;
30
+ manifest.serverIslandMap = settings.serverIslandMap;
31
+ manifest.serverIslandNameMap = settings.serverIslandNameMap;
29
32
  }
30
33
  // renderers are loaded on every request,
31
34
  // so it needs to be mutable here unlike in other environments
@@ -104,8 +107,10 @@ class DevPipeline extends Pipeline {
104
107
  }
105
108
  async preload(routeData, filePath) {
106
109
  const { loader } = this;
107
- if (filePath.href === new URL(DEFAULT_404_COMPONENT, this.config.root).href) {
108
- return { default: default404Page };
110
+ for (const route of this.defaultRoutes) {
111
+ if (route.matchesComponent(filePath)) {
112
+ return route.instance;
113
+ }
109
114
  }
110
115
  const renderers__ = this.settings.renderers.map((r) => loadRenderer(r, loader));
111
116
  const renderers_ = await Promise.all(renderers__);
@@ -152,6 +157,16 @@ class DevPipeline extends Pipeline {
152
157
  setManifestData(manifestData) {
153
158
  this.manifestData = manifestData;
154
159
  }
160
+ rewriteKnownRoute(route, sourceRoute) {
161
+ if (isServerLikeOutput(this.config) && sourceRoute.prerender) {
162
+ for (let def of this.defaultRoutes) {
163
+ if (route === def.route) {
164
+ return def.instance;
165
+ }
166
+ }
167
+ }
168
+ throw new Error("Unknown route");
169
+ }
155
170
  }
156
171
  export {
157
172
  DevPipeline
@@ -4,7 +4,7 @@ import { getViteErrorPayload } from "../core/errors/dev/index.js";
4
4
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
5
5
  import { patchOverlay } from "../core/errors/overlay.js";
6
6
  import { createViteLoader } from "../core/module-loader/index.js";
7
- import { ensure404Route } from "../core/routing/astro-designed-error-pages.js";
7
+ import { injectDefaultRoutes } from "../core/routing/default.js";
8
8
  import { createRouteManifest } from "../core/routing/index.js";
9
9
  import { toRoutingStrategy } from "../i18n/utils.js";
10
10
  import { baseMiddleware } from "./base.js";
@@ -23,7 +23,8 @@ function createVitePluginAstroServer({
23
23
  configureServer(viteServer) {
24
24
  const loader = createViteLoader(viteServer);
25
25
  const manifest = createDevelopmentManifest(settings);
26
- let manifestData = ensure404Route(
26
+ let manifestData = injectDefaultRoutes(
27
+ manifest,
27
28
  createRouteManifest({ settings, fsMod }, logger)
28
29
  );
29
30
  const pipeline = DevPipeline.create(manifestData, { loader, logger, manifest, settings });
@@ -32,7 +33,7 @@ function createVitePluginAstroServer({
32
33
  function rebuildManifest(needsManifestRebuild) {
33
34
  pipeline.clearRouteCache();
34
35
  if (needsManifestRebuild) {
35
- manifestData = ensure404Route(createRouteManifest({ settings }, logger));
36
+ manifestData = injectDefaultRoutes(manifest, createRouteManifest({ settings }, logger));
36
37
  pipeline.setManifestData(manifestData);
37
38
  }
38
39
  }
@@ -98,6 +99,7 @@ function createDevelopmentManifest(settings) {
98
99
  };
99
100
  }
100
101
  return {
102
+ hrefRoot: settings.config.root.toString(),
101
103
  trailingSlash: settings.config.trailingSlash,
102
104
  buildFormat: settings.config.build.format,
103
105
  compressHTML: settings.config.compressHTML,
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  DEFAULT_404_COMPONENT,
3
3
  REROUTE_DIRECTIVE_HEADER,
4
+ REWRITE_DIRECTIVE_HEADER_KEY,
4
5
  clientLocalsSymbol
5
6
  } from "../core/constants.js";
6
7
  import { AstroErrorData, isAstroError } from "../core/errors/index.js";
@@ -9,7 +10,6 @@ import { loadMiddleware } from "../core/middleware/loadMiddleware.js";
9
10
  import { RenderContext } from "../core/render-context.js";
10
11
  import { getProps } from "../core/render/index.js";
11
12
  import { createRequest } from "../core/request.js";
12
- import { default404Page } from "../core/routing/astro-designed-error-pages.js";
13
13
  import { matchAllRoutes } from "../core/routing/index.js";
14
14
  import { getSortedPreloadedMatches } from "../prerender/routing.js";
15
15
  import { writeSSRResult, writeWebResponse } from "./response.js";
@@ -68,18 +68,6 @@ ${AstroErrorData.NoMatchingStaticPathFound.hint(possibleRoutes)}`
68
68
  );
69
69
  }
70
70
  const custom404 = getCustom404Route(manifestData);
71
- if (custom404 && custom404.component === DEFAULT_404_COMPONENT) {
72
- const component = {
73
- default: default404Page
74
- };
75
- return {
76
- route: custom404,
77
- filePath: new URL(`file://${custom404.component}`),
78
- resolvedPathname: pathname,
79
- preloadedComponent: component,
80
- mod: component
81
- };
82
- }
83
71
  if (custom404) {
84
72
  const filePath = new URL(`./${custom404.component}`, config.root);
85
73
  const preloadedComponent = await pipeline.preload(custom404, filePath);
@@ -152,8 +140,12 @@ async function handleRoute({
152
140
  routeData: route
153
141
  });
154
142
  let response;
143
+ let isReroute = false;
144
+ let isRewrite = false;
155
145
  try {
156
146
  response = await renderContext.render(mod);
147
+ isReroute = response.headers.has(REROUTE_DIRECTIVE_HEADER);
148
+ isRewrite = response.headers.has(REWRITE_DIRECTIVE_HEADER_KEY);
157
149
  } catch (err) {
158
150
  const custom500 = getCustom500Route(manifestData);
159
151
  if (!custom500) {
@@ -194,13 +186,20 @@ async function handleRoute({
194
186
  incomingResponse
195
187
  });
196
188
  }
197
- if (response.headers.has(REROUTE_DIRECTIVE_HEADER)) {
189
+ if (isReroute) {
190
+ response.headers.delete(REROUTE_DIRECTIVE_HEADER);
191
+ }
192
+ if (isRewrite) {
198
193
  response.headers.delete(REROUTE_DIRECTIVE_HEADER);
199
194
  }
200
195
  if (route.type === "endpoint") {
201
196
  await writeWebResponse(incomingResponse, response);
202
197
  return;
203
198
  }
199
+ if (isRewrite) {
200
+ await writeSSRResult(request, response, incomingResponse);
201
+ return;
202
+ }
204
203
  if (response.status < 400 && response.status >= 300) {
205
204
  await writeSSRResult(request, response, incomingResponse);
206
205
  return;
@@ -9,6 +9,7 @@ import { safeParseFrontmatter } from "../content/utils.js";
9
9
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
10
10
  import { isMarkdownFile } from "../core/util.js";
11
11
  import { shorthash } from "../runtime/server/shorthash.js";
12
+ import { createDefaultAstroMetadata } from "../vite-plugin-astro/metadata.js";
12
13
  import { getFileInfo } from "../vite-plugin-utils/index.js";
13
14
  import { getMarkdownCodeForImages } from "./images.js";
14
15
  const astroServerRuntimeModulePath = normalizePath(
@@ -122,14 +123,7 @@ function markdown({ settings, logger }) {
122
123
  return {
123
124
  code,
124
125
  meta: {
125
- astro: {
126
- hydratedComponents: [],
127
- clientOnlyComponents: [],
128
- scripts: [],
129
- propagation: "none",
130
- containsHead: false,
131
- pageOptions: {}
132
- },
126
+ astro: createDefaultAstroMetadata(),
133
127
  vite: {
134
128
  lang: "ts"
135
129
  }
@@ -13,3 +13,8 @@ export declare function getFileInfo(id: string, config: AstroConfig): {
13
13
  */
14
14
  export declare function normalizeFilename(filename: string, root: URL): string;
15
15
  export declare function cleanUrl(url: string): string;
16
+ /**
17
+ * Detect `?url`, `?raw`, and `?direct`, in which case we usually want to skip
18
+ * transforming any code with this queries as Vite will handle it directly.
19
+ */
20
+ export declare function hasSpecialQueries(id: string): boolean;
@@ -33,8 +33,13 @@ const postfixRE = /[?#].*$/s;
33
33
  function cleanUrl(url) {
34
34
  return url.replace(postfixRE, "");
35
35
  }
36
+ const specialQueriesRE = /(?:\?|&)(?:url|raw|direct)(?:&|$)/;
37
+ function hasSpecialQueries(id) {
38
+ return specialQueriesRE.test(id);
39
+ }
36
40
  export {
37
41
  cleanUrl,
38
42
  getFileInfo,
43
+ hasSpecialQueries,
39
44
  normalizeFilename
40
45
  };