astro 4.10.2 → 4.11.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 (72) hide show
  1. package/components/Code.astro +9 -0
  2. package/dist/@types/astro.d.ts +43 -39
  3. package/dist/actions/runtime/virtual/server.d.ts +1 -1
  4. package/dist/assets/internal.d.ts +1 -1
  5. package/dist/assets/internal.js +6 -0
  6. package/dist/assets/types.d.ts +8 -2
  7. package/dist/assets/types.js +7 -0
  8. package/dist/container/index.d.ts +32 -1
  9. package/dist/container/index.js +45 -0
  10. package/dist/container/pipeline.d.ts +0 -1
  11. package/dist/container/pipeline.js +13 -32
  12. package/dist/container/vite-plugin-container.d.ts +2 -0
  13. package/dist/container/vite-plugin-container.js +15 -0
  14. package/dist/content/runtime-assets.d.ts +3 -3
  15. package/dist/content/types-generator.js +55 -34
  16. package/dist/content/utils.d.ts +11 -0
  17. package/dist/content/utils.js +49 -0
  18. package/dist/content/vite-plugin-content-imports.d.ts +3 -1
  19. package/dist/content/vite-plugin-content-imports.js +15 -4
  20. package/dist/core/app/index.d.ts +4 -0
  21. package/dist/core/app/index.js +17 -6
  22. package/dist/core/app/pipeline.d.ts +1 -2
  23. package/dist/core/app/pipeline.js +11 -39
  24. package/dist/core/base-pipeline.d.ts +0 -9
  25. package/dist/core/base-pipeline.js +1 -1
  26. package/dist/core/build/internal.d.ts +4 -0
  27. package/dist/core/build/internal.js +2 -1
  28. package/dist/core/build/page-data.js +2 -4
  29. package/dist/core/build/pipeline.d.ts +1 -2
  30. package/dist/core/build/pipeline.js +16 -42
  31. package/dist/core/build/plugins/plugin-chunks.js +6 -0
  32. package/dist/core/build/plugins/plugin-prerender.js +55 -48
  33. package/dist/core/build/plugins/plugin-ssr.js +15 -12
  34. package/dist/core/build/static-build.js +36 -44
  35. package/dist/core/build/types.d.ts +0 -1
  36. package/dist/core/config/schema.d.ts +4 -156
  37. package/dist/core/constants.d.ts +4 -0
  38. package/dist/core/constants.js +3 -1
  39. package/dist/core/cookies/cookies.d.ts +5 -0
  40. package/dist/core/cookies/cookies.js +12 -0
  41. package/dist/core/cookies/response.d.ts +1 -0
  42. package/dist/core/cookies/response.js +1 -0
  43. package/dist/core/create-vite.js +4 -6
  44. package/dist/core/dev/dev.js +1 -1
  45. package/dist/core/errors/errors-data.d.ts +40 -11
  46. package/dist/core/errors/errors-data.js +13 -6
  47. package/dist/core/messages.js +2 -2
  48. package/dist/core/render-context.d.ts +1 -1
  49. package/dist/core/render-context.js +22 -6
  50. package/dist/core/request.js +7 -1
  51. package/dist/core/routing/astro-designed-error-pages.d.ts +1 -0
  52. package/dist/core/routing/astro-designed-error-pages.js +15 -1
  53. package/dist/core/routing/rewrite.d.ts +10 -0
  54. package/dist/core/routing/rewrite.js +41 -0
  55. package/dist/core/util.js +5 -2
  56. package/dist/env/constants.d.ts +0 -1
  57. package/dist/env/constants.js +0 -2
  58. package/dist/env/runtime.d.ts +3 -1
  59. package/dist/env/runtime.js +8 -1
  60. package/dist/env/schema.d.ts +2 -78
  61. package/dist/env/schema.js +1 -17
  62. package/dist/env/vite-plugin-env.js +15 -15
  63. package/dist/jsx/server.d.ts +3 -5
  64. package/dist/jsx/server.js +3 -1
  65. package/dist/vite-plugin-astro/index.js +1 -1
  66. package/dist/vite-plugin-astro-server/pipeline.d.ts +1 -2
  67. package/dist/vite-plugin-astro-server/pipeline.js +15 -42
  68. package/dist/vite-plugin-astro-server/request.js +1 -1
  69. package/dist/vite-plugin-astro-server/route.js +53 -94
  70. package/package.json +8 -7
  71. package/templates/env/module.mjs +14 -5
  72. package/templates/env/types.d.ts +1 -12
