astro 2.5.6 → 2.6.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 (79) hide show
  1. package/dist/@types/astro.d.ts +115 -90
  2. package/dist/assets/generate.js +2 -2
  3. package/dist/config/index.js +11 -3
  4. package/dist/config/vite-plugin-content-listen.d.ts +18 -0
  5. package/dist/config/vite-plugin-content-listen.js +26 -0
  6. package/dist/content/consts.d.ts +2 -1
  7. package/dist/content/consts.js +8 -1
  8. package/dist/content/runtime.js +67 -47
  9. package/dist/content/vite-plugin-content-assets.js +26 -10
  10. package/dist/content/vite-plugin-content-virtual-mod.js +18 -9
  11. package/dist/core/app/index.js +27 -18
  12. package/dist/core/app/node.js +4 -3
  13. package/dist/core/app/types.d.ts +1 -2
  14. package/dist/core/build/common.js +2 -0
  15. package/dist/core/build/generate.js +76 -13
  16. package/dist/core/build/internal.d.ts +2 -0
  17. package/dist/core/build/internal.js +18 -1
  18. package/dist/core/build/plugins/plugin-css.js +1 -1
  19. package/dist/core/build/plugins/plugin-middleware.js +1 -7
  20. package/dist/core/build/plugins/plugin-pages.d.ts +1 -0
  21. package/dist/core/build/plugins/plugin-pages.js +14 -4
  22. package/dist/core/build/plugins/plugin-ssr.js +10 -14
  23. package/dist/core/build/static-build.js +9 -10
  24. package/dist/core/config/config.js +1 -10
  25. package/dist/core/config/schema.d.ts +48 -64
  26. package/dist/core/config/schema.js +13 -11
  27. package/dist/core/config/settings.js +2 -2
  28. package/dist/core/constants.js +1 -1
  29. package/dist/core/dev/dev.js +1 -1
  30. package/dist/core/endpoint/index.js +2 -2
  31. package/dist/core/errors/errors-data.d.ts +12 -20
  32. package/dist/core/errors/errors-data.js +13 -1
  33. package/dist/core/messages.js +2 -2
  34. package/dist/core/path.d.ts +1 -15
  35. package/dist/core/path.js +1 -80
  36. package/dist/core/redirects/component.d.ts +4 -0
  37. package/dist/core/redirects/component.js +19 -0
  38. package/dist/core/redirects/helpers.d.ts +4 -0
  39. package/dist/core/redirects/helpers.js +29 -0
  40. package/dist/core/redirects/index.d.ts +3 -0
  41. package/dist/core/redirects/index.js +11 -0
  42. package/dist/core/redirects/validate.d.ts +1 -0
  43. package/dist/core/redirects/validate.js +13 -0
  44. package/dist/core/render/context.d.ts +2 -1
  45. package/dist/core/render/core.d.ts +2 -1
  46. package/dist/core/render/core.js +18 -1
  47. package/dist/core/render/dev/environment.js +2 -2
  48. package/dist/core/render/dev/vite.js +12 -13
  49. package/dist/core/render/result.d.ts +2 -0
  50. package/dist/core/render/result.js +3 -3
  51. package/dist/core/routing/manifest/create.js +50 -4
  52. package/dist/core/util.js +10 -3
  53. package/dist/integrations/index.js +3 -8
  54. package/dist/prerender/utils.d.ts +2 -2
  55. package/dist/prerender/utils.js +6 -6
  56. package/dist/runtime/server/astro-island.js +7 -4
  57. package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
  58. package/dist/runtime/server/astro-island.prebuilt.js +1 -1
  59. package/dist/runtime/server/render/any.js +4 -2
  60. package/dist/runtime/server/render/astro/render-template.d.ts +1 -1
  61. package/dist/runtime/server/render/astro/render-template.js +5 -9
  62. package/dist/runtime/server/render/common.js +6 -0
  63. package/dist/runtime/server/render/component.js +2 -2
  64. package/dist/runtime/server/render/page.d.ts +1 -1
  65. package/dist/runtime/server/render/page.js +10 -6
  66. package/dist/runtime/server/render/util.d.ts +6 -0
  67. package/dist/runtime/server/render/util.js +8 -0
  68. package/dist/vite-plugin-astro-server/request.js +2 -2
  69. package/dist/vite-plugin-astro-server/route.js +16 -9
  70. package/dist/vite-plugin-head/index.js +1 -1
  71. package/dist/vite-plugin-html/transform/index.js +3 -7
  72. package/dist/vite-plugin-markdown/content-entry-type.js +6 -1
  73. package/dist/vite-plugin-scanner/index.js +4 -4
  74. package/dist/vite-plugin-utils/index.js +1 -1
  75. package/env.d.ts +2 -2
  76. package/package.json +2 -1
  77. package/src/content/template/virtual-mod.mjs +1 -1
  78. package/tsconfigs/base.json +3 -1
  79. package/tsconfigs/strictest.json +3 -1
@@ -73,7 +73,7 @@ export interface CLIFlags {
73
73
  drafts?: boolean;
74
74
  open?: boolean;
75
75
  experimentalAssets?: boolean;
76
- experimentalMiddleware?: boolean;
76
+ experimentalRedirects?: boolean;
77
77
  }
78
78
  export interface BuildConfig {
79
79
  /**
@@ -396,6 +396,50 @@ export interface AstroUserConfig {
396
396
  * ```
397
397
  */
398
398
  cacheDir?: string;
399
+ /**
400
+ * @docs
401
+ * @name redirects (Experimental)
402
+ * @type {RedirectConfig}
403
+ * @default `{}`
404
+ * @version 2.6.0
405
+ * @description Specify a mapping of redirects where the key is the route to match
406
+ * and the value is the path to redirect to.
407
+ *
408
+ * You can redirect both static and dynamic routes, but only to the same kind of route.
409
+ * For example you cannot have a `'/article': '/blog/[...slug]'` redirect.
410
+ *
411
+ *
412
+ * ```js
413
+ * {
414
+ * redirects: {
415
+ * '/old': '/new',
416
+ * '/blog/[...slug]': '/articles/[...slug]',
417
+ * }
418
+ * }
419
+ * ```
420
+ *
421
+ *
422
+ * For statically-generated sites with no adapter installed, this will produce a client redirect using a [`<meta http-equiv="refresh">` tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#http-equiv) and does not support status codes.
423
+ *
424
+ * When using SSR or with a static adapter in `output: static`
425
+ * mode, status codes are supported.
426
+ * Astro will serve redirected GET requests with a status of `301`
427
+ * and use a status of `308` for any other request method.
428
+ *
429
+ * You can customize the [redirection status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages) using an object in the redirect config:
430
+ *
431
+ * ```js
432
+ * {
433
+ * redirects: {
434
+ * '/other': {
435
+ * status: 302,
436
+ * destination: '/place',
437
+ * },
438
+ * }
439
+ * }
440
+ * ```
441
+ */
442
+ redirects?: RedirectConfig;
399
443
  /**
400
444
  * @docs
401
445
  * @name site
@@ -670,6 +714,50 @@ export interface AstroUserConfig {
670
714
  * ```
671
715
  */
672
716
  serverEntry?: string;
717
+ /**
718
+ * @docs
719
+ * @name build.redirects
720
+ * @type {boolean}
721
+ * @default `true`
722
+ * @version 2.6.0
723
+ * @description
724
+ * Specifies whether redirects will be output to HTML during the build.
725
+ * This option only applies to `output: 'static'` mode; in SSR redirects
726
+ * are treated the same as all responses.
727
+ *
728
+ * This option is mostly meant to be used by adapters that have special
729
+ * configuration files for redirects and do not need/want HTML based redirects.
730
+ *
731
+ * ```js
732
+ * {
733
+ * build: {
734
+ * redirects: false
735
+ * }
736
+ * }
737
+ * ```
738
+ */
739
+ redirects?: boolean;
740
+ /**
741
+ * @docs
742
+ * @name build.inlineStylesheets
743
+ * @type {('always' | 'auto' | 'never')}
744
+ * @default `never`
745
+ * @version 2.6.0
746
+ * @description
747
+ * Control whether styles are sent to the browser in a separate css file or inlined into `<style>` tags. Choose from the following options:
748
+ * - `'always'` - all styles are inlined into `<style>` tags
749
+ * - `'auto'` - only stylesheets smaller than `ViteConfig.build.assetsInlineLimit` (default: 4kb) are inlined. Otherwise, styles are sent in external stylesheets.
750
+ * - `'never'` - all styles are sent in external stylesheets
751
+ *
752
+ * ```js
753
+ * {
754
+ * build: {
755
+ * inlineStylesheets: `auto`,
756
+ * },
757
+ * }
758
+ * ```
759
+ */
760
+ inlineStylesheets?: 'always' | 'auto' | 'never';
673
761
  };
674
762
  /**
675
763
  * @docs
@@ -1001,103 +1089,24 @@ export interface AstroUserConfig {
1001
1089
  assets?: boolean;
1002
1090
  /**
1003
1091
  * @docs
1004
- * @name experimental.inlineStylesheets
1005
- * @type {('always' | 'auto' | 'never')}
1006
- * @default `never`
1007
- * @version 2.4.0
1008
- * @description
1009
- * Control whether styles are sent to the browser in a separate css file or inlined into `<style>` tags. Choose from the following options:
1010
- * - `'always'` - all styles are inlined into `<style>` tags
1011
- * - `'auto'` - only stylesheets smaller than `ViteConfig.build.assetsInlineLimit` (default: 4kb) are inlined. Otherwise, styles are sent in external stylesheets.
1012
- * - `'never'` - all styles are sent in external stylesheets
1013
- *
1014
- * ```js
1015
- * {
1016
- * experimental: {
1017
- * inlineStylesheets: `auto`,
1018
- * },
1019
- * }
1020
- * ```
1021
- */
1022
- inlineStylesheets?: 'always' | 'auto' | 'never';
1023
- /**
1024
- * @docs
1025
- * @name experimental.customClientDirectives
1026
- * @type {boolean}
1027
- * @default `false`
1028
- * @version 2.5.0
1029
- * @description
1030
- * Allow integrations to use the [experimental `addClientDirective` API](/en/reference/integrations-reference/#addclientdirective-option) in the `astro:config:setup` hook
1031
- * to add custom client directives in Astro files.
1032
- *
1033
- * To enable this feature, set `experimental.customClientDirectives` to `true` in your Astro config:
1034
- *
1035
- * ```js
1036
- * {
1037
- * experimental: {
1038
- * customClientDirectives: true,
1039
- * },
1040
- * }
1041
- * ```
1042
- */
1043
- customClientDirectives?: boolean;
1044
- /**
1045
- * @docs
1046
- * @name experimental.middleware
1047
- * @type {boolean}
1048
- * @default `false`
1049
- * @version 2.4.0
1050
- * @description
1051
- * Enable experimental support for Astro middleware.
1052
- *
1053
- * To enable this feature, set `experimental.middleware` to `true` in your Astro config:
1054
- *
1055
- * ```js
1056
- * {
1057
- * experimental: {
1058
- * middleware: true,
1059
- * },
1060
- * }
1061
- * ```
1062
- */
1063
- middleware?: boolean;
1064
- /**
1065
- * @docs
1066
- * @name experimental.hybridOutput
1092
+ * @name experimental.redirects
1067
1093
  * @type {boolean}
1068
1094
  * @default `false`
1069
- * @version 2.5.0
1095
+ * @version 2.6.0
1070
1096
  * @description
1071
- * Enable experimental support for hybrid SSR with pre-rendering enabled by default.
1072
- *
1073
- * To enable this feature, first set `experimental.hybridOutput` to `true` in your Astro config, and set `output` to `hybrid`.
1097
+ * Enable experimental support for redirect configuration. With this enabled
1098
+ * you can set redirects via the top-level `redirects` property. To enable
1099
+ * this feature, set `experimental.redirects` to `true`.
1074
1100
  *
1075
1101
  * ```js
1076
1102
  * {
1077
- * output: 'hybrid',
1078
1103
  * experimental: {
1079
- * hybridOutput: true,
1104
+ * redirects: true,
1080
1105
  * },
1081
1106
  * }
1082
1107
  * ```
1083
- * Then add `export const prerender = false` to any page or endpoint you want to opt-out of pre-rendering.
1084
- * ```astro
1085
- * ---
1086
- * // pages/contact.astro
1087
- * export const prerender = false
1088
- *
1089
- * if (Astro.request.method === 'POST') {
1090
- * // handle form submission
1091
- * }
1092
- * ---
1093
- * <form method="POST">
1094
- * <input type="text" name="name" />
1095
- * <input type="email" name="email" />
1096
- * <button type="submit">Submit</button>
1097
- * </form>
1098
- * ```
1099
1108
  */
1100
- hybridOutput?: boolean;
1109
+ redirects?: boolean;
1101
1110
  };
1102
1111
  /** @deprecated - Use "integrations" instead. Run Astro to learn more about migrating. */
1103
1112
  renderers?: never;
@@ -1171,6 +1180,12 @@ export interface ContentEntryType {
1171
1180
  viteId: string;
1172
1181
  }): rollup.LoadResult | Promise<rollup.LoadResult>;
1173
1182
  contentModuleTypes?: string;
1183
+ /**
1184
+ * Handle asset propagation for rendered content to avoid bleed.
1185
+ * Ex. MDX content can import styles and scripts, so `handlePropagation` should be true.
1186
+ * @default true
1187
+ */
1188
+ handlePropagation?: boolean;
1174
1189
  }
1175
1190
  type GetContentEntryInfoReturnType = {
1176
1191
  data: Record<string, unknown>;
@@ -1414,6 +1429,7 @@ export interface AstroAdapter {
1414
1429
  args?: any;
1415
1430
  }
1416
1431
  type Body = string;
1432
+ export type ValidRedirectStatus = 300 | 301 | 302 | 303 | 304 | 307 | 308;
1417
1433
  interface AstroSharedContext<Props extends Record<string, any> = Record<string, any>> {
1418
1434
  /**
1419
1435
  * The address (usually IP address) of the user. Used with SSR only.
@@ -1442,7 +1458,7 @@ interface AstroSharedContext<Props extends Record<string, any> = Record<string,
1442
1458
  /**
1443
1459
  * Redirect to another page (**SSR Only**).
1444
1460
  */
1445
- redirect(path: string, status?: 301 | 302 | 303 | 307 | 308): Response;
1461
+ redirect(path: string, status?: ValidRedirectStatus): Response;
1446
1462
  /**
1447
1463
  * Object accessed via Astro middleware
1448
1464
  */
@@ -1625,7 +1641,7 @@ export interface AstroIntegration {
1625
1641
  };
1626
1642
  }
1627
1643
  export type MiddlewareNext<R> = () => Promise<R>;
1628
- export type MiddlewareHandler<R> = (context: APIContext, next: MiddlewareNext<R>) => Promise<R> | Promise<void> | void;
1644
+ export type MiddlewareHandler<R> = (context: APIContext, next: MiddlewareNext<R>) => Promise<R> | R | Promise<void> | void;
1629
1645
  export type MiddlewareResponseHandler = MiddlewareHandler<Response>;
1630
1646
  export type MiddlewareEndpointHandler = MiddlewareHandler<Response | EndpointOutput>;
1631
1647
  export type MiddlewareNextResponse = MiddlewareNext<Response>;
@@ -1636,12 +1652,16 @@ export interface AstroPluginOptions {
1636
1652
  settings: AstroSettings;
1637
1653
  logging: LogOptions;
1638
1654
  }
1639
- export type RouteType = 'page' | 'endpoint';
1655
+ export type RouteType = 'page' | 'endpoint' | 'redirect';
1640
1656
  export interface RoutePart {
1641
1657
  content: string;
1642
1658
  dynamic: boolean;
1643
1659
  spread: boolean;
1644
1660
  }
1661
+ type RedirectConfig = string | {
1662
+ status: ValidRedirectStatus;
1663
+ destination: string;
1664
+ };
1645
1665
  export interface RouteData {
1646
1666
  route: string;
1647
1667
  component: string;
@@ -1653,7 +1673,12 @@ export interface RouteData {
1653
1673
  segments: RoutePart[][];
1654
1674
  type: RouteType;
1655
1675
  prerender: boolean;
1676
+ redirect?: RedirectConfig;
1677
+ redirectRoute?: RouteData;
1656
1678
  }
1679
+ export type RedirectRouteData = RouteData & {
1680
+ redirect: string;
1681
+ };
1657
1682
  export type SerializedRouteData = Omit<RouteData, 'generate' | 'pattern'> & {
1658
1683
  generate: undefined;
1659
1684
  pattern: string;
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import { basename, join } from "node:path/posix";
3
3
  import { warn } from "../core/logger/core.js";
4
4
  import { prependForwardSlash } from "../core/path.js";
5
- import { isHybridOutput } from "../prerender/utils.js";
5
+ import { isServerLikeOutput } from "../prerender/utils.js";
6
6
  import { getConfiguredImageService, isESMImportedImage } from "./internal.js";
7
7
  async function generateImage(buildOpts, options, filepath) {
8
8
  if (!isESMImportedImage(options.src)) {
@@ -21,7 +21,7 @@ async function generateImage(buildOpts, options, filepath) {
21
21
  useCache = false;
22
22
  }
23
23
  let serverRoot, clientRoot;
24
- if (buildOpts.settings.config.output === "server" || isHybridOutput(buildOpts.settings.config)) {
24
+ if (isServerLikeOutput(buildOpts.settings.config)) {
25
25
  serverRoot = buildOpts.settings.config.build.server;
26
26
  clientRoot = buildOpts.settings.config.build.client;
27
27
  } else {
@@ -5,17 +5,21 @@ function getViteConfig(inlineConfig) {
5
5
  return async ({ mode, command }) => {
6
6
  const cmd = command === "serve" ? "dev" : command;
7
7
  const [
8
+ fs,
8
9
  { mergeConfig },
9
10
  { nodeLogDestination },
10
11
  { openConfig, createSettings },
11
12
  { createVite },
12
- { runHookConfigSetup, runHookConfigDone }
13
+ { runHookConfigSetup, runHookConfigDone },
14
+ { astroContentListenPlugin }
13
15
  ] = await Promise.all([
16
+ import("fs"),
14
17
  import("vite"),
15
18
  import("../core/logger/node.js"),
16
19
  import("../core/config/index.js"),
17
20
  import("../core/create-vite.js"),
18
- import("../integrations/index.js")
21
+ import("../integrations/index.js"),
22
+ import("./vite-plugin-content-listen.js")
19
23
  ]);
20
24
  const logging = {
21
25
  dest: nodeLogDestination,
@@ -29,7 +33,11 @@ function getViteConfig(inlineConfig) {
29
33
  await runHookConfigSetup({ settings, command: cmd, logging });
30
34
  const viteConfig = await createVite(
31
35
  {
32
- mode
36
+ mode,
37
+ plugins: [
38
+ // Initialize the content listener
39
+ astroContentListenPlugin({ settings, logging, fs })
40
+ ]
33
41
  },
34
42
  { settings, logging, mode }
35
43
  );
@@ -0,0 +1,18 @@
1
+ /// <reference types="node" />
2
+ import type fsMod from 'node:fs';
3
+ import type { Plugin } from 'vite';
4
+ import type { AstroSettings } from '../@types/astro';
5
+ import type { LogOptions } from '../core/logger/core.js';
6
+ /**
7
+ * Listen for Astro content directory changes and generate types.
8
+ *
9
+ * This is a separate plugin for `getViteConfig` as the `attachContentServerListeners` API
10
+ * needs to be called at different times in `astro dev` and `getViteConfig`. For `astro dev`,
11
+ * it needs to be called after the Astro server is started (packages/astro/src/core/dev/dev.ts).
12
+ * For `getViteConfig`, it needs to be called after the Vite server is started.
13
+ */
14
+ export declare function astroContentListenPlugin({ settings, logging, fs, }: {
15
+ settings: AstroSettings;
16
+ logging: LogOptions;
17
+ fs: typeof fsMod;
18
+ }): Plugin;
@@ -0,0 +1,26 @@
1
+ import { attachContentServerListeners } from "../content/server-listeners.js";
2
+ function astroContentListenPlugin({
3
+ settings,
4
+ logging,
5
+ fs
6
+ }) {
7
+ let server;
8
+ return {
9
+ name: "astro:content-listen",
10
+ apply: "serve",
11
+ configureServer(_server) {
12
+ server = _server;
13
+ },
14
+ async buildStart() {
15
+ await attachContentServerListeners({
16
+ fs,
17
+ settings,
18
+ logging,
19
+ viteServer: server
20
+ });
21
+ }
22
+ };
23
+ }
24
+ export {
25
+ astroContentListenPlugin
26
+ };
@@ -1,9 +1,10 @@
1
1
  export declare const PROPAGATED_ASSET_FLAG = "astroPropagatedAssets";
2
+ export declare const CONTENT_RENDER_FLAG = "astroRenderContent";
2
3
  export declare const CONTENT_FLAG = "astroContentCollectionEntry";
3
4
  export declare const DATA_FLAG = "astroDataCollectionEntry";
4
- export declare const CONTENT_FLAGS: readonly ["astroContentCollectionEntry", "astroDataCollectionEntry", "astroPropagatedAssets"];
5
5
  export declare const VIRTUAL_MODULE_ID = "astro:content";
6
6
  export declare const LINKS_PLACEHOLDER = "@@ASTRO-LINKS@@";
7
7
  export declare const STYLES_PLACEHOLDER = "@@ASTRO-STYLES@@";
8
8
  export declare const SCRIPTS_PLACEHOLDER = "@@ASTRO-SCRIPTS@@";
9
+ export declare const CONTENT_FLAGS: readonly ["astroContentCollectionEntry", "astroRenderContent", "astroDataCollectionEntry", "astroPropagatedAssets"];
9
10
  export declare const CONTENT_TYPES_FILE = "types.d.ts";
@@ -1,15 +1,22 @@
1
1
  const PROPAGATED_ASSET_FLAG = "astroPropagatedAssets";
2
+ const CONTENT_RENDER_FLAG = "astroRenderContent";
2
3
  const CONTENT_FLAG = "astroContentCollectionEntry";
3
4
  const DATA_FLAG = "astroDataCollectionEntry";
4
- const CONTENT_FLAGS = [CONTENT_FLAG, DATA_FLAG, PROPAGATED_ASSET_FLAG];
5
5
  const VIRTUAL_MODULE_ID = "astro:content";
6
6
  const LINKS_PLACEHOLDER = "@@ASTRO-LINKS@@";
7
7
  const STYLES_PLACEHOLDER = "@@ASTRO-STYLES@@";
8
8
  const SCRIPTS_PLACEHOLDER = "@@ASTRO-SCRIPTS@@";
9
+ const CONTENT_FLAGS = [
10
+ CONTENT_FLAG,
11
+ CONTENT_RENDER_FLAG,
12
+ DATA_FLAG,
13
+ PROPAGATED_ASSET_FLAG
14
+ ];
9
15
  const CONTENT_TYPES_FILE = "types.d.ts";
10
16
  export {
11
17
  CONTENT_FLAG,
12
18
  CONTENT_FLAGS,
19
+ CONTENT_RENDER_FLAG,
13
20
  CONTENT_TYPES_FILE,
14
21
  DATA_FLAG,
15
22
  LINKS_PLACEHOLDER,
@@ -184,7 +184,7 @@ async function render({
184
184
  id,
185
185
  renderEntryImport
186
186
  }) {
187
- var _a;
187
+ var _a, _b;
188
188
  const UnexpectedRenderError = new AstroError({
189
189
  ...AstroErrorData.UnknownContentCollectionError,
190
190
  message: `Unexpected error while rendering ${String(collection)} \u2192 ${String(id)}.`
@@ -194,53 +194,70 @@ async function render({
194
194
  const baseMod = await renderEntryImport();
195
195
  if (baseMod == null || typeof baseMod !== "object")
196
196
  throw UnexpectedRenderError;
197
- const { collectedStyles, collectedLinks, collectedScripts, getMod } = baseMod;
198
- if (typeof getMod !== "function")
199
- throw UnexpectedRenderError;
200
- const mod = await getMod();
201
- if (mod == null || typeof mod !== "object")
197
+ const { default: defaultMod } = baseMod;
198
+ if (isPropagatedAssetsModule(defaultMod)) {
199
+ const { collectedStyles, collectedLinks, collectedScripts, getMod } = defaultMod;
200
+ if (typeof getMod !== "function")
201
+ throw UnexpectedRenderError;
202
+ const propagationMod = await getMod();
203
+ if (propagationMod == null || typeof propagationMod !== "object")
204
+ throw UnexpectedRenderError;
205
+ const Content = createComponent({
206
+ factory(result, baseProps, slots) {
207
+ let styles = "", links = "", scripts = "";
208
+ if (Array.isArray(collectedStyles)) {
209
+ styles = collectedStyles.map((style) => {
210
+ return renderUniqueStylesheet(result, {
211
+ type: "inline",
212
+ content: style
213
+ });
214
+ }).join("");
215
+ }
216
+ if (Array.isArray(collectedLinks)) {
217
+ links = collectedLinks.map((link) => {
218
+ return renderUniqueStylesheet(result, {
219
+ type: "external",
220
+ src: prependForwardSlash(link)
221
+ });
222
+ }).join("");
223
+ }
224
+ if (Array.isArray(collectedScripts)) {
225
+ scripts = collectedScripts.map((script) => renderScriptElement(script)).join("");
226
+ }
227
+ let props = baseProps;
228
+ if (id.endsWith("mdx")) {
229
+ props = {
230
+ components: propagationMod.components ?? {},
231
+ ...baseProps
232
+ };
233
+ }
234
+ return createHeadAndContent(
235
+ unescapeHTML(styles + links + scripts),
236
+ renderTemplate`${renderComponent(
237
+ result,
238
+ "Content",
239
+ propagationMod.Content,
240
+ props,
241
+ slots
242
+ )}`
243
+ );
244
+ },
245
+ propagation: "self"
246
+ });
247
+ return {
248
+ Content,
249
+ headings: ((_a = propagationMod.getHeadings) == null ? void 0 : _a.call(propagationMod)) ?? [],
250
+ remarkPluginFrontmatter: propagationMod.frontmatter ?? {}
251
+ };
252
+ } else if (baseMod.Content && typeof baseMod.Content === "function") {
253
+ return {
254
+ Content: baseMod.Content,
255
+ headings: ((_b = baseMod.getHeadings) == null ? void 0 : _b.call(baseMod)) ?? [],
256
+ remarkPluginFrontmatter: baseMod.frontmatter ?? {}
257
+ };
258
+ } else {
202
259
  throw UnexpectedRenderError;
203
- const Content = createComponent({
204
- factory(result, baseProps, slots) {
205
- let styles = "", links = "", scripts = "";
206
- if (Array.isArray(collectedStyles)) {
207
- styles = collectedStyles.map((style) => {
208
- return renderUniqueStylesheet(result, {
209
- type: "inline",
210
- content: style
211
- });
212
- }).join("");
213
- }
214
- if (Array.isArray(collectedLinks)) {
215
- links = collectedLinks.map((link) => {
216
- return renderUniqueStylesheet(result, {
217
- type: "external",
218
- src: prependForwardSlash(link)
219
- });
220
- }).join("");
221
- }
222
- if (Array.isArray(collectedScripts)) {
223
- scripts = collectedScripts.map((script) => renderScriptElement(script)).join("");
224
- }
225
- let props = baseProps;
226
- if (id.endsWith(".mdx")) {
227
- props = {
228
- components: mod.components ?? {},
229
- ...baseProps
230
- };
231
- }
232
- return createHeadAndContent(
233
- unescapeHTML(styles + links + scripts),
234
- renderTemplate`${renderComponent(result, "Content", mod.Content, props, slots)}`
235
- );
236
- },
237
- propagation: "self"
238
- });
239
- return {
240
- Content,
241
- headings: ((_a = mod.getHeadings) == null ? void 0 : _a.call(mod)) ?? [],
242
- remarkPluginFrontmatter: mod.frontmatter ?? {}
243
- };
260
+ }
244
261
  }
245
262
  function createReference({ lookupMap }) {
246
263
  return function reference(collection) {
@@ -271,6 +288,9 @@ function createReference({ lookupMap }) {
271
288
  });
272
289
  };
273
290
  }
291
+ function isPropagatedAssetsModule(module) {
292
+ return typeof module === "object" && module != null && "__astroPropagation" in module;
293
+ }
274
294
  export {
275
295
  createCollectionToGlobResultMap,
276
296
  createGetCollection,
@@ -1,4 +1,5 @@
1
- import { pathToFileURL } from "url";
1
+ import { extname } from "node:path";
2
+ import { pathToFileURL } from "node:url";
2
3
  import { moduleIsTopLevelPage, walkParentInfos } from "../core/build/graph.js";
3
4
  import { getPageDataByViteID } from "../core/build/internal.js";
4
5
  import { createViteLoader } from "../core/module-loader/vite.js";
@@ -6,15 +7,13 @@ import { joinPaths, prependForwardSlash } from "../core/path.js";
6
7
  import { getStylesForURL } from "../core/render/dev/css.js";
7
8
  import { getScriptsForURL } from "../core/render/dev/scripts.js";
8
9
  import {
10
+ CONTENT_RENDER_FLAG,
9
11
  LINKS_PLACEHOLDER,
10
12
  PROPAGATED_ASSET_FLAG,
11
13
  SCRIPTS_PLACEHOLDER,
12
14
  STYLES_PLACEHOLDER
13
15
  } from "./consts.js";
14
- function isPropagatedAsset(viteId) {
15
- const flags = new URLSearchParams(viteId.split("?")[1]);
16
- return flags.has(PROPAGATED_ASSET_FLAG);
17
- }
16
+ import { hasContentFlag } from "./utils.js";
18
17
  function astroContentAssetPropagationPlugin({
19
18
  mode,
20
19
  settings
@@ -22,6 +21,21 @@ function astroContentAssetPropagationPlugin({
22
21
  let devModuleLoader;
23
22
  return {
24
23
  name: "astro:content-asset-propagation",
24
+ enforce: "pre",
25
+ async resolveId(id, importer, opts) {
26
+ if (hasContentFlag(id, CONTENT_RENDER_FLAG)) {
27
+ const base = id.split("?")[0];
28
+ for (const { extensions, handlePropagation = true } of settings.contentEntryTypes) {
29
+ if (handlePropagation && extensions.includes(extname(base))) {
30
+ return this.resolve(`${base}?${PROPAGATED_ASSET_FLAG}`, importer, {
31
+ skipSelf: true,
32
+ ...opts
33
+ });
34
+ }
35
+ }
36
+ return this.resolve(base, importer, { skipSelf: true, ...opts });
37
+ }
38
+ },
25
39
  configureServer(server) {
26
40
  if (mode === "dev") {
27
41
  devModuleLoader = createViteLoader(server);
@@ -29,7 +43,7 @@ function astroContentAssetPropagationPlugin({
29
43
  },
30
44
  async transform(_, id, options) {
31
45
  var _a;
32
- if (isPropagatedAsset(id)) {
46
+ if (hasContentFlag(id, PROPAGATED_ASSET_FLAG)) {
33
47
  const basePath = id.split("?")[0];
34
48
  let stringifiedLinks, stringifiedStyles, stringifiedScripts;
35
49
  if ((options == null ? void 0 : options.ssr) && devModuleLoader) {
@@ -55,12 +69,14 @@ function astroContentAssetPropagationPlugin({
55
69
  stringifiedScripts = JSON.stringify(SCRIPTS_PLACEHOLDER);
56
70
  }
57
71
  const code = `
58
- export async function getMod() {
72
+ async function getMod() {
59
73
  return import(${JSON.stringify(basePath)});
60
74
  }
61
- export const collectedLinks = ${stringifiedLinks};
62
- export const collectedStyles = ${stringifiedStyles};
63
- export const collectedScripts = ${stringifiedScripts};
75
+ const collectedLinks = ${stringifiedLinks};
76
+ const collectedStyles = ${stringifiedStyles};
77
+ const collectedScripts = ${stringifiedScripts};
78
+ const defaultMod = { __astroPropagation: true, getMod, collectedLinks, collectedStyles, collectedScripts };
79
+ export default defaultMod;
64
80
  `;
65
81
  return { code, map: { mappings: "" } };
66
82
  }
@@ -29,15 +29,20 @@ function astroContentVirtualModPlugin({
29
29
  "@@COLLECTION_NAME_BY_REFERENCE_KEY@@",
30
30
  new URL("reference-map.json", contentPaths.cacheDir).pathname
31
31
  ).replace("@@CONTENT_DIR@@", relContentDir).replace(
32
- "@@CONTENT_ENTRY_GLOB_PATH@@",
33
- // [!_] = ignore files starting with "_"
34
- `${relContentDir}**/[!_]*${getExtGlob(contentEntryExts)}`
35
- ).replace("@@DATA_ENTRY_GLOB_PATH@@", `${relContentDir}**/[!_]*${getExtGlob(dataEntryExts)}`).replace(
36
- "@@RENDER_ENTRY_GLOB_PATH@@",
37
- `${relContentDir}**/*${getExtGlob(
38
- /** Note: data collections excluded */
39
- contentEntryExts
40
- )}`
32
+ "'@@CONTENT_ENTRY_GLOB_PATH@@'",
33
+ JSON.stringify(globWithUnderscoresIgnored(relContentDir, contentEntryExts))
34
+ ).replace(
35
+ "'@@DATA_ENTRY_GLOB_PATH@@'",
36
+ JSON.stringify(globWithUnderscoresIgnored(relContentDir, dataEntryExts))
37
+ ).replace(
38
+ "'@@RENDER_ENTRY_GLOB_PATH@@'",
39
+ JSON.stringify(
40
+ globWithUnderscoresIgnored(
41
+ relContentDir,
42
+ /** Note: data collections excluded */
43
+ contentEntryExts
44
+ )
45
+ )
41
46
  );
42
47
  const astroContentVirtualModuleId = "\0" + VIRTUAL_MODULE_ID;
43
48
  return {
@@ -150,6 +155,10 @@ const UnexpectedLookupMapError = new AstroError({
150
155
  ...AstroErrorData.UnknownContentCollectionError,
151
156
  message: `Unexpected error while parsing content entry IDs and slugs.`
152
157
  });
158
+ function globWithUnderscoresIgnored(relContentDir, exts) {
159
+ const extGlob = getExtGlob(exts);
160
+ return [`${relContentDir}/**/*${extGlob}`, `!**/_*/**${extGlob}`, `!**/_*${extGlob}`];
161
+ }
153
162
  export {
154
163
  astroContentVirtualModPlugin,
155
164
  getStringifiedLookupMap