astro 5.0.0-alpha.3 → 5.0.0-alpha.4

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.
@@ -35,7 +35,12 @@ export declare class ContentLayer {
35
35
  export declare function simpleLoader<TData extends {
36
36
  id: string;
37
37
  }>(handler: () => Array<TData> | Promise<Array<TData>>, context: LoaderContext): Promise<void>;
38
- export declare function getDataStoreFile(settings: AstroSettings): URL;
38
+ /**
39
+ * Get the path to the data store file.
40
+ * During development, this is in the `.astro` directory so that the Vite watcher can see it.
41
+ * In production, it's in the cache directory so that it's preserved between builds.
42
+ */
43
+ export declare function getDataStoreFile(settings: AstroSettings, isDev?: boolean): URL;
39
44
  export declare const globalContentLayer: {
40
45
  init: (options: ContentLayerOptions) => ContentLayer;
41
46
  get: () => ContentLayer | null;
@@ -1,7 +1,6 @@
1
1
  import { promises as fs, existsSync } from "node:fs";
2
2
  import * as fastq from "fastq";
3
3
  import xxhash from "xxhash-wasm";
4
- import { AstroUserError } from "../core/errors/errors.js";
5
4
  import {
6
5
  ASSET_IMPORTS_FILE,
7
6
  CONTENT_LAYER_TYPE,
@@ -103,18 +102,6 @@ class ContentLayer {
103
102
  logger.debug("Content config not loaded, skipping sync");
104
103
  return;
105
104
  }
106
- if (!this.#settings.config.experimental.contentLayer) {
107
- const contentLayerCollections = Object.entries(contentConfig.config.collections).filter(
108
- ([_, collection]) => collection.type === CONTENT_LAYER_TYPE
109
- );
110
- if (contentLayerCollections.length > 0) {
111
- throw new AstroUserError(
112
- `The following collections have a loader defined, but the content layer is not enabled: ${contentLayerCollections.map(([title]) => title).join(", ")}.`,
113
- "To enable the Content Layer API, set `experimental: { contentLayer: true }` in your Astro config file."
114
- );
115
- }
116
- return;
117
- }
118
105
  logger.info("Syncing content");
119
106
  const { digest: currentConfigDigest } = contentConfig.config;
120
107
  this.#lastConfigDigest = currentConfigDigest;
@@ -228,11 +215,9 @@ async function simpleLoader(handler, context) {
228
215
  context.store.set({ id: raw.id, data: item });
229
216
  }
230
217
  }
231
- function getDataStoreFile(settings) {
232
- return new URL(
233
- DATA_STORE_FILE,
234
- process?.env.NODE_ENV === "development" ? settings.dotAstroDir : settings.config.cacheDir
235
- );
218
+ function getDataStoreFile(settings, isDev) {
219
+ isDev ??= process?.env.NODE_ENV === "development";
220
+ return new URL(DATA_STORE_FILE, isDev ? settings.dotAstroDir : settings.config.cacheDir);
236
221
  }
237
222
  function contentLayerSingleton() {
238
223
  let instance = null;
@@ -36,7 +36,7 @@ export interface DataEntry<TData extends Record<string, unknown> = Record<string
36
36
  * A read-only data store for content collections. This is used to retrieve data from the content layer at runtime.
37
37
  * To add or modify data, use {@link MutableDataStore} instead.
38
38
  */
39
- export declare class DataStore {
39
+ export declare class ImmutableDataStore {
40
40
  protected _collections: Map<string, Map<string, any>>;
41
41
  constructor();
42
42
  get<T = DataEntry>(collectionName: string, key: string): T | undefined;
@@ -50,6 +50,6 @@ export declare class DataStore {
50
50
  * Attempts to load a DataStore from the virtual module.
51
51
  * This only works in Vite.
52
52
  */
53
- static fromModule(): Promise<DataStore>;
54
- static fromMap(data: Map<string, Map<string, any>>): Promise<DataStore>;
53
+ static fromModule(): Promise<ImmutableDataStore>;
54
+ static fromMap(data: Map<string, Map<string, any>>): Promise<ImmutableDataStore>;
55
55
  }
@@ -1,5 +1,5 @@
1
1
  import * as devalue from "devalue";
2
- class DataStore {
2
+ class ImmutableDataStore {
3
3
  _collections = /* @__PURE__ */ new Map();
4
4
  constructor() {
5
5
  this._collections = /* @__PURE__ */ new Map();
@@ -40,16 +40,16 @@ class DataStore {
40
40
  try {
41
41
  const data = await import("astro:data-layer-content");
42
42
  if (data.default instanceof Map) {
43
- return DataStore.fromMap(data.default);
43
+ return ImmutableDataStore.fromMap(data.default);
44
44
  }
45
45
  const map = devalue.unflatten(data.default);
46
- return DataStore.fromMap(map);
46
+ return ImmutableDataStore.fromMap(map);
47
47
  } catch {
48
48
  }
49
- return new DataStore();
49
+ return new ImmutableDataStore();
50
50
  }
51
51
  static async fromMap(data) {
52
- const store = new DataStore();
52
+ const store = new ImmutableDataStore();
53
53
  store._collections = data;
54
54
  return store;
55
55
  }
@@ -59,7 +59,7 @@ function dataStoreSingleton() {
59
59
  return {
60
60
  get: async () => {
61
61
  if (!instance) {
62
- instance = DataStore.fromModule();
62
+ instance = ImmutableDataStore.fromModule();
63
63
  }
64
64
  return instance;
65
65
  },
@@ -70,6 +70,6 @@ function dataStoreSingleton() {
70
70
  }
71
71
  const globalDataStore = dataStoreSingleton();
72
72
  export {
73
- DataStore,
73
+ ImmutableDataStore,
74
74
  globalDataStore
75
75
  };
@@ -2,8 +2,8 @@ import type { FSWatcher } from 'vite';
2
2
  import type { ZodSchema } from 'zod';
3
3
  import type { AstroIntegrationLogger } from '../../core/logger/core.js';
4
4
  import type { AstroConfig } from '../../types/public/config.js';
5
- import type { ContentEntryType } from '../../types/public/content.js';
6
- import type { MetaStore, ScopedDataStore } from '../mutable-data-store.js';
5
+ import type { DataStore, MetaStore } from '../mutable-data-store.js';
6
+ export type { DataStore, MetaStore };
7
7
  export interface ParseDataOptions<TData extends Record<string, unknown>> {
8
8
  /** The ID of the entry. Unique per collection */
9
9
  id: string;
@@ -15,8 +15,8 @@ export interface ParseDataOptions<TData extends Record<string, unknown>> {
15
15
  export interface LoaderContext {
16
16
  /** The unique name of the collection */
17
17
  collection: string;
18
- /** A database abstraction to store the actual data */
19
- store: ScopedDataStore;
18
+ /** A database to store the actual data */
19
+ store: DataStore;
20
20
  /** A simple KV store, designed for things like sync tokens */
21
21
  meta: MetaStore;
22
22
  logger: AstroIntegrationLogger;
@@ -30,7 +30,6 @@ export interface LoaderContext {
30
30
  watcher?: FSWatcher;
31
31
  /** If the loader has been triggered by an integration, this may optionally contain extra data set by that integration */
32
32
  refreshContextData?: Record<string, unknown>;
33
- entryTypes: Map<string, ContentEntryType>;
34
33
  }
35
34
  export interface Loader {
36
35
  /** Unique name of the loader, e.g. the npm package name */
@@ -1,10 +1,10 @@
1
1
  import { type PathLike } from 'node:fs';
2
- import { type DataEntry, DataStore, type RenderedContent } from './data-store.js';
2
+ import { type DataEntry, ImmutableDataStore, type RenderedContent } from './data-store.js';
3
3
  /**
4
4
  * Extends the DataStore with the ability to change entries and write them to disk.
5
5
  * This is kept as a separate class to avoid needing node builtins at runtime, when read-only access is all that is needed.
6
6
  */
7
- export declare class MutableDataStore extends DataStore {
7
+ export declare class MutableDataStore extends ImmutableDataStore {
8
8
  #private;
9
9
  set(collectionName: string, key: string, value: unknown): void;
10
10
  delete(collectionName: string, key: string): void;
@@ -15,7 +15,7 @@ export declare class MutableDataStore extends DataStore {
15
15
  addModuleImport(fileName: string): void;
16
16
  writeAssetImports(filePath: PathLike): Promise<void>;
17
17
  writeModuleImports(filePath: PathLike): Promise<void>;
18
- scopedStore(collectionName: string): ScopedDataStore;
18
+ scopedStore(collectionName: string): DataStore;
19
19
  /**
20
20
  * Returns a MetaStore for a given collection, or if no collection is provided, the default meta collection.
21
21
  */
@@ -31,7 +31,7 @@ export declare class MutableDataStore extends DataStore {
31
31
  static fromString(data: string): Promise<MutableDataStore>;
32
32
  static fromFile(filePath: string | URL): Promise<MutableDataStore>;
33
33
  }
34
- export interface ScopedDataStore {
34
+ export interface DataStore {
35
35
  get: <TData extends Record<string, unknown> = Record<string, unknown>>(key: string) => DataEntry<TData> | undefined;
36
36
  entries: () => Array<[id: string, DataEntry]>;
37
37
  set: <TData extends Record<string, unknown>>(opts: {
@@ -4,10 +4,10 @@ import { Traverse } from "neotraverse/modern";
4
4
  import { imageSrcToImportId, importIdToSymbolName } from "../assets/utils/resolveImports.js";
5
5
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
6
6
  import { IMAGE_IMPORT_PREFIX } from "./consts.js";
7
- import { DataStore } from "./data-store.js";
7
+ import { ImmutableDataStore } from "./data-store.js";
8
8
  import { contentModuleToId } from "./utils.js";
9
9
  const SAVE_DEBOUNCE_MS = 500;
10
- class MutableDataStore extends DataStore {
10
+ class MutableDataStore extends ImmutableDataStore {
11
11
  #file;
12
12
  #assetsFile;
13
13
  #modulesFile;
@@ -17,7 +17,6 @@ import {
17
17
  CONTENT_FLAG,
18
18
  CONTENT_RENDER_FLAG,
19
19
  DATA_FLAG,
20
- DATA_STORE_FILE,
21
20
  DATA_STORE_VIRTUAL_ID,
22
21
  MODULES_IMPORTS_FILE,
23
22
  MODULES_MJS_ID,
@@ -26,6 +25,7 @@ import {
26
25
  RESOLVED_VIRTUAL_MODULE_ID,
27
26
  VIRTUAL_MODULE_ID
28
27
  } from "./consts.js";
28
+ import { getDataStoreFile } from "./content-layer.js";
29
29
  import {
30
30
  getContentEntryIdAndSlug,
31
31
  getContentPaths,
@@ -50,10 +50,7 @@ function astroContentVirtualModPlugin({
50
50
  enforce: "pre",
51
51
  configResolved(config) {
52
52
  IS_DEV = config.mode === "development";
53
- dataStoreFile = new URL(
54
- DATA_STORE_FILE,
55
- IS_DEV ? settings.dotAstroDir : settings.config.cacheDir
56
- );
53
+ dataStoreFile = getDataStoreFile(settings, IS_DEV);
57
54
  },
58
55
  async resolveId(id) {
59
56
  if (id === VIRTUAL_MODULE_ID) {
@@ -61,7 +61,6 @@ export declare const ASTRO_CONFIG_DEFAULTS: {
61
61
  clientPrerender: false;
62
62
  serverIslands: false;
63
63
  contentIntellisense: false;
64
- contentLayer: false;
65
64
  };
66
65
  };
67
66
  export declare const AstroConfigSchema: z.ZodObject<{
@@ -622,19 +621,16 @@ export declare const AstroConfigSchema: z.ZodObject<{
622
621
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
623
622
  serverIslands: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
624
623
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
625
- contentLayer: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
626
624
  }, "strict", z.ZodTypeAny, {
627
625
  contentCollectionCache: boolean;
628
626
  clientPrerender: boolean;
629
627
  serverIslands: boolean;
630
628
  contentIntellisense: boolean;
631
- contentLayer: boolean;
632
629
  }, {
633
630
  contentCollectionCache?: boolean | undefined;
634
631
  clientPrerender?: boolean | undefined;
635
632
  serverIslands?: boolean | undefined;
636
633
  contentIntellisense?: boolean | undefined;
637
- contentLayer?: boolean | undefined;
638
634
  }>>;
639
635
  legacy: z.ZodDefault<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
640
636
  }, "strip", z.ZodTypeAny, {
@@ -760,7 +756,6 @@ export declare const AstroConfigSchema: z.ZodObject<{
760
756
  clientPrerender: boolean;
761
757
  serverIslands: boolean;
762
758
  contentIntellisense: boolean;
763
- contentLayer: boolean;
764
759
  };
765
760
  legacy: {};
766
761
  site?: string | undefined;
@@ -924,7 +919,6 @@ export declare const AstroConfigSchema: z.ZodObject<{
924
919
  clientPrerender?: boolean | undefined;
925
920
  serverIslands?: boolean | undefined;
926
921
  contentIntellisense?: boolean | undefined;
927
- contentLayer?: boolean | undefined;
928
922
  } | undefined;
929
923
  legacy?: {} | undefined;
930
924
  }>;
@@ -1487,19 +1481,16 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1487
1481
  clientPrerender: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1488
1482
  serverIslands: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1489
1483
  contentIntellisense: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1490
- contentLayer: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1491
1484
  }, "strict", z.ZodTypeAny, {
1492
1485
  contentCollectionCache: boolean;
1493
1486
  clientPrerender: boolean;
1494
1487
  serverIslands: boolean;
1495
1488
  contentIntellisense: boolean;
1496
- contentLayer: boolean;
1497
1489
  }, {
1498
1490
  contentCollectionCache?: boolean | undefined;
1499
1491
  clientPrerender?: boolean | undefined;
1500
1492
  serverIslands?: boolean | undefined;
1501
1493
  contentIntellisense?: boolean | undefined;
1502
- contentLayer?: boolean | undefined;
1503
1494
  }>>;
1504
1495
  legacy: z.ZodDefault<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
1505
1496
  }, {
@@ -1700,7 +1691,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1700
1691
  clientPrerender: boolean;
1701
1692
  serverIslands: boolean;
1702
1693
  contentIntellisense: boolean;
1703
- contentLayer: boolean;
1704
1694
  };
1705
1695
  legacy: {};
1706
1696
  site?: string | undefined;
@@ -1864,7 +1854,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1864
1854
  clientPrerender?: boolean | undefined;
1865
1855
  serverIslands?: boolean | undefined;
1866
1856
  contentIntellisense?: boolean | undefined;
1867
- contentLayer?: boolean | undefined;
1868
1857
  } | undefined;
1869
1858
  legacy?: {} | undefined;
1870
1859
  }>, {
@@ -1991,7 +1980,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
1991
1980
  clientPrerender: boolean;
1992
1981
  serverIslands: boolean;
1993
1982
  contentIntellisense: boolean;
1994
- contentLayer: boolean;
1995
1983
  };
1996
1984
  legacy: {};
1997
1985
  site?: string | undefined;
@@ -2155,7 +2143,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
2155
2143
  clientPrerender?: boolean | undefined;
2156
2144
  serverIslands?: boolean | undefined;
2157
2145
  contentIntellisense?: boolean | undefined;
2158
- contentLayer?: boolean | undefined;
2159
2146
  } | undefined;
2160
2147
  legacy?: {} | undefined;
2161
2148
  }>, {
@@ -2282,7 +2269,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
2282
2269
  clientPrerender: boolean;
2283
2270
  serverIslands: boolean;
2284
2271
  contentIntellisense: boolean;
2285
- contentLayer: boolean;
2286
2272
  };
2287
2273
  legacy: {};
2288
2274
  site?: string | undefined;
@@ -2446,7 +2432,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
2446
2432
  clientPrerender?: boolean | undefined;
2447
2433
  serverIslands?: boolean | undefined;
2448
2434
  contentIntellisense?: boolean | undefined;
2449
- contentLayer?: boolean | undefined;
2450
2435
  } | undefined;
2451
2436
  legacy?: {} | undefined;
2452
2437
  }>, {
@@ -2573,7 +2558,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
2573
2558
  clientPrerender: boolean;
2574
2559
  serverIslands: boolean;
2575
2560
  contentIntellisense: boolean;
2576
- contentLayer: boolean;
2577
2561
  };
2578
2562
  legacy: {};
2579
2563
  site?: string | undefined;
@@ -2737,7 +2721,6 @@ export declare function createRelativeSchema(cmd: string, fileProtocolRoot: stri
2737
2721
  clientPrerender?: boolean | undefined;
2738
2722
  serverIslands?: boolean | undefined;
2739
2723
  contentIntellisense?: boolean | undefined;
2740
- contentLayer?: boolean | undefined;
2741
2724
  } | undefined;
2742
2725
  legacy?: {} | undefined;
2743
2726
  }>;
@@ -50,8 +50,7 @@ const ASTRO_CONFIG_DEFAULTS = {
50
50
  contentCollectionCache: false,
51
51
  clientPrerender: false,
52
52
  serverIslands: false,
53
- contentIntellisense: false,
54
- contentLayer: false
53
+ contentIntellisense: false
55
54
  }
56
55
  };
57
56
  const AstroConfigSchema = z.object({
@@ -329,8 +328,7 @@ const AstroConfigSchema = z.object({
329
328
  contentCollectionCache: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentCollectionCache),
330
329
  clientPrerender: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.clientPrerender),
331
330
  serverIslands: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.serverIslands),
332
- contentIntellisense: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentIntellisense),
333
- contentLayer: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentLayer)
331
+ contentIntellisense: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentIntellisense)
334
332
  }).strict(
335
333
  `Invalid or outdated experimental feature.
336
334
  Check for incorrect spelling or outdated Astro version.
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "5.0.0-alpha.3";
1
+ const ASTRO_VERSION = "5.0.0-alpha.4";
2
2
  const REROUTE_DIRECTIVE_HEADER = "X-Astro-Reroute";
3
3
  const REWRITE_DIRECTIVE_HEADER_KEY = "X-Astro-Rewrite";
4
4
  const REWRITE_DIRECTIVE_HEADER_VALUE = "yes";
@@ -22,7 +22,7 @@ async function dev(inlineConfig) {
22
22
  await telemetry.record([]);
23
23
  const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
24
24
  const logger = restart.container.logger;
25
- const currentVersion = "5.0.0-alpha.3";
25
+ const currentVersion = "5.0.0-alpha.4";
26
26
  const isPrerelease = currentVersion.includes("-");
27
27
  if (!isPrerelease) {
28
28
  try {
@@ -125,15 +125,13 @@ async function createContainerWithAutomaticRestart({
125
125
  { key: "u", description: "" },
126
126
  { key: "c", description: "" }
127
127
  ];
128
- if (restart.container.settings.config.experimental.contentLayer) {
129
- customShortcuts.push({
130
- key: "s",
131
- description: "sync content layer",
132
- action: () => {
133
- globalContentLayer.get()?.sync();
134
- }
135
- });
136
- }
128
+ customShortcuts.push({
129
+ key: "s",
130
+ description: "sync content layer",
131
+ action: () => {
132
+ globalContentLayer.get()?.sync();
133
+ }
134
+ });
137
135
  restart.container.viteServer.bindCLIShortcuts({
138
136
  customShortcuts
139
137
  });
@@ -38,7 +38,7 @@ function serverStart({
38
38
  host,
39
39
  base
40
40
  }) {
41
- const version = "5.0.0-alpha.3";
41
+ const version = "5.0.0-alpha.4";
42
42
  const localPrefix = `${dim("\u2503")} Local `;
43
43
  const networkPrefix = `${dim("\u2503")} Network `;
44
44
  const emptyPrefix = " ".repeat(11);
@@ -270,7 +270,7 @@ function printHelp({
270
270
  message.push(
271
271
  linebreak(),
272
272
  ` ${bgGreen(black(` ${commandName} `))} ${green(
273
- `v${"5.0.0-alpha.3"}`
273
+ `v${"5.0.0-alpha.4"}`
274
274
  )} ${headline}`
275
275
  );
276
276
  }
@@ -1,8 +1,10 @@
1
1
  import fsMod, { existsSync } from "node:fs";
2
+ import { dirname, relative } from "node:path";
2
3
  import { performance } from "node:perf_hooks";
3
4
  import { fileURLToPath } from "node:url";
4
5
  import { dim } from "kleur/colors";
5
6
  import { createServer } from "vite";
7
+ import { normalizePath } from "vite";
6
8
  import { CONTENT_TYPES_FILE } from "../../content/consts.js";
7
9
  import { getDataStoreFile, globalContentLayer } from "../../content/content-layer.js";
8
10
  import { createContentTypesGenerator } from "../../content/index.js";
@@ -27,7 +29,6 @@ import {
27
29
  } from "../errors/index.js";
28
30
  import { formatErrorMessage } from "../messages.js";
29
31
  import { ensureProcessNodeEnv } from "../util.js";
30
- import { writeFiles } from "./write-files.js";
31
32
  async function sync(inlineConfig, { fs, telemetry: _telemetry = false } = {}) {
32
33
  ensureProcessNodeEnv("production");
33
34
  const logger = createNodeLogger(inlineConfig);
@@ -97,7 +98,7 @@ async function syncInternal({
97
98
  });
98
99
  }
99
100
  syncAstroEnv(settings);
100
- await writeFiles(settings, fs, logger);
101
+ writeInjectedTypes(settings, fs);
101
102
  logger.info("types", `Generated ${dim(getTimeStat(timerStart, performance.now()))}`);
102
103
  } catch (err) {
103
104
  const error = createSafeError(err);
@@ -108,6 +109,29 @@ async function syncInternal({
108
109
  throw error;
109
110
  }
110
111
  }
112
+ function getTsReference(type, value) {
113
+ return `/// <reference ${type}=${JSON.stringify(value)} />`;
114
+ }
115
+ const CLIENT_TYPES_REFERENCE = getTsReference("types", "astro/client");
116
+ function writeInjectedTypes(settings, fs) {
117
+ const references = [];
118
+ for (const { filename, content } of settings.injectedTypes) {
119
+ const filepath = fileURLToPath(new URL(filename, settings.dotAstroDir));
120
+ fs.mkdirSync(dirname(filepath), { recursive: true });
121
+ fs.writeFileSync(filepath, content, "utf-8");
122
+ references.push(normalizePath(relative(fileURLToPath(settings.dotAstroDir), filepath)));
123
+ }
124
+ const astroDtsContent = `${CLIENT_TYPES_REFERENCE}
125
+ ${references.map((reference) => getTsReference("path", reference)).join("\n")}`;
126
+ if (references.length === 0) {
127
+ fs.mkdirSync(settings.dotAstroDir, { recursive: true });
128
+ }
129
+ fs.writeFileSync(
130
+ fileURLToPath(new URL("./types.d.ts", settings.dotAstroDir)),
131
+ astroDtsContent,
132
+ "utf-8"
133
+ );
134
+ }
111
135
  async function syncContentCollections(settings, { logger, fs }) {
112
136
  const tempViteServer = await createServer(
113
137
  await createVite(
@@ -276,18 +276,16 @@ async function runHookServerSetup({
276
276
  logger
277
277
  }) {
278
278
  let refreshContent;
279
- if (config.experimental?.contentLayer) {
280
- refreshContent = async (options) => {
281
- const contentConfig = globalContentConfigObserver.get();
282
- if (contentConfig.status !== "loaded" || !Object.values(contentConfig.config.collections).some(
283
- (collection) => collection.type === CONTENT_LAYER_TYPE
284
- )) {
285
- return;
286
- }
287
- const contentLayer = await globalContentLayer.get();
288
- await contentLayer?.sync(options);
289
- };
290
- }
279
+ refreshContent = async (options) => {
280
+ const contentConfig = globalContentConfigObserver.get();
281
+ if (contentConfig.status !== "loaded" || !Object.values(contentConfig.config.collections).some(
282
+ (collection) => collection.type === CONTENT_LAYER_TYPE
283
+ )) {
284
+ return;
285
+ }
286
+ const contentLayer = await globalContentLayer.get();
287
+ await contentLayer?.sync(options);
288
+ };
291
289
  for (const integration of config.integrations) {
292
290
  if (integration?.hooks?.["astro:server:setup"]) {
293
291
  await withTakingALongTimeMsg({
@@ -1573,204 +1573,6 @@ export interface AstroUserConfig {
1573
1573
  * To use this feature with the Astro VS Code extension, you must also enable the `astro.content-intellisense` option in your VS Code settings. For editors using the Astro language server directly, pass the `contentIntellisense: true` initialization parameter to enable this feature.
1574
1574
  */
1575
1575
  contentIntellisense?: boolean;
1576
- /**
1577
- * @docs
1578
- * @name experimental.contentLayer
1579
- * @type {boolean}
1580
- * @default `false`
1581
- * @version 4.14.0
1582
- * @description
1583
- *
1584
- * The Content Layer API is a new way to handle content and data in Astro. It is similar to and builds upon [content collections](/en/guides/content-collections/), taking them beyond local files in `src/content/` and allowing you to fetch content from anywhere, including remote APIs, by adding a `loader` to your collection.
1585
- *
1586
- * Your existing content collections can be [migrated to the Content Layer API](#migrating-an-existing-content-collection-to-use-the-content-layer-api) with a few small changes. However, it is not necessary to update all your collections at once to add a new collection powered by the Content Layer API. You may have collections using both the existing and new APIs defined in `src/content/config.ts` at the same time.
1587
- *
1588
- * The Content Layer API is designed to be more powerful and more performant, helping sites scale to thousands of pages. Data is cached between builds and updated incrementally. Markdown parsing is also 5-10 times faster, with similar scale reductions in memory, and MDX is 2-3 times faster.
1589
- *
1590
- * To enable, add the `contentLayer` flag to the `experimental` object in your Astro config:
1591
- *
1592
- * ```js
1593
- * // astro.config.mjs
1594
- * {
1595
- * experimental: {
1596
- * contentLayer: true,
1597
- * }
1598
- * }
1599
- * ```
1600
- *
1601
- * #### Fetching data with a `loader`
1602
- *
1603
- * The Content Layer API allows you to fetch your content from outside of the `src/content/` folder (whether stored locally in your project or remotely) and uses a `loader` property to retrieve your data.
1604
- *
1605
- * The `loader` is defined in the collection's schema and returns an array of entries. Astro provides two built-in loader functions (`glob()` and `file()`) for fetching your local content, as well as access to the API to [construct your own loader and fetch remote data](#creating-a-loader).
1606
- *
1607
- * The `glob()` loader creates entries from directories of Markdown, MDX, Markdoc, or JSON files from anywhere on the filesystem. It accepts a `pattern` of entry files to match, and a `base` file path of where your files are located. Use this when you have one file per entry.
1608
- *
1609
- * The `file()` loader creates multiple entries from a single local file. Use this when all your entries are stored in an array of objects.
1610
- *
1611
- * ```ts {3,8,19}
1612
- * // src/content/config.ts
1613
- * import { defineCollection, z } from 'astro:content';
1614
- * import { glob, file } from 'astro/loaders';
1615
- *
1616
- * const blog = defineCollection({
1617
- * // By default the ID is a slug generated from
1618
- * // the path of the file relative to `base`
1619
- * loader: glob({ pattern: "**\/*.md", base: "./src/data/blog" }),
1620
- * schema: z.object({
1621
- * title: z.string(),
1622
- * description: z.string(),
1623
- * pubDate: z.coerce.date(),
1624
- * updatedDate: z.coerce.date().optional(),
1625
- * })
1626
- * });
1627
- *
1628
- * const dogs = defineCollection({
1629
- * // The path is relative to the project root, or an absolute path.
1630
- * loader: file("src/data/dogs.json"),
1631
- * schema: z.object({
1632
- * id: z.string(),
1633
- * breed: z.string(),
1634
- * temperament: z.array(z.string()),
1635
- * }),
1636
- * });
1637
- *
1638
- * export const collections = { blog, dogs };
1639
- * ```
1640
- *
1641
- * :::note
1642
- * Loaders will not automatically [exclude files prefaced with an `_`](/en/guides/routing/#excluding-pages). Use a regular expression such as `pattern: '**\/[^_]*.md'` in your loader to ignore these files.
1643
- * :::
1644
- *
1645
- * #### Querying and rendering with the Content Layer API
1646
- *
1647
- * The collection can be [queried in the same way as content collections](/en/guides/content-collections/#querying-collections):
1648
- *
1649
- * ```ts
1650
- * // src/pages/index.astro
1651
- * import { getCollection, getEntry } from 'astro:content';
1652
- *
1653
- * // Get all entries from a collection.
1654
- * // Requires the name of the collection as an argument.
1655
- * const allBlogPosts = await getCollection('blog');
1656
- *
1657
- * // Get a single entry from a collection.
1658
- * // Requires the name of the collection and ID
1659
- * const labradorData = await getEntry('dogs', 'labrador-retriever');
1660
- * ```
1661
- *
1662
- * Entries generated from Markdown, MDX, or Markdoc can be rendered directly to a page using the `render()` function.
1663
- *
1664
- * :::note
1665
- * The syntax for rendering collection entries is different from the current content collections syntax.
1666
- * :::
1667
- *
1668
- * ```astro title="src/pages/[slug].astro"
1669
- * ---
1670
- * import { getEntry, render } from 'astro:content';
1671
- *
1672
- * const post = await getEntry('blog', Astro.params.slug);
1673
- *
1674
- * const { Content, headings } = await render(post);
1675
- * ---
1676
- *
1677
- * <Content />
1678
- * ```
1679
- *
1680
- * #### Creating a loader
1681
- *
1682
- * With the Content Layer API, you can build loaders to load or generate content from anywhere.
1683
- *
1684
- * For example, you can create a loader that fetches collection entries from a remote API.
1685
- *
1686
- * ```ts
1687
- * // src/content/config.ts
1688
- * const countries = defineCollection({
1689
- * loader: async () => {
1690
- * const response = await fetch("https://restcountries.com/v3.1/all");
1691
- * const data = await response.json();
1692
- * // Must return an array of entries with an id property,
1693
- * // or an object with IDs as keys and entries as values
1694
- * return data.map((country) => ({
1695
- * id: country.cca3,
1696
- * ...country,
1697
- * }));
1698
- * },
1699
- * // optionally add a schema
1700
- * // schema: z.object...
1701
- * });
1702
- *
1703
- * export const collections = { countries };
1704
- * ```
1705
- *
1706
- * For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading while also giving full access to the data store. See the API in [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md#loaders).
1707
- *
1708
- * #### Migrating an existing content collection to use the Content Layer API
1709
- *
1710
- * You can convert an existing content collection with Markdown, MDX, Markdoc, or JSON entries to use the Content Layer API.
1711
- *
1712
- * 1. **Move the collection folder out of `src/content/`** (e.g. to `src/data/`). All collections located in the `src/content/` folder will use the existing Content Collections API.
1713
- *
1714
- * **Do not move the existing `src/content/config.ts` file**. This file will define all collections, using either API.
1715
- *
1716
- * 2. **Edit the collection definition**. Your updated collection requires a `loader`, and the option to select a collection `type` is no longer available.
1717
- *
1718
- * ```ts ins={3,8} del={7}
1719
- * // src/content/config.ts
1720
- * import { defineCollection, z } from 'astro:content';
1721
- * import { glob } from 'astro/loaders';
1722
- *
1723
- * const blog = defineCollection({
1724
- * // For content layer you no longer define a `type`
1725
- * type: 'content',
1726
- * loader: glob({ pattern: '**\/[^_]*.md', base: "./src/data/blog" }),
1727
- * schema: z.object({
1728
- * title: z.string(),
1729
- * description: z.string(),
1730
- * pubDate: z.coerce.date(),
1731
- * updatedDate: z.coerce.date().optional(),
1732
- * }),
1733
- * });
1734
- * ```
1735
- *
1736
- * 3. **Change references from `slug` to `id`**. Content layer collections do not have a `slug` field. Instead, all updated collections will have an `id`.
1737
- *
1738
- * ```astro ins={7} del={6}
1739
- * // src/pages/index.astro
1740
- * ---
1741
- * export async function getStaticPaths() {
1742
- * const posts = await getCollection('blog');
1743
- * return posts.map((post) => ({
1744
- * params: { slug: post.slug },
1745
- * params: { slug: post.id },
1746
- * props: post,
1747
- * }));
1748
- * }
1749
- * ---
1750
- * ```
1751
- *
1752
- * 4. **Switch to the new `render()` function**. Entries no longer have a `render()` method, as they are now serializable plain objects. Instead, import the `render()` function from `astro:content`.
1753
- *
1754
- * ```astro ins={4,9} del={3,8}
1755
- * // src/pages/index.astro
1756
- * ---
1757
- * import { getEntry } from 'astro:content';
1758
- * import { getEntry, render } from 'astro:content';
1759
- *
1760
- * const post = await getEntry('blog', params.slug);
1761
- *
1762
- * const { Content, headings } = await post.render();
1763
- * const { Content, headings } = await render(post);
1764
- * ---
1765
- *
1766
- * <Content />
1767
- * ```
1768
- *
1769
- * #### Learn more
1770
- *
1771
- * For a complete overview and the full API reference, see [the Content Layer API RFC](https://github.com/withastro/roadmap/blob/content-layer/proposals/0047-content-layer.md) and [share your feedback](https://github.com/withastro/roadmap/pull/982).
1772
- */
1773
- contentLayer?: boolean;
1774
1576
  };
1775
1577
  }
1776
1578
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "5.0.0-alpha.3",
3
+ "version": "5.0.0-alpha.4",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -168,8 +168,8 @@
168
168
  "zod-to-json-schema": "^3.23.2",
169
169
  "zod-to-ts": "^1.2.0",
170
170
  "@astrojs/internal-helpers": "0.4.1",
171
- "@astrojs/markdown-remark": "6.0.0-alpha.1",
172
- "@astrojs/telemetry": "3.1.0"
171
+ "@astrojs/telemetry": "3.1.0",
172
+ "@astrojs/markdown-remark": "6.0.0-alpha.1"
173
173
  },
174
174
  "optionalDependencies": {
175
175
  "sharp": "^0.33.3"
@@ -1 +0,0 @@
1
- export declare const REFERENCE_FILE = "./types.d.ts";
@@ -1,4 +0,0 @@
1
- const REFERENCE_FILE = "./types.d.ts";
2
- export {
3
- REFERENCE_FILE
4
- };
@@ -1,4 +0,0 @@
1
- import type fsMod from 'node:fs';
2
- import type { AstroSettings } from '../../types/astro.js';
3
- import type { Logger } from '../logger/core.js';
4
- export declare function writeFiles(settings: AstroSettings, fs: typeof fsMod, logger: Logger): Promise<void>;
@@ -1,67 +0,0 @@
1
- import { dirname, relative } from "node:path";
2
- import { fileURLToPath } from "node:url";
3
- import { bold } from "kleur/colors";
4
- import { normalizePath } from "vite";
5
- import { AstroError, AstroErrorData } from "../errors/index.js";
6
- import { REFERENCE_FILE } from "./constants.js";
7
- async function writeFiles(settings, fs, logger) {
8
- try {
9
- writeInjectedTypes(settings, fs);
10
- await setUpEnvTs(settings, fs, logger);
11
- } catch (e) {
12
- throw new AstroError(AstroErrorData.UnknownFilesystemError, { cause: e });
13
- }
14
- }
15
- function getTsReference(type, value) {
16
- return `/// <reference ${type}=${JSON.stringify(value)} />`;
17
- }
18
- const CLIENT_TYPES_REFERENCE = getTsReference("types", "astro/client");
19
- function writeInjectedTypes(settings, fs) {
20
- const references = [];
21
- for (const { filename, content } of settings.injectedTypes) {
22
- const filepath = fileURLToPath(new URL(filename, settings.dotAstroDir));
23
- fs.mkdirSync(dirname(filepath), { recursive: true });
24
- fs.writeFileSync(filepath, content, "utf-8");
25
- references.push(normalizePath(relative(fileURLToPath(settings.dotAstroDir), filepath)));
26
- }
27
- const astroDtsContent = `${CLIENT_TYPES_REFERENCE}
28
- ${references.map((reference) => getTsReference("path", reference)).join("\n")}`;
29
- if (references.length === 0) {
30
- fs.mkdirSync(settings.dotAstroDir, { recursive: true });
31
- }
32
- fs.writeFileSync(
33
- fileURLToPath(new URL(REFERENCE_FILE, settings.dotAstroDir)),
34
- astroDtsContent,
35
- "utf-8"
36
- );
37
- }
38
- async function setUpEnvTs(settings, fs, logger) {
39
- const envTsPath = fileURLToPath(new URL("env.d.ts", settings.config.srcDir));
40
- const envTsPathRelativetoRoot = relative(fileURLToPath(settings.config.root), envTsPath);
41
- const relativePath = normalizePath(
42
- relative(
43
- fileURLToPath(settings.config.srcDir),
44
- fileURLToPath(new URL(REFERENCE_FILE, settings.dotAstroDir))
45
- )
46
- );
47
- const expectedTypeReference = getTsReference("path", relativePath);
48
- if (fs.existsSync(envTsPath)) {
49
- const initialEnvContents = await fs.promises.readFile(envTsPath, "utf-8");
50
- let typesEnvContents = initialEnvContents;
51
- if (!typesEnvContents.includes(expectedTypeReference)) {
52
- typesEnvContents = `${expectedTypeReference}
53
- ${typesEnvContents}`;
54
- }
55
- if (initialEnvContents !== typesEnvContents) {
56
- logger.info("types", `Updated ${bold(envTsPathRelativetoRoot)} type declarations.`);
57
- await fs.promises.writeFile(envTsPath, typesEnvContents, "utf-8");
58
- }
59
- } else {
60
- await fs.promises.mkdir(settings.config.srcDir, { recursive: true });
61
- await fs.promises.writeFile(envTsPath, expectedTypeReference, "utf-8");
62
- logger.info("types", `Added ${bold(envTsPathRelativetoRoot)} type declarations`);
63
- }
64
- }
65
- export {
66
- writeFiles
67
- };