@@ -108,6 +108,53 @@ function getEntryConfigByExtMap(entryTypes) {
108
108
  }
109
109
  return map;
110
110
  }
111
+ async function getSymlinkedContentCollections({
112
+ contentDir,
113
+ logger,
114
+ fs
115
+ }) {
116
+ const contentPaths = /* @__PURE__ */ new Map();
117
+ const contentDirPath = fileURLToPath(contentDir);
118
+ try {
119
+ if (!fs.existsSync(contentDirPath) || !fs.lstatSync(contentDirPath).isDirectory()) {
120
+ return contentPaths;
121
+ }
122
+ } catch {
123
+ return contentPaths;
124
+ }
125
+ try {
126
+ const contentDirEntries = await fs.promises.readdir(contentDir, { withFileTypes: true });
127
+ for (const entry of contentDirEntries) {
128
+ if (entry.isSymbolicLink()) {
129
+ const entryPath = path.join(contentDirPath, entry.name);
130
+ const realPath = await fs.promises.realpath(entryPath);
131
+ contentPaths.set(normalizePath(realPath), entry.name);
132
+ }
133
+ }
134
+ } catch (e) {
135
+ logger.warn("content", `Error when reading content directory "${contentDir}"`);
136
+ logger.debug("content", e);
137
+ return /* @__PURE__ */ new Map();
138
+ }
139
+ return contentPaths;
140
+ }
141
+ function reverseSymlink({
142
+ entry,
143
+ symlinks,
144
+ contentDir
145
+ }) {
146
+ const entryPath = normalizePath(typeof entry === "string" ? entry : fileURLToPath(entry));
147
+ const contentDirPath = typeof contentDir === "string" ? contentDir : fileURLToPath(contentDir);
148
+ if (!symlinks || symlinks.size === 0) {
149
+ return entryPath;
150
+ }
151
+ for (const [realPath, symlinkName] of symlinks) {
152
+ if (entryPath.startsWith(realPath)) {
153
+ return normalizePath(path.join(contentDirPath, symlinkName, entryPath.replace(realPath, "")));
154
+ }
155
+ }
156
+ return entryPath;
157
+ }
111
158
  function getEntryCollectionName({
112
159
  contentDir,
113
160
  entry
@@ -354,6 +401,7 @@ export {
354
401
  getEntrySlug,
355
402
  getEntryType,
356
403
  getExtGlob,
404
+ getSymlinkedContentCollections,
357
405
  globalContentConfigObserver,
358
406
  hasAnyContentFlag,
359
407
  hasAssetPropagationFlag,
@@ -363,5 +411,6 @@ export {
363
411
  msg,
364
412
  parseEntrySlug,
365
413
  reloadContentConfigObserver,
414
+ reverseSymlink,
366
415
  safeParseFrontmatter
367
416
  };
@@ -2,7 +2,9 @@
2
2
  import type fsMod from 'node:fs';
3
3
  import type { Plugin } from 'vite';
4
4
  import type { AstroSettings } from '../@types/astro.js';
5
- export declare function astroContentImportPlugin({ fs, settings, }: {
5
+ import type { Logger } from '../core/logger/core.js';
6
+ export declare function astroContentImportPlugin({ fs, settings, logger, }: {
6
7
  fs: typeof fsMod;
7
8
  settings: AstroSettings;
9
+ logger: Logger;
8
10
  }): Plugin[];
@@ -16,10 +16,12 @@ import {
16
16
  getEntryConfigByExtMap,
17
17
  getEntryData,
18
18
  getEntryType,
19
+ getSymlinkedContentCollections,
19
20
  globalContentConfigObserver,
20
21
  hasContentFlag,
21
22
  parseEntrySlug,
22
- reloadContentConfigObserver
23
+ reloadContentConfigObserver,
24
+ reverseSymlink
23
25
  } from "./utils.js";
24
26
  function getContentRendererByViteId(viteId, settings) {
25
27
  let ext = viteId.split(".").pop();
@@ -35,7 +37,8 @@ const CHOKIDAR_MODIFIED_EVENTS = ["add", "unlink", "change"];
35
37
  const COLLECTION_TYPES_TO_INVALIDATE_ON = ["data", "content", "config"];
36
38
  function astroContentImportPlugin({
37
39
  fs,
38
- settings
40
+ settings,
41
+ logger
39
42
  }) {
40
43
  const contentPaths = getContentPaths(settings.config, fs);
41
44
  const contentEntryExts = getContentEntryExts(settings);
@@ -44,15 +47,23 @@ function astroContentImportPlugin({
44
47
  const dataEntryConfigByExt = getEntryConfigByExtMap(settings.dataEntryTypes);
45
48
  const { contentDir } = contentPaths;
46
49
  let shouldEmitFile = false;
50
+ let symlinks;
47
51
  const plugins = [
48
52
  {
49
53
  name: "astro:content-imports",
50
54
  config(_config, env) {
51
55
  shouldEmitFile = env.command === "build";
52
56
  },
57
+ async buildStart() {
58
+ symlinks = await getSymlinkedContentCollections({ contentDir, logger, fs });
59
+ },
53
60
  async transform(_, viteId) {
54
61
  if (hasContentFlag(viteId, DATA_FLAG)) {
55
- const fileId = viteId.split("?")[0] ?? viteId;
62
+ const fileId = reverseSymlink({
63
+ entry: viteId.split("?")[0] ?? viteId,
64
+ contentDir,
65
+ symlinks
66
+ });
56
67
  const { id, data, collection, _internal } = await getDataEntryModule({
57
68
  fileId,
58
69
  entryConfigByExt: dataEntryConfigByExt,
@@ -74,7 +85,7 @@ export const _internal = {
74
85
  `;
75
86
  return code;
76
87
  } else if (hasContentFlag(viteId, CONTENT_FLAG)) {
77
- const fileId = viteId.split("?")[0];
88
+ const fileId = reverseSymlink({ entry: viteId.split("?")[0], contentDir, symlinks });
78
89
  const { id, slug, collection, body, data, _internal } = await getContentEntryModule({
79
90
  fileId,
80
91
  entryConfigByExt: contentEntryConfigByExt,
@@ -39,6 +39,10 @@ export interface RenderErrorOptions {
39
39
  * Whether to skip middleware while rendering the error page. Defaults to false.
40
40
  */
41
41
  skipMiddleware?: boolean;
42
+ /**
43
+ * Allows passing an error to 500.astro. It will be available through `Astro.props.error`.
44
+ */
45
+ error?: unknown;
42
46
  }
43
47
  export declare class App {
44
48
  #private;
@@ -195,8 +195,9 @@ class App {
195
195
  }
196
196
  if (locals) {
197
197
  if (typeof locals !== "object") {
198
- this.#logger.error(null, new AstroError(AstroErrorData.LocalsNotAnObject).stack);
199
- return this.#renderError(request, { status: 500 });
198
+ const error = new AstroError(AstroErrorData.LocalsNotAnObject);
199
+ this.#logger.error(null, error.stack);
200
+ return this.#renderError(request, { status: 500, error });
200
201
  }
201
202
  Reflect.set(request, clientLocalsSymbol, locals);
202
203
  }
@@ -229,13 +230,16 @@ class App {
229
230
  response = await renderContext.render(await mod.page());
230
231
  } catch (err) {
231
232
  this.#logger.error(null, err.stack || err.message || String(err));
232
- return this.#renderError(request, { locals, status: 500 });
233
+ return this.#renderError(request, { locals, status: 500, error: err });
233
234
  }
234
235
  if (REROUTABLE_STATUS_CODES.includes(response.status) && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== "no") {
235
236
  return this.#renderError(request, {
236
237
  locals,
237
238
  response,
238
- status: response.status
239
+ status: response.status,
240
+ // We don't have an error to report here. Passing null means we pass nothing intentionally
241
+ // while undefined means there's no error
242
+ error: response.status === 500 ? null : void 0
239
243
  });
240
244
  }
241
245
  if (response.headers.has(REROUTE_DIRECTIVE_HEADER)) {
@@ -276,7 +280,13 @@ class App {
276
280
  * If it is a known error code, try sending the according page (e.g. 404.astro / 500.astro).
277
281
  * This also handles pre-rendered /404 or /500 routes
278
282
  */
279
- async #renderError(request, { locals, status, response: originalResponse, skipMiddleware = false }) {
283
+ async #renderError(request, {
284
+ locals,
285
+ status,
286
+ response: originalResponse,
287
+ skipMiddleware = false,
288
+ error
289
+ }) {
280
290
  const errorRoutePath = `/${status}${this.#manifest.trailingSlash === "always" ? "/" : ""}`;
281
291
  const errorRouteData = matchRoute(errorRoutePath, this.#manifestData);
282
292
  const url = new URL(request.url);
@@ -300,7 +310,8 @@ class App {
300
310
  pathname: this.#getPathnameFromRequest(request),
301
311
  request,
302
312
  routeData: errorRouteData,
303
- status
313
+ status,
314
+ props: { error }
304
315
  });
305
316
  const response2 = await renderContext.render(await mod.page());
306
317
  return this.#mergeResponses(response2, originalResponse);
@@ -7,7 +7,6 @@ export declare class AppPipeline extends Pipeline {
7
7
  headElements(routeData: RouteData): Pick<SSRResult, 'scripts' | 'styles' | 'links'>;
8
8
  componentMetadata(): void;
9
9
  getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
10
- tryRewrite(payload: RewritePayload, request: Request, sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
10
+ tryRewrite(payload: RewritePayload, request: Request, _sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
11
11
  getModuleForRoute(route: RouteData): Promise<SinglePageBuiltModule>;
12
- rewriteKnownRoute(pathname: string, _sourceRoute: RouteData): ComponentInstance;
13
12
  }
@@ -5,6 +5,7 @@ import { AstroError } from "../errors/index.js";
5
5
  import { RedirectSinglePageBuiltModule } from "../redirects/component.js";
6
6
  import { createModuleScriptElement, createStylesheetElementSet } from "../render/ssr-element.js";
7
7
  import { DEFAULT_404_ROUTE } from "../routing/astro-designed-error-pages.js";
8
+ import { findRouteToRewrite } from "../routing/rewrite.js";
8
9
  class AppPipeline extends Pipeline {
9
10
  #manifestData;
10
11
  static create(manifestData, {
@@ -62,38 +63,17 @@ class AppPipeline extends Pipeline {
62
63
  const module = await this.getModuleForRoute(routeData);
63
64
  return module.page();
64
65
  }
65
- async tryRewrite(payload, request, sourceRoute) {
66
- let foundRoute;
67
- let finalUrl = void 0;
68
- for (const route of this.#manifestData.routes) {
69
- if (payload instanceof URL) {
70
- finalUrl = payload;
71
- } else if (payload instanceof Request) {
72
- finalUrl = new URL(payload.url);
73
- } else {
74
- finalUrl = new URL(payload, new URL(request.url).origin);
75
- }
76
- if (route.pattern.test(decodeURI(finalUrl.pathname))) {
77
- foundRoute = route;
78
- break;
79
- } else if (finalUrl.pathname === "/404") {
80
- foundRoute = DEFAULT_404_ROUTE;
81
- break;
82
- }
83
- }
84
- if (foundRoute && finalUrl) {
85
- if (foundRoute.pathname === "/404") {
86
- const componentInstance = this.rewriteKnownRoute(foundRoute.pathname, sourceRoute);
87
- return [foundRoute, componentInstance, finalUrl];
88
- } else {
89
- const componentInstance = await this.getComponentByRoute(foundRoute);
90
- return [foundRoute, componentInstance, finalUrl];
91
- }
92
- }
93
- throw new AstroError({
94
- ...RewriteEncounteredAnError,
95
- message: RewriteEncounteredAnError.message(payload.toString())
66
+ async tryRewrite(payload, request, _sourceRoute) {
67
+ const [foundRoute, finalUrl] = findRouteToRewrite({
68
+ payload,
69
+ request,
70
+ routes: this.manifest?.routes.map((r) => r.routeData),
71
+ trailingSlash: this.manifest.trailingSlash,
72
+ buildFormat: this.manifest.buildFormat,
73
+ base: this.manifest.base
96
74
  });
75
+ const componentInstance = await this.getComponentByRoute(foundRoute);
76
+ return [foundRoute, componentInstance, finalUrl];
97
77
  }
98
78
  async getModuleForRoute(route) {
99
79
  if (route.component === DEFAULT_404_COMPONENT) {
@@ -121,14 +101,6 @@ class AppPipeline extends Pipeline {
121
101
  );
122
102
  }
123
103
  }
124
- // We don't need to check the source route, we already are in SSR
125
- rewriteKnownRoute(pathname, _sourceRoute) {
126
- if (pathname === "/404") {
127
- return { default: () => new Response(null, { status: 404 }) };
128
- } else {
129
- return { default: () => new Response(null, { status: 500 }) };
130
- }
131
- }
132
104
  }
133
105
  export {
134
106
  AppPipeline
@@ -73,15 +73,6 @@ export declare abstract class Pipeline {
73
73
  * @param routeData
74
74
  */
75
75
  abstract getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
76
- /**
77
- * Attempts to execute a rewrite of a known Astro route:
78
- * - /404 -> src/pages/404.astro -> template
79
- * - /500 -> src/pages/500.astro
80
- *
81
- * @param pathname The pathname where the user wants to rewrite e.g. "/404"
82
- * @param sourceRoute The original route where the first request started. This is needed in case a pipeline wants to check if the current route is pre-rendered or not
83
- */
84
- abstract rewriteKnownRoute(pathname: string, sourceRoute: RouteData): ComponentInstance;
85
76
  }
86
77
  export interface HeadElements extends Pick<SSRResult, 'scripts' | 'styles' | 'links'> {
87
78
  }
@@ -30,7 +30,7 @@ class Pipeline {
30
30
  if (callSetGetEnv && manifest.experimentalEnvGetSecretEnabled) {
31
31
  setGetEnv(() => {
32
32
  throw new AstroError(AstroErrorData.EnvUnsupportedGetSecret);
33
- });
33
+ }, true);
34
34
  }
35
35
  }
36
36
  internalMiddleware;
@@ -89,6 +89,10 @@ export interface BuildInternals {
89
89
  ssrSplitEntryChunks: Map<string, Rollup.OutputChunk>;
90
90
  componentMetadata: SSRResult['componentMetadata'];
91
91
  middlewareEntryPoint?: URL;
92
+ /**
93
+ * Chunks in the bundle that are only used in prerendering that we can delete later
94
+ */
95
+ prerenderOnlyChunks: Rollup.OutputChunk[];
92
96
  }
93
97
  /**
94
98
  * Creates internal maps used to coordinate the CSS and HTML plugins.
@@ -26,7 +26,8 @@ function createBuildInternals() {
26
26
  componentMetadata: /* @__PURE__ */ new Map(),
27
27
  ssrSplitEntryChunks: /* @__PURE__ */ new Map(),
28
28
  entryPoints: /* @__PURE__ */ new Map(),
29
- cacheManifestUsed: false
29
+ cacheManifestUsed: false,
30
+ prerenderOnlyChunks: []
30
31
  };
31
32
  }
32
33
  function trackPageData(internals, component, pageData, componentModuleId, componentURL) {
@@ -29,8 +29,7 @@ async function collectPagesData(opts) {
29
29
  route,
30
30
  moduleSpecifier: "",
31
31
  styles: [],
32
- hoistedScript: void 0,
33
- hasSharedModules: false
32
+ hoistedScript: void 0
34
33
  };
35
34
  clearInterval(routeCollectionLogTimeout);
36
35
  if (settings.config.output === "static") {
@@ -50,8 +49,7 @@ async function collectPagesData(opts) {
50
49
  route,
51
50
  moduleSpecifier: "",
52
51
  styles: [],
53
- hoistedScript: void 0,
54
- hasSharedModules: false
52
+ hoistedScript: void 0
55
53
  };
56
54
  }
57
55
  clearInterval(dataCollectionLogTimeout);
@@ -38,7 +38,6 @@ export declare class BuildPipeline extends Pipeline {
38
38
  */
39
39
  retrieveRoutesToGenerate(): Map<PageBuildData, string>;
40
40
  getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
41
- tryRewrite(payload: RewritePayload, request: Request, sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
41
+ tryRewrite(payload: RewritePayload, request: Request, _sourceRoute: RouteData): Promise<[RouteData, ComponentInstance, URL]>;
42
42
  retrieveSsrEntry(route: RouteData, filePath: string): Promise<SinglePageBuiltModule>;
43
- rewriteKnownRoute(_pathname: string, sourceRoute: RouteData): ComponentInstance;
44
43
  }
@@ -1,7 +1,6 @@
1
1
  import { getOutputDirectory } from "../../prerender/utils.js";
2
2
  import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from "../../vite-plugin-scripts/index.js";
3
- import { InvalidRewrite404, RewriteEncounteredAnError } from "../errors/errors-data.js";
4
- import { AstroError } from "../errors/index.js";
3
+ import { DEFAULT_404_COMPONENT } from "../constants.js";
5
4
  import { routeIsFallback, routeIsRedirect } from "../redirects/helpers.js";
6
5
  import { RedirectSinglePageBuiltModule } from "../redirects/index.js";
7
6
  import { Pipeline } from "../render/index.js";
@@ -10,7 +9,8 @@ import {
10
9
  createModuleScriptsSet,
11
10
  createStylesheetElementSet
12
11
  } from "../render/ssr-element.js";
13
- import { DEFAULT_404_ROUTE } from "../routing/astro-designed-error-pages.js";
12
+ import { default404Page } from "../routing/astro-designed-error-pages.js";
13
+ import { findRouteToRewrite } from "../routing/rewrite.js";
14
14
  import { isServerLikeOutput } from "../util.js";
15
15
  import { getOutDirWithinCwd } from "./common.js";
16
16
  import { cssOrder, getPageData, mergeInlineCss } from "./internal.js";
@@ -201,45 +201,25 @@ class BuildPipeline extends Pipeline {
201
201
  if (this.#componentsInterner.has(routeData)) {
202
202
  const entry = this.#componentsInterner.get(routeData);
203
203
  return await entry.page();
204
+ } else if (routeData.component === DEFAULT_404_COMPONENT) {
205
+ return { default: default404Page };
204
206
  } else {
205
207
  const filePath = this.#routesByFilePath.get(routeData);
206
208
  const module = await this.retrieveSsrEntry(routeData, filePath);
207
209
  return module.page();
208
210
  }
209
211
  }
210
- async tryRewrite(payload, request, sourceRoute) {
211
- let foundRoute;
212
- let finalUrl = void 0;
213
- for (const route of this.options.manifest.routes) {
214
- if (payload instanceof URL) {
215
- finalUrl = payload;
216
- } else if (payload instanceof Request) {
217
- finalUrl = new URL(payload.url);
218
- } else {
219
- finalUrl = new URL(payload, new URL(request.url).origin);
220
- }
221
- if (route.pattern.test(decodeURI(finalUrl.pathname))) {
222
- foundRoute = route;
223
- break;
224
- } else if (finalUrl.pathname === "/404") {
225
- foundRoute = DEFAULT_404_ROUTE;
226
- break;
227
- }
228
- }
229
- if (foundRoute && finalUrl) {
230
- if (foundRoute.pathname === "/404") {
231
- const componentInstance = await this.rewriteKnownRoute(foundRoute.pathname, sourceRoute);
232
- return [foundRoute, componentInstance, finalUrl];
233
- } else {
234
- const componentInstance = await this.getComponentByRoute(foundRoute);
235
- return [foundRoute, componentInstance, finalUrl];
236
- }
237
- } else {
238
- throw new AstroError({
239
- ...RewriteEncounteredAnError,
240
- message: RewriteEncounteredAnError.message(payload.toString())
241
- });
242
- }
212
+ async tryRewrite(payload, request, _sourceRoute) {
213
+ const [foundRoute, finalUrl] = findRouteToRewrite({
214
+ payload,
215
+ request,
216
+ routes: this.options.manifest.routes,
217
+ trailingSlash: this.config.trailingSlash,
218
+ buildFormat: this.config.build.format,
219
+ base: this.config.base
220
+ });
221
+ const componentInstance = await this.getComponentByRoute(foundRoute);
222
+ return [foundRoute, componentInstance, finalUrl];
243
223
  }
244
224
  async retrieveSsrEntry(route, filePath) {
245
225
  if (this.#componentsInterner.has(route)) {
@@ -285,12 +265,6 @@ class BuildPipeline extends Pipeline {
285
265
  }
286
266
  return RedirectSinglePageBuiltModule;
287
267
  }
288
- rewriteKnownRoute(_pathname, sourceRoute) {
289
- if (!isServerLikeOutput(this.config) || sourceRoute.prerender) {
290
- throw new AstroError(InvalidRewrite404);
291
- }
292
- throw new Error(`Unreachable, in SSG this route shouldn't be generated`);
293
- }
294
268
  }
295
269
  function createEntryURL(filePath, outFolder) {
296
270
  return new URL("./" + filePath + `?time=${Date.now()}`, outFolder);
@@ -8,6 +8,12 @@ function vitePluginChunks() {
8
8
  if (id.includes("astro/dist/runtime/server/")) {
9
9
  return "astro/server";
10
10
  }
11
+ if (id.includes("astro/dist/runtime")) {
12
+ return "astro";
13
+ }
14
+ if (id.includes("astro/dist/env/setup")) {
15
+ return "astro/env-setup";
16
+ }
11
17
  }
12
18
  });
13
19
  }
@@ -1,57 +1,64 @@
1
- import path from "node:path";
2
1
  import { getPrerenderMetadata } from "../../../prerender/metadata.js";
3
- import { extendManualChunks } from "./util.js";
4
- function vitePluginPrerender(opts, internals) {
2
+ import { ASTRO_PAGE_RESOLVED_MODULE_ID } from "./plugin-pages.js";
3
+ import { getPagesFromVirtualModulePageName } from "./util.js";
4
+ function vitePluginPrerender(internals) {
5
5
  return {
6
6
  name: "astro:rollup-plugin-prerender",
7
- outputOptions(outputOptions) {
8
- extendManualChunks(outputOptions, {
9
- after(id, meta) {
10
- if (id.includes("astro/dist/runtime")) {
11
- return "astro";
12
- }
13
- const pageInfo = internals.pagesByViteID.get(id);
14
- let hasSharedModules = false;
15
- if (pageInfo) {
16
- if (getPrerenderMetadata(meta.getModuleInfo(id))) {
17
- const infoMeta = meta.getModuleInfo(id);
18
- for (const moduleId of infoMeta.importedIds) {
19
- const moduleMeta = meta.getModuleInfo(moduleId);
20
- if (
21
- // a shared modules should be inside the `src/` folder, at least
22
- moduleMeta.id.startsWith(opts.settings.config.srcDir.pathname) && // and has at least two importers: the current page and something else
23
- moduleMeta.importers.length > 1
24
- ) {
25
- for (const importer of moduleMeta.importedIds) {
26
- if (importer !== id) {
27
- const importerModuleMeta = meta.getModuleInfo(importer);
28
- if (importerModuleMeta) {
29
- if (importerModuleMeta.id.includes("/pages")) {
30
- if (getPrerenderMetadata(importerModuleMeta) === false) {
31
- hasSharedModules = true;
32
- break;
33
- }
34
- } else if (importerModuleMeta.id.includes("/middleware")) {
35
- hasSharedModules = true;
36
- break;
37
- }
38
- }
39
- }
40
- }
41
- }
42
- }
43
- pageInfo.hasSharedModules = hasSharedModules;
44
- pageInfo.route.prerender = true;
45
- return "prerender";
46
- }
47
- pageInfo.route.prerender = false;
48
- return `pages/${path.basename(pageInfo.component)}`;
49
- }
50
- }
7
+ generateBundle(_, bundle) {
8
+ const moduleIds = this.getModuleIds();
9
+ for (const id of moduleIds) {
10
+ const pageInfo = internals.pagesByViteID.get(id);
11
+ if (!pageInfo) continue;
12
+ const moduleInfo = this.getModuleInfo(id);
13
+ if (!moduleInfo) continue;
14
+ const prerender = !!getPrerenderMetadata(moduleInfo);
15
+ pageInfo.route.prerender = prerender;
16
+ }
17
+ const nonPrerenderOnlyChunks = getNonPrerenderOnlyChunks(bundle, internals);
18
+ internals.prerenderOnlyChunks = Object.values(bundle).filter((chunk) => {
19
+ return chunk.type === "chunk" && !nonPrerenderOnlyChunks.has(chunk);
51
20
  });
52
21
  }
53
22
  };
54
23
  }
24
+ function getNonPrerenderOnlyChunks(bundle, internals) {
25
+ const chunks = Object.values(bundle);
26
+ const prerenderOnlyEntryChunks = /* @__PURE__ */ new Set();
27
+ const nonPrerenderOnlyEntryChunks = /* @__PURE__ */ new Set();
28
+ for (const chunk of chunks) {
29
+ if (chunk.type === "chunk" && (chunk.isEntry || chunk.isDynamicEntry)) {
30
+ if (chunk.facadeModuleId?.startsWith(ASTRO_PAGE_RESOLVED_MODULE_ID)) {
31
+ const pageDatas = getPagesFromVirtualModulePageName(
32
+ internals,
33
+ ASTRO_PAGE_RESOLVED_MODULE_ID,
34
+ chunk.facadeModuleId
35
+ );
36
+ const prerender = pageDatas.every((pageData) => pageData.route.prerender);
37
+ if (prerender) {
38
+ prerenderOnlyEntryChunks.add(chunk);
39
+ continue;
40
+ }
41
+ }
42
+ nonPrerenderOnlyEntryChunks.add(chunk);
43
+ }
44
+ }
45
+ const nonPrerenderOnlyChunks = new Set(nonPrerenderOnlyEntryChunks);
46
+ for (const chunk of nonPrerenderOnlyChunks) {
47
+ for (const importFileName of chunk.imports) {
48
+ const importChunk = bundle[importFileName];
49
+ if (importChunk?.type === "chunk") {
50
+ nonPrerenderOnlyChunks.add(importChunk);
51
+ }
52
+ }
53
+ for (const dynamicImportFileName of chunk.dynamicImports) {
54
+ const dynamicImportChunk = bundle[dynamicImportFileName];
55
+ if (dynamicImportChunk?.type === "chunk" && !prerenderOnlyEntryChunks.has(dynamicImportChunk)) {
56
+ nonPrerenderOnlyChunks.add(dynamicImportChunk);
57
+ }
58
+ }
59
+ }
60
+ return nonPrerenderOnlyChunks;
61
+ }
55
62
  function pluginPrerender(opts, internals) {
56
63
  if (opts.settings.config.output === "static") {
57
64
  return { targets: ["server"] };
@@ -61,7 +68,7 @@ function pluginPrerender(opts, internals) {
61
68
  hooks: {
62
69
  "build:before": () => {
63
70
  return {
64
- vitePlugin: vitePluginPrerender(opts, internals)
71
+ vitePlugin: vitePluginPrerender(internals)
65
72
  };
66
73
  }
67
74
  }
@@ -16,7 +16,15 @@ function vitePluginSSR(internals, adapter, options) {
16
16
  name: "@astrojs/vite-plugin-astro-ssr-server",
17
17
  enforce: "post",
18
18
  options(opts) {
19
- return addRollupInput(opts, [SSR_VIRTUAL_MODULE_ID]);
19
+ const inputs = /* @__PURE__ */ new Set();
20
+ for (const pageData of Object.values(options.allPages)) {
21
+ if (routeIsRedirect(pageData.route)) {
22
+ continue;
23
+ }
24
+ inputs.add(getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component));
25
+ }
26
+ inputs.add(SSR_VIRTUAL_MODULE_ID);
27
+ return addRollupInput(opts, Array.from(inputs));
20
28
  },
21
29
  resolveId(id) {
22
30
  if (id === SSR_VIRTUAL_MODULE_ID) {
@@ -60,7 +68,6 @@ function vitePluginSSR(internals, adapter, options) {
60
68
  contents.push(...ssrCode.contents);
61
69
  return [...imports, ...contents, ...exports].join("\n");
62
70
  }
63
- return void 0;
64
71
  },
65
72
  async generateBundle(_opts, bundle) {
66
73
  for (const [, chunk] of Object.entries(bundle)) {
@@ -110,21 +117,18 @@ function pluginSSR(options, internals) {
110
117
  const SPLIT_MODULE_ID = "@astro-page-split:";
111
118
  const RESOLVED_SPLIT_MODULE_ID = "\0@astro-page-split:";
112
119
  function vitePluginSSRSplit(internals, adapter, options) {
113
- const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
114
120
  return {
115
121
  name: "@astrojs/vite-plugin-astro-ssr-split",
116
122
  enforce: "post",
117
123
  options(opts) {
118
- if (functionPerRouteEnabled) {
119
- const inputs = /* @__PURE__ */ new Set();
120
- for (const pageData of Object.values(options.allPages)) {
121
- if (routeIsRedirect(pageData.route)) {
122
- continue;
123
- }
124
- inputs.add(getVirtualModulePageName(SPLIT_MODULE_ID, pageData.component));
124
+ const inputs = /* @__PURE__ */ new Set();
125
+ for (const pageData of Object.values(options.allPages)) {
126
+ if (routeIsRedirect(pageData.route)) {
127
+ continue;
125
128
  }
126
- return addRollupInput(opts, Array.from(inputs));
129
+ inputs.add(getVirtualModulePageName(SPLIT_MODULE_ID, pageData.component));
127
130
  }
131
+ return addRollupInput(opts, Array.from(inputs));
128
132
  },
129
133
  resolveId(id) {
130
134
  if (id.startsWith(SPLIT_MODULE_ID)) {
@@ -149,7 +153,6 @@ function vitePluginSSRSplit(internals, adapter, options) {
149
153
  exports.push("export { pageModule }");
150
154
  return [...imports, ...contents, ...exports].join("\n");
151
155
  }
152
- return void 0;
153
156
  },
154
157
  async generateBundle(_opts, bundle) {
155
158
  for (const [, chunk] of Object.entries(bundle)) {