From d9546c9e71b9df30858debb0fcd5032e9710fd1e Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Mon, 5 Dec 2022 15:40:10 -0500 Subject: [PATCH 001/125] new: content collections intro --- src/pages/en/guides/content-collections.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/pages/en/guides/content-collections.md diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md new file mode 100644 index 0000000000000..79f2916b271fb --- /dev/null +++ b/src/pages/en/guides/content-collections.md @@ -0,0 +1,19 @@ +--- +layout: ~/layouts/MainLayout.astro +title: Content Collections (Experimental) +description: Content collections help organize your Markdown and type-check your frontmatter with schemas. +i18nReady: false +--- + +Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. You may reach for collections if you: +- Have a medium-to-large number of documents to manage and fetch (exmaple: a blog with 50+ posts). +- Want to enforce frontmatter fields, and fail if fields are missing (example: every blog post should have a title and description). +- Plan to use content in multiple areas of your site (landing pages, footers, navigation, etc). + +## Glossary + +We'll be using the words "schema," "collection," and "entry" throughout these docs. Let's define them: + +- **Schema:** a way to codify the "structure" of your data. In this case, frontmatter data +- **Collection:** a set of data that share a common schema. In this case, Markdown and MDX files +- **Entry:** A piece of data (Markdown or MDX file) belonging to a given collection From a06e06feceea99baea973eece629a31d8083d7a8 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Mon, 5 Dec 2022 15:51:02 -0500 Subject: [PATCH 002/125] draft: paste from RFC initial pass --- src/pages/en/guides/content-collections.md | 239 ++++++++++++++++++++- 1 file changed, 236 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 79f2916b271fb..1f72b364f863a 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -6,14 +6,247 @@ i18nReady: false --- Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. You may reach for collections if you: -- Have a medium-to-large number of documents to manage and fetch (exmaple: a blog with 50+ posts). +- Have a medium-to-large number of documents to manage and fetch (example: a blog with 50+ posts). - Want to enforce frontmatter fields, and fail if fields are missing (example: every blog post should have a title and description). - Plan to use content in multiple areas of your site (landing pages, footers, navigation, etc). ## Glossary -We'll be using the words "schema," "collection," and "entry" throughout these docs. Let's define them: - - **Schema:** a way to codify the "structure" of your data. In this case, frontmatter data - **Collection:** a set of data that share a common schema. In this case, Markdown and MDX files - **Entry:** A piece of data (Markdown or MDX file) belonging to a given collection + +## The `src/content/` directory + +This RFC introduces a new, reserved directory for Astro to manage: `{srcDir}/content/`. This directory is where all collections and schema definitions live, relative to your configured source directory. + +## The `.astro` cache directory + +Since we will preprocess your post frontmatter separate from Vite ([see background](#background)), we need a new home for generated metadata. This will be a special `.astro` directory **generated by Astro** at build time or on dev server startup. + +We expect `.astro` to live at the base of your project directory. This falls inline with generated directories like `.vscode` for editor tooling and `.vercel` for deployments. + +To clarify, **the user will not view or edit files in the `.astro` directory.** However, since it will live at the base of their project, they are free to check this generated directory into their repository. + +## The `astro:content` module + +Content Schemas introduces a new virtual module convention for Astro using the `astro:` prefix. Since all types and utilities are generated based on your content, we are free to use whatever name we choose. We chose `astro:` for this proposal since: +1. It falls in-line with [NodeJS' `node:` convention](https://2ality.com/2021/12/node-protocol-imports.html). +2. It leaves the door open for future `astro:` utility modules based on your project's configuration. + +The user will import helpers like `getCollection` and `getEntry` from `astro:content` like so: + +```tsx +import { getCollection, getEntry } from 'astro:content'; +``` + +Users can also expect full auto-importing and intellisense from their editor. + + +## Creating a collection + +All entries in `src/content/` **must** be nested in a "collection" directory. This allows you to get a collection of entries based on the directory name, and optionally enforce frontmatter types with a schema. This is similar to creating a new table in a database, or a new content model in a CMS like Contentful. + +What this looks like in practice: + +```bash +src/content/ + # All newsletters have the same frontmatter properties + newsletters/ + week-1.md + week-2.md + week-3.md + # All blog posts have the same frontmatter properties + blog/ + columbia.md + enterprise.md + endeavour.md +``` + +### Nested directories + +Collections are considered **one level deep**, so you cannot nest collections (or collection schemas) within other collections. However, we *will* allow nested directories to better organize your content. This is vital for certain use cases like internationalization: + +```bash +src/content/ + docs/ + # docs schema applies to all nested directories πŸ‘‡ + en/ + es/ + ... +``` + +All nested directories will share the same (optional) schema defined at the top level. Which brings us to... + +## Adding a schema + +Schemas are an optional way to enforce frontmatter types in a collection. To configure schemas, you can create a `src/content/config.{js|mjs|ts}` file. This file should: + +1. `export` a `collections` object, with each object key corresponding to the collection's folder name. We will offer a `defineCollection` utility similar to `defineConfig` in your `astro.config.*` today (see example below). +2. Use a [Zod object](https://github.com/colinhacks/zod#objects) to define schema properties. The `z` utility will be built-in and exposed by `astro:content`. + +For instance, say every `blog/` entry should have a `title`, `slug`, a list of `tags`, and an optional `image` url. We can specify each object property like so: + +```ts +// src/content/config.ts +import { z, defineCollection } from 'astro:content'; + +const blog = defineCollection({ + schema: { + title: z.string(), + slug: z.string(), + // mark optional properties with `.optional()` + image: z.string().optional(), + tags: z.array(z.string()), + }, +}); + +export const collections = { blog }; +``` + +You can also include dashes `-` in your collection name using a string as the key: + +```ts +const myNewsletter = defineCollection({...}); + +export const collections = { 'my-newsletter': myNewsletter }; +``` + +### Why Zod? + +We chose [Zod](https://github.com/colinhacks/zod) since it offers key benefits over plain TypeScript types. Namely: +- specifying default values for optional fields using `.default()` +- checking the *shape* of string values with built-in regexes, like `.url()` for URLs and `.email()` for emails + +```tsx +... +// "language" is optional, with a default value of english +language: z.enum(['es', 'de', 'en']).default('en'), +// allow email strings only. i.e. "jeff" would fail to parse, but "hey@blog.biz" would pass +authorContact: z.string().email(), +// allow url strings only. i.e. "/post" would fail, but `https://blog.biz/post` would pass +canonicalURL: z.string().url(), +``` + +You can [browse Zod's documentation](https://github.com/colinhacks/zod) for a complete rundown of features. + +## Fetching content + +Astro provides 2 functions to query collections: + +- `getCollection` - get all entries in a collection, or based on a filter +- `getEntry` - get a specific entry in a collection by file name + +These functions will have typed based on collections that exist. In other words, `getCollection('banana')` will raise a type error if there is no `src/content/banana/`. + +```tsx +--- +import { getCollection, getEntry } from 'astro:content'; +// Get all `blog` entries +const allBlogPosts = await getCollection('blog'); +// Filter blog posts by entry properties +const draftBlogPosts = await getCollection('blog', ({ id, slug, data }) => { + return data.status === 'draft'; +}); +// Get a specific blog post by file name +const enterprise = await getEntry('blog', 'enterprise.md'); +--- +``` + +### Return type + +Assume the `blog` collection schema looks like this: + +```tsx +// src/content/config.ts +import { defineCollection, z } from 'astro:content'; + +const blog = defineCollection({ + schema: { + title: z.string(), + slug: z.string(), + image: z.string().optional(), + tags: z.array(z.string()), + }, +}); + +export const collections = { blog }; +``` + +`await getCollection('blog')` will return entries of the following type: + +```tsx +{ + // parsed frontmatter + data: { + title: string; + slug: string; + image?: string; + tags: string[]; + }; + // unique identifier file path relative to src/content/[collection] + // example below would reflect the file names in your project + id: 'file-1.md' | 'file-2.md' | ...; + // URL-ready slug computed by stripping the file extension from `id` + slug: 'file-1' | 'file-2' | ...; + // raw body of the Markdown or MDX document + body: string; +} +``` + +:::note +The `body` is the *raw* content of the file. This ensures builds remain performant by avoiding expensive rendering pipelines. See [β€œMoving to `src/pages/`"](#mapping-to-srcpages) to understand how a `` component could be used to render this file, and pull in that pipeline only where necessary. +::: + +### Nested directories + +[As noted earlier](#nested-directories), you may organize entries into directories as well. The result will **still be a flat array** when fetching a collection via `getCollection`, with the nested directory reflected in an entry’s `id`: + +```tsx +const docsEntries = await getCollection('docs'); +console.log(docsEntries) +/* +-> [ + { id: 'en/getting-started.md', slug: 'en/getting-started', data: {...} }, + { id: 'en/structure.md', slug: 'en/structure', data: {...} }, + { id: 'es/getting-started.md', slug: 'es/getting-started', data: {...} }, + { id: 'es/structure.md', slug: 'es/structure', data: {...} }, + ... +] +*/ +``` + +This is in-keeping with our database table and CMS collection analogies. Directories are a way to organize your content, but do *not* effect the underlying, flat collection β†’ entry relationship. + +## Mapping to `src/pages/` + +We imagine users will want to map their collections onto live URLs on their site. This should be similar to globbing directories outside of `src/pages/` today, using `getStaticPaths` to generate routes dynamically. + +Say you have a `docs` collection subdivided by locale like so: + +```bash +src/content/ + docs/ + en/ + getting-started.md + ... + es/ + getting-started.md + ... +``` + +We want all `docs/` entries to be mapped onto pages, with those nested directories respected as nested URLs. We can do the following with `getStaticPaths`: + +```tsx +// src/pages/docs/[...slug].astro +import { getCollection } from 'astro:content'; + +export async function getStaticPaths() { + const blog = await getCollection('docs'); + return blog.map(entry => ({ + params: { slug: entry.slug }, + }); +} +``` + +This will generate routes for every entry in our collection, mapping each entry slug (a path relative to `src/content/docs`) to a URL. From d991b50f1fcf879dcc2e9453f503fc220d8b68ae Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Mon, 5 Dec 2022 16:42:22 -0500 Subject: [PATCH 003/125] new: finalize feature walkthrough, add landing pg example --- src/pages/en/guides/content-collections.md | 164 ++++++++++++++------- 1 file changed, 113 insertions(+), 51 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 1f72b364f863a..ad9d487462df3 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -16,36 +16,14 @@ Content collections help organize your Markdown or MDX and type-check your front - **Collection:** a set of data that share a common schema. In this case, Markdown and MDX files - **Entry:** A piece of data (Markdown or MDX file) belonging to a given collection -## The `src/content/` directory +## The content directory -This RFC introduces a new, reserved directory for Astro to manage: `{srcDir}/content/`. This directory is where all collections and schema definitions live, relative to your configured source directory. - -## The `.astro` cache directory - -Since we will preprocess your post frontmatter separate from Vite ([see background](#background)), we need a new home for generated metadata. This will be a special `.astro` directory **generated by Astro** at build time or on dev server startup. - -We expect `.astro` to live at the base of your project directory. This falls inline with generated directories like `.vscode` for editor tooling and `.vercel` for deployments. - -To clarify, **the user will not view or edit files in the `.astro` directory.** However, since it will live at the base of their project, they are free to check this generated directory into their repository. - -## The `astro:content` module - -Content Schemas introduces a new virtual module convention for Astro using the `astro:` prefix. Since all types and utilities are generated based on your content, we are free to use whatever name we choose. We chose `astro:` for this proposal since: -1. It falls in-line with [NodeJS' `node:` convention](https://2ality.com/2021/12/node-protocol-imports.html). -2. It leaves the door open for future `astro:` utility modules based on your project's configuration. - -The user will import helpers like `getCollection` and `getEntry` from `astro:content` like so: - -```tsx -import { getCollection, getEntry } from 'astro:content'; -``` - -Users can also expect full auto-importing and intellisense from their editor. +Content Collections introduce a new, reserved directory for Astro to manage: `{srcDir}/content/`. This directory is where all content collections and frontmatter schemas live. ## Creating a collection -All entries in `src/content/` **must** be nested in a "collection" directory. This allows you to get a collection of entries based on the directory name, and optionally enforce frontmatter types with a schema. This is similar to creating a new table in a database, or a new content model in a CMS like Contentful. +All entries in `{srcDir}/content/` **must** be nested in a "collection" directory. This allows you to retrieve a collection of entries based on the directory name, and optionally enforce frontmatter types with a schema. Think of collections like database tables or content types in a CMS. What this looks like in practice: @@ -63,9 +41,9 @@ src/content/ endeavour.md ``` -### Nested directories +### Organizing with nested directories -Collections are considered **one level deep**, so you cannot nest collections (or collection schemas) within other collections. However, we *will* allow nested directories to better organize your content. This is vital for certain use cases like internationalization: +Collections are considered **one level deep**, so you cannot nest collections (or collection schemas) within other collections. However, we do allow nested directories to better organize your content. This is vital for certain use cases like internationalization: ```bash src/content/ @@ -76,7 +54,9 @@ src/content/ ... ``` -All nested directories will share the same (optional) schema defined at the top level. Which brings us to... +All nested directories will share the same (optional) schema defined at the top level. + +See [getting from nested directories](#getting-from-nested-directories) to see how folders are treated when retrieving collections. ## Adding a schema @@ -104,7 +84,7 @@ const blog = defineCollection({ export const collections = { blog }; ``` -You can also include dashes `-` in your collection name using a string as the key: +You can also include dashes `-` in your collection name using a string as the key. For example, to configure the collection `src/content/my-newsletter`, you may do the following: ```ts const myNewsletter = defineCollection({...}); @@ -117,20 +97,27 @@ export const collections = { 'my-newsletter': myNewsletter }; We chose [Zod](https://github.com/colinhacks/zod) since it offers key benefits over plain TypeScript types. Namely: - specifying default values for optional fields using `.default()` - checking the *shape* of string values with built-in regexes, like `.url()` for URLs and `.email()` for emails +- transforming a frontmatter value into another value, like parsing a publish date to [a `Date` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date). -```tsx -... -// "language" is optional, with a default value of english -language: z.enum(['es', 'de', 'en']).default('en'), -// allow email strings only. i.e. "jeff" would fail to parse, but "hey@blog.biz" would pass -authorContact: z.string().email(), -// allow url strings only. i.e. "/post" would fail, but `https://blog.biz/post` would pass -canonicalURL: z.string().url(), +```ts +{ + // "language" is optional, with a default value of english + language: z.enum(['es', 'de', 'en']).default('en'), + // allow email strings only. + // ex. "jeff" would fail to parse, but "hey@blog.biz" would pass + authorContact: z.string().email(), + // allow url strings only. + // ex. "/post" would fail, but `https://blog.biz/post` would pass + canonicalURL: z.string().url(), + // parse publishDate as a browser-standard Date object + // ex. "Bananaday" would fail to parse, but "2022-10-10" would pass + publishDate: z.string().transform(str => new Date(str)), +} ``` You can [browse Zod's documentation](https://github.com/colinhacks/zod) for a complete rundown of features. -## Fetching content +## Getting content Astro provides 2 functions to query collections: @@ -139,7 +126,7 @@ Astro provides 2 functions to query collections: These functions will have typed based on collections that exist. In other words, `getCollection('banana')` will raise a type error if there is no `src/content/banana/`. -```tsx +```astro --- import { getCollection, getEntry } from 'astro:content'; // Get all `blog` entries @@ -157,7 +144,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); Assume the `blog` collection schema looks like this: -```tsx +```ts // src/content/config.ts import { defineCollection, z } from 'astro:content'; @@ -175,7 +162,7 @@ export const collections = { blog }; `await getCollection('blog')` will return entries of the following type: -```tsx +```ts { // parsed frontmatter data: { @@ -198,15 +185,15 @@ export const collections = { blog }; The `body` is the *raw* content of the file. This ensures builds remain performant by avoiding expensive rendering pipelines. See [β€œMoving to `src/pages/`"](#mapping-to-srcpages) to understand how a `` component could be used to render this file, and pull in that pipeline only where necessary. ::: -### Nested directories +### Getting from nested directories -[As noted earlier](#nested-directories), you may organize entries into directories as well. The result will **still be a flat array** when fetching a collection via `getCollection`, with the nested directory reflected in an entry’s `id`: +[As noted earlier](#organizing-with-nested-directories), you may organize entries into directories as well. The result will **still be a flat array** when getting a collection via `getCollection`, with the nested directory reflected in an entry’s `id`: -```tsx +```ts const docsEntries = await getCollection('docs'); console.log(docsEntries) /* --> [ +[ { id: 'en/getting-started.md', slug: 'en/getting-started', data: {...} }, { id: 'en/structure.md', slug: 'en/structure', data: {...} }, { id: 'es/getting-started.md', slug: 'es/getting-started', data: {...} }, @@ -216,11 +203,22 @@ console.log(docsEntries) */ ``` -This is in-keeping with our database table and CMS collection analogies. Directories are a way to organize your content, but do *not* effect the underlying, flat collection β†’ entry relationship. +To fetch from a specific directory **within** a collection, Astro recommends `getCollection` with a filter: -## Mapping to `src/pages/` +```astro +--- +import { getCollection } from 'astro:content'; -We imagine users will want to map their collections onto live URLs on their site. This should be similar to globbing directories outside of `src/pages/` today, using `getStaticPaths` to generate routes dynamically. +const enDocs = await getCollection('docs', ({ id }) => { + // Where `id` is 'en/page-1.md' | 'en/page-2.md' | ... + return id.startsWith('en'); +}); +--- +``` + +## Generate pages from content collections + +You might map content collections to live URLs on your site. This should be similar to globbing directories outside of `src/pages/`, [using `getStaticPaths` to generate routes dynamically.](/en/core-concepts/routing/#dynamic-routes) Say you have a `docs` collection subdivided by locale like so: @@ -235,7 +233,7 @@ src/content/ ... ``` -We want all `docs/` entries to be mapped onto pages, with those nested directories respected as nested URLs. We can do the following with `getStaticPaths`: +You may want all `docs/` entries to be mapped onto pages, with those nested directories respected as nested URLs. You can do the following with `getStaticPaths`: ```tsx // src/pages/docs/[...slug].astro @@ -244,9 +242,73 @@ import { getCollection } from 'astro:content'; export async function getStaticPaths() { const blog = await getCollection('docs'); return blog.map(entry => ({ + // Where `entry.slug` is `en/getting-started` | `es/getting-started` | ... params: { slug: entry.slug }, - }); + })); } ``` -This will generate routes for every entry in our collection, mapping each entry slug (a path relative to `src/content/docs`) to a URL. +This will generate routes for every entry in our collection, mapping each entry slug (a path relative to `src/content/docs/`) to a URL. This example will generate: +- `/docs/en/getting-started` +- `/docs/es/getting-started` + +...and so on. + +## Landing page example + +Say you're building a landing page for your collection of blog posts: + +```bash +src/content/ + blog/ + enterprise.md + columbia.md + endeavour.md +``` + +Each blog post has required and optional fields you'd like to type-check. You can add a `src/content/config.ts` file and configure the `blog` collection like so: + +```ts +// src/content/config.ts +import { z, defineCollection } from 'astro:content'; + +const blog = defineCollection({ + schema: { + title: z.string(), + slug: z.string(), + tags: z.array(z.string()), + status: z.enum(['draft', 'published']).default('draft'), + publishedDate: z.string().transform((str) => new Date(str)), + }, +}); + +export const collections = { blog }; +``` + +Now, you can use `getCollection` to retrieve type-safe frontmatter and slugs to use as links: + +```astro +--- +// src/pages/index.astro +import { getCollection, getEntry } from 'astro:content'; + +// Get all published blog posts +const blogPosts = await getCollection('blog', ({ data }) => { + return data.status === 'published'; +}); +--- + +
    + {allBlogPosts.map(post => ( +
  • + {/* Access frontmatter properties with `.data` */} + {post.data.title} + {/* Each property is type-safe, */} + {/* so expect nice autocomplete and red squiggles here! */} + +
  • + ))} +
+``` From b03445b23b29067a50a93118bbd08746b441e75b Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Mon, 5 Dec 2022 17:02:34 -0500 Subject: [PATCH 004/125] feat: add Rendering Content docs --- src/pages/en/guides/content-collections.md | 79 +++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ad9d487462df3..44eb793e5f7fc 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -216,7 +216,84 @@ const enDocs = await getCollection('docs', ({ id }) => { --- ``` -## Generate pages from content collections +## Rendering content with `renderEntry` + +You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)). + +You can retrieve a `Content` component for use in your Astro files with `renderEntry`: + +```astro +--- +const { getEntry } from 'astro:content'; + +const announcementPost = await getEntry('announcements', 'welcome.md'); +// Pass a `getEntry` result or `getCollection` array item: +const { Content } = await renderEntry(announcementPost); +// Or pass a valid ID and collection name individually: +const { Content } = await renderEntry({ + id: announcementPost.id, + collection: announcementPost.collection, +}); +--- + +

{announcementPost.data.title}

+ +``` + +This example will render the contents of `welcome.md`. + +### Access content headings + +Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `renderEntry`: + +```astro +--- +import { getCollection, renderEntry } from 'astro:content'; +const blogPosts = await getCollection('blog'); +--- + +{blogPosts.map(async (post) => { + const { + headings, // result of `getHeadings` + } = await renderEntry(post); + const { readingTime } = injectedFrontmatter; + const h1 = headings.find(h => h.depth === 1); + + return

{h1} - {readingTime} min read

+})} +``` + +### Access injected frontmatter + +Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `renderEntry`: + +```astro +--- +import { getCollection, renderEntry } from 'astro:content'; +const blogPosts = await getCollection('blog'); +--- + +{blogPosts.map(post => { + const { + injectedFrontmatter, // all properties injected via remark + } = renderEntry(post); + const { readingTime } = injectedFrontmatter; + const h1 = headings.find(h => h.depth === 1); + + return

{h1} - {readingTime} min read

+}) +``` + +Assuming `readingTime` was injected ([see our reading time example](/en/guides/markdown-content/#example-calculate-reading-time)), all properties should be available here. + +
+**πŸ™‹ Why don't `getCollection` and `getEntry` contain these values?** + +The remark and rehype pipelines are only run when your content is **rendered.** This lets `renderEntry` access anything generated by these plugins like injected frontmatter. To stay performant, `getCollection` and `getEntry` do not have this capability. + +
+ +## Generating pages from content collections You might map content collections to live URLs on your site. This should be similar to globbing directories outside of `src/pages/`, [using `getStaticPaths` to generate routes dynamically.](/en/core-concepts/routing/#dynamic-routes) From 55db44362784fc5d5e2b8cca88afb556570a30db Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 11:48:55 -0500 Subject: [PATCH 005/125] feat: add to nav --- src/i18n/en/nav.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/i18n/en/nav.ts b/src/i18n/en/nav.ts index 683cf0a5bf404..458e498eb4aca 100644 --- a/src/i18n/en/nav.ts +++ b/src/i18n/en/nav.ts @@ -62,6 +62,11 @@ export default [ key: 'guides/server-side-rendering', }, { text: 'Authoring Content', slug: 'guides/content', key: 'guides/content' }, + { + text: 'Content Collections (Experimental)', + slug: 'guides/content-collections', + key: 'guides/content-collections', + }, { text: 'Connecting a CMS', slug: 'guides/cms', key: 'guides/cms' }, { text: 'Images', slug: 'guides/images', key: 'guides/images' }, { text: 'Fonts', slug: 'guides/fonts', key: 'guides/fonts' }, From 1c57b9c8d65326b94fbdfd30ca5f8f5035ae9c9b Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 11:49:31 -0500 Subject: [PATCH 006/125] edit: nested directory and schema --- src/pages/en/guides/content-collections.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 44eb793e5f7fc..cc94987cd3c69 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -54,7 +54,7 @@ src/content/ ... ``` -All nested directories will share the same (optional) schema defined at the top level. +All nested directories will share the same schema defined for the top-level collection, if any (**docs** in this example). See [getting from nested directories](#getting-from-nested-directories) to see how folders are treated when retrieving collections. @@ -62,10 +62,10 @@ See [getting from nested directories](#getting-from-nested-directories) to see h Schemas are an optional way to enforce frontmatter types in a collection. To configure schemas, you can create a `src/content/config.{js|mjs|ts}` file. This file should: -1. `export` a `collections` object, with each object key corresponding to the collection's folder name. We will offer a `defineCollection` utility similar to `defineConfig` in your `astro.config.*` today (see example below). +1. `export` a `collections` object, with each object key corresponding to the collection's folder name. We will offer a `defineCollection` utility [similar to the `defineConfig` helper](/en/guides/configuring-astro/#the-astro-config-file) (see example below). 2. Use a [Zod object](https://github.com/colinhacks/zod#objects) to define schema properties. The `z` utility will be built-in and exposed by `astro:content`. -For instance, say every `blog/` entry should have a `title`, `slug`, a list of `tags`, and an optional `image` url. We can specify each object property like so: +For instance, say every `blog/` entry should have a `title`, `slug`, a list of `tags`, and an optional `image` url. We can specify each object property like so [using Zod functions](https://github.com/colinhacks/zod): ```ts // src/content/config.ts From 93bc3a286bcfa1a5ba877c90a8b024c595d3e40c Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 11:49:42 -0500 Subject: [PATCH 007/125] new: zod quick reference --- src/pages/en/guides/content-collections.md | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index cc94987cd3c69..0b5779dc03888 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -117,6 +117,36 @@ We chose [Zod](https://github.com/colinhacks/zod) since it offers key benefits o You can [browse Zod's documentation](https://github.com/colinhacks/zod) for a complete rundown of features. +### Zod quick reference + +YAML covers strings, booleans, numbers, objects, and arrays. Here's a quick cheatsheet for each of those: + +```ts +import { z, defineCollection } from 'astro:content'; + +defineCollection({ + schema: { + // Boolean + isDraft: z.boolean(), + // String + title: z.string(), + // Number + sortOrder: z.number(), + // Array - Note array(...) is a wrapper around the type each element + tags: z.array(z.string()), + // Enum - Pass array of exact values that are supported, of any type + language: z.enum(['en', 'es']), + // Object + image: z.object({ + src: z.string(), + alt: z.string(), + }), + } +}) +``` + +See the [**Why Zod?** example](#why-zod) above for Zod-specific features like defaults and transforms. + ## Getting content Astro provides 2 functions to query collections: From 292bc1db739f290d971307917ac821b6620782dc Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 11:51:16 -0500 Subject: [PATCH 008/125] edit: quick reference --- src/pages/en/guides/content-collections.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 0b5779dc03888..5b2ca56f30b2d 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -119,7 +119,7 @@ You can [browse Zod's documentation](https://github.com/colinhacks/zod) for a co ### Zod quick reference -YAML covers strings, booleans, numbers, objects, and arrays. Here's a quick cheatsheet for each of those: +Frontmatter YAML covers strings, booleans, numbers, objects, and arrays. Here's a quick cheatsheet for each of those: ```ts import { z, defineCollection } from 'astro:content'; @@ -132,9 +132,10 @@ defineCollection({ title: z.string(), // Number sortOrder: z.number(), - // Array - Note array(...) is a wrapper around the type each element + // Array + // Note: array(...) is a wrapper around the type each element (ex. array of strings) tags: z.array(z.string()), - // Enum - Pass array of exact values that are supported, of any type + // Enum language: z.enum(['en', 'es']), // Object image: z.object({ From dd70ad29dc6ab111c35d160222965019fc2cac4a Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 12:20:48 -0500 Subject: [PATCH 009/125] edit: better intro --- src/pages/en/guides/content-collections.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5b2ca56f30b2d..2c3735451dab2 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -6,12 +6,14 @@ i18nReady: false --- Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. You may reach for collections if you: -- Have a medium-to-large number of documents to manage and fetch (example: a blog with 50+ posts). -- Want to enforce frontmatter fields, and fail if fields are missing (example: every blog post should have a title and description). -- Plan to use content in multiple areas of your site (landing pages, footers, navigation, etc). +- **Have a medium-to-large number of documents** to manage and fetch (example: a blog with 50+ posts). +- **Want to enforce frontmatter fields,** and fail if fields are missing (example: every blog post should have a title and description). +- **Plan to use content in multiple areas** of your site (landing pages, footers, navigation, etc). ## Glossary +We'll be using "schema," "collection," and "entry" throughout this guide. Let's define these terms: + - **Schema:** a way to codify the "structure" of your data. In this case, frontmatter data - **Collection:** a set of data that share a common schema. In this case, Markdown and MDX files - **Entry:** A piece of data (Markdown or MDX file) belonging to a given collection From 70d7bf9343fb24f65a3ce183f296a9ddc197e123 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 12:21:08 -0500 Subject: [PATCH 010/125] edit: better Zod onboarding callouts --- src/pages/en/guides/content-collections.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 2c3735451dab2..3a4abdc377235 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -86,6 +86,10 @@ const blog = defineCollection({ export const collections = { blog }; ``` +:::tip +Browse the [**Zod quick reference**](#zod-quick-reference) for a rundown on the basics! +::: + You can also include dashes `-` in your collection name using a string as the key. For example, to configure the collection `src/content/my-newsletter`, you may do the following: ```ts @@ -134,8 +138,13 @@ defineCollection({ title: z.string(), // Number sortOrder: z.number(), + // Optional - Extend any type with `.optional()` + footnote: z.string().optional(), + // Default value - Extend any type with `.default(value)` + author: z.string().default('Anonymous'), // Array - // Note: array(...) is a wrapper around the type each element (ex. array of strings) + // Note: array(...) is a wrapper around the type of each element + // Ex. array of strings: tags: z.array(z.string()), // Enum language: z.enum(['en', 'es']), @@ -148,7 +157,7 @@ defineCollection({ }) ``` -See the [**Why Zod?** example](#why-zod) above for Zod-specific features like defaults and transforms. +See the [**Why Zod?** example](#why-zod) above for more Zod-specific features like transforms. ## Getting content From ac9e57e39539e00a946d4e9aeb6bd3ffab468d81 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 12:21:25 -0500 Subject: [PATCH 011/125] edit: clarify why rendering content is better than body --- src/pages/en/guides/content-collections.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 3a4abdc377235..5624abe111a0a 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -202,29 +202,31 @@ const blog = defineCollection({ export const collections = { blog }; ``` -`await getCollection('blog')` will return entries of the following type: +`await getCollection('blog')` will return entries of the following type, with the type of `data` inferred from your schema: ```ts { - // parsed frontmatter + // Unique ID using file path relative to src/content/[collection] + // Ex. for content/[collection]/file-1.md... + id: 'file-1.md' | 'file-2.md' | ...; + // URL-ready slug using ID with file extension stripped + // Ex. for content/[collection]/file-1.md... + slug: 'file-1' | 'file-2' | ...; + // Inferred from collection schema + // Defaults to `any` if no schema is configured data: { title: string; slug: string; image?: string; tags: string[]; }; - // unique identifier file path relative to src/content/[collection] - // example below would reflect the file names in your project - id: 'file-1.md' | 'file-2.md' | ...; - // URL-ready slug computed by stripping the file extension from `id` - slug: 'file-1' | 'file-2' | ...; - // raw body of the Markdown or MDX document + // Raw body of the Markdown or MDX document body: string; } ``` :::note -The `body` is the *raw* content of the file. This ensures builds remain performant by avoiding expensive rendering pipelines. See [β€œMoving to `src/pages/`"](#mapping-to-srcpages) to understand how a `` component could be used to render this file, and pull in that pipeline only where necessary. +The `body` is the *raw* content of the file. This ensures builds remain performant by avoiding expensive rendering pipelines. See [**Rendering content**](#rendering-content-with-renderentry) to compile this body to a `Content` component for use in your Astro files. ::: ### Getting from nested directories From 936233ee55ca6cf696189eee02574cad67c448c4 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 12:21:51 -0500 Subject: [PATCH 012/125] new: Rendering guide for pages --- src/pages/en/guides/content-collections.md | 86 +++++++++++++++++----- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5624abe111a0a..cbe7b46126198 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -266,9 +266,9 @@ You may need to render the contents of these Markdown and MDX entries as well. T You can retrieve a `Content` component for use in your Astro files with `renderEntry`: -```astro +```astro "renderEntry" --- -const { getEntry } from 'astro:content'; +import { renderEntry, getEntry } from 'astro:content'; const announcementPost = await getEntry('announcements', 'welcome.md'); // Pass a `getEntry` result or `getCollection` array item: @@ -284,26 +284,22 @@ const { Content } = await renderEntry({ ``` -This example will render the contents of `welcome.md`. +This example will render the contents of `content/announcements/welcome.md`. ### Access content headings Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `renderEntry`: -```astro +```astro "{ headings }" --- import { getCollection, renderEntry } from 'astro:content'; const blogPosts = await getCollection('blog'); --- {blogPosts.map(async (post) => { - const { - headings, // result of `getHeadings` - } = await renderEntry(post); - const { readingTime } = injectedFrontmatter; + const { headings } = await renderEntry(post); const h1 = headings.find(h => h.depth === 1); - - return

{h1} - {readingTime} min read

+ return

{h1}

})} ``` @@ -311,21 +307,17 @@ const blogPosts = await getCollection('blog'); Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `renderEntry`: -```astro +```astro "{ injectedFrontmatter }" --- import { getCollection, renderEntry } from 'astro:content'; const blogPosts = await getCollection('blog'); --- -{blogPosts.map(post => { - const { - injectedFrontmatter, // all properties injected via remark - } = renderEntry(post); +{blogPosts.map(async (post) => { + const { injectedFrontmatter } = await renderEntry(post); const { readingTime } = injectedFrontmatter; - const h1 = headings.find(h => h.depth === 1); - - return

{h1} - {readingTime} min read

-}) + return

{post.data.title} - {readingTime}

+})} ``` Assuming `readingTime` was injected ([see our reading time example](/en/guides/markdown-content/#example-calculate-reading-time)), all properties should be available here. @@ -356,17 +348,20 @@ src/content/ You may want all `docs/` entries to be mapped onto pages, with those nested directories respected as nested URLs. You can do the following with `getStaticPaths`: -```tsx +```astro "{ slug: entry.slug }" +--- // src/pages/docs/[...slug].astro import { getCollection } from 'astro:content'; export async function getStaticPaths() { const blog = await getCollection('docs'); + // Map collection entries to pages return blog.map(entry => ({ // Where `entry.slug` is `en/getting-started` | `es/getting-started` | ... params: { slug: entry.slug }, })); } +--- ``` This will generate routes for every entry in our collection, mapping each entry slug (a path relative to `src/content/docs/`) to a URL. This example will generate: @@ -375,6 +370,57 @@ This will generate routes for every entry in our collection, mapping each entry ...and so on. +### Rendering post contents + +You can pass each entry via `props` and use `renderEntry` to render its contents: + +```astro "renderEntry" "props: entry" +--- +// src/pages/docs/[...slug].astro +import { getCollection, renderEntry } from 'astro:content'; + +export async function getStaticPaths() { + const blog = await getCollection('docs'); + return blog.map(entry => ({ + // Pass blog entry as props + params: { slug: entry.slug, props: entry }, + })); +} + +const entry = Astro.props; +const { Content } = await renderEntry(entry); +--- + +

{entry.data.title}

+ +``` + +To add type safety, you can use the `CollectionEntry` utility: + +```astro ins={14} "CollectionEntry," +--- +// src/pages/docs/[...slug].astro +import { CollectionEntry, getCollection, renderEntry } from 'astro:content'; + +export async function getStaticPaths() { + const blog = await getCollection('docs'); + return blog.map(entry => ({ + // Pass blog entry as props + params: { slug: entry.slug, props: entry }, + })); +} + +// Get type of a `docs` entry +type Props = CollectionEntry<'docs'>; + +const entry = Astro.props; +const { Content } = await renderEntry(entry); +--- + +

{entry.data.title}

+ +``` + ## Landing page example Say you're building a landing page for your collection of blog posts: From 11a2901531f50ee5dc166797a1961ff1b87709d8 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 12:24:08 -0500 Subject: [PATCH 013/125] edit: highlight collection names --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index cbe7b46126198..93a4cfaadaaa2 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -29,10 +29,10 @@ All entries in `{srcDir}/content/` **must** be nested in a "collection" director What this looks like in practice: -```bash +```bash "newsletter/" "blog/" src/content/ # All newsletters have the same frontmatter properties - newsletters/ + newsletter/ week-1.md week-2.md week-3.md From 3f70af526ccc545d9944e68c72d79e41e9638005 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 6 Dec 2022 12:25:00 -0500 Subject: [PATCH 014/125] edit: remove unneeded optional comment --- src/pages/en/guides/content-collections.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 93a4cfaadaaa2..82443d0bac13a 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -77,7 +77,6 @@ const blog = defineCollection({ schema: { title: z.string(), slug: z.string(), - // mark optional properties with `.optional()` image: z.string().optional(), tags: z.array(z.string()), }, From 7c563300de2ec0bc0f5c6f79fd69a549cace042e Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Wed, 7 Dec 2022 08:51:52 -0500 Subject: [PATCH 015/125] edit: medium-to-large -> non-trivial --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 82443d0bac13a..026bd03a0517c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -6,9 +6,9 @@ i18nReady: false --- Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. You may reach for collections if you: -- **Have a medium-to-large number of documents** to manage and fetch (example: a blog with 50+ posts). -- **Want to enforce frontmatter fields,** and fail if fields are missing (example: every blog post should have a title and description). - **Plan to use content in multiple areas** of your site (landing pages, footers, navigation, etc). +- **Have a non-trivial number of documents** to manage and fetch (example: a blog with 50+ posts). +- **Want to enforce frontmatter fields,** and fail if fields are missing (example: every blog post should have a title and description). ## Glossary From dd34936074bfd6fe562da37cd49f27b8775b9ba0 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:48:40 -0500 Subject: [PATCH 016/125] srcDir -> src Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 026bd03a0517c..91254e7c13f31 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -20,7 +20,7 @@ We'll be using "schema," "collection," and "entry" throughout this guide. Let's ## The content directory -Content Collections introduce a new, reserved directory for Astro to manage: `{srcDir}/content/`. This directory is where all content collections and frontmatter schemas live. +Content Collections introduce a new, reserved directory that Astro will manage for you: `src/content/`. This directory is where all content collections and frontmatter schemas live. ## Creating a collection From 6a8418aaef42b0a549f71284ca932e5dd7d63504 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:48:57 -0500 Subject: [PATCH 017/125] edit: refine glossary Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 91254e7c13f31..2be3cc7c664ac 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -14,9 +14,9 @@ Content collections help organize your Markdown or MDX and type-check your front We'll be using "schema," "collection," and "entry" throughout this guide. Let's define these terms: -- **Schema:** a way to codify the "structure" of your data. In this case, frontmatter data -- **Collection:** a set of data that share a common schema. In this case, Markdown and MDX files -- **Entry:** A piece of data (Markdown or MDX file) belonging to a given collection +- **Schema:** the shape and type you expect your data to have. In this case, frontmatter data. +- **Collection:** a set of data that share a common schema. In this case, a set of Markdown and MDX files. +- **Entry:** A piece of data belonging to a given collection. In this case, a single Markdown or MDX file. ## The content directory From a393479ebffef3cb342d59196453b4428385627e Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:49:46 -0500 Subject: [PATCH 018/125] edit: tweak CMS and database comparison Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 2be3cc7c664ac..1cbb3fa8253b1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -25,7 +25,7 @@ Content Collections introduce a new, reserved directory that Astro will manage f ## Creating a collection -All entries in `{srcDir}/content/` **must** be nested in a "collection" directory. This allows you to retrieve a collection of entries based on the directory name, and optionally enforce frontmatter types with a schema. Think of collections like database tables or content types in a CMS. +All entries in `src/content/` **must** be nested in a "collection" directory. This allows you to retrieve a collection of entries based on the directory name, and optionally enforce frontmatter types with a schema. In this way, collections are a bit like database tables or content types in a CMS: they help you group similar kinds of content together. What this looks like in practice: From 33d0162f4ebec013a68594349c230b0ed7e259f1 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:50:04 -0500 Subject: [PATCH 019/125] adding -> defining a collection Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 1cbb3fa8253b1..4deee5cce377b 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -60,7 +60,7 @@ All nested directories will share the same schema defined for the top-level coll See [getting from nested directories](#getting-from-nested-directories) to see how folders are treated when retrieving collections. -## Adding a schema +## Defining a collection schema Schemas are an optional way to enforce frontmatter types in a collection. To configure schemas, you can create a `src/content/config.{js|mjs|ts}` file. This file should: From 854ea85a41916bc09f57f2f5ed0097942b1dcf71 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:50:58 -0500 Subject: [PATCH 020/125] edit: render example lead-in Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 4deee5cce377b..9c325f0b11e24 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -263,7 +263,7 @@ const enDocs = await getCollection('docs', ({ id }) => { You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)). -You can retrieve a `Content` component for use in your Astro files with `renderEntry`: +You can retrieve a `` component for use in your Astro files with `renderEntry`. For example, this page will render the contents of `content/announcements/welcome.md`: ```astro "renderEntry" --- From 64a0d23f9cf6b094830a0ce0845710a018f7c4e1 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:51:22 -0500 Subject: [PATCH 021/125] edit: injectedFrontmatter destructure clarity Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 9c325f0b11e24..7c8463f3ce250 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -314,8 +314,7 @@ const blogPosts = await getCollection('blog'); {blogPosts.map(async (post) => { const { injectedFrontmatter } = await renderEntry(post); - const { readingTime } = injectedFrontmatter; - return

{post.data.title} - {readingTime}

+ return

{post.data.title} β€” {injectedFrontmatter.readingTime}

})} ``` From 235b0d74d90662b20573013550ae01026ebc803e Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:53:06 -0500 Subject: [PATCH 022/125] edit: add filename to render entry example Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 7c8463f3ce250..2083c7b6a939a 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -267,6 +267,7 @@ You can retrieve a `` component for use in your Astro files with `ren ```astro "renderEntry" --- +// src/pages/welcome-announcement.astro import { renderEntry, getEntry } from 'astro:content'; const announcementPost = await getEntry('announcements', 'welcome.md'); From b7345780abb092d614a73be7a85f9258c5b57f66 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:53:56 -0500 Subject: [PATCH 023/125] edit: tweak readingTime wording Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 2083c7b6a939a..44f63a52aa928 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -319,7 +319,7 @@ const blogPosts = await getCollection('blog'); })} ``` -Assuming `readingTime` was injected ([see our reading time example](/en/guides/markdown-content/#example-calculate-reading-time)), all properties should be available here. +Assuming `readingTime` was injected ([see our reading time example](/en/guides/markdown-content/#example-calculate-reading-time)), it will be available on the `injectedFrontmatter` object.
**πŸ™‹ Why don't `getCollection` and `getEntry` contain these values?** From 67f4eef86e861413281bd5ba9b77e351a187a2ac Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:54:59 -0500 Subject: [PATCH 024/125] edit: simplify schema example Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 44f63a52aa928..7b4601b378f7b 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -67,7 +67,7 @@ Schemas are an optional way to enforce frontmatter types in a collection. To con 1. `export` a `collections` object, with each object key corresponding to the collection's folder name. We will offer a `defineCollection` utility [similar to the `defineConfig` helper](/en/guides/configuring-astro/#the-astro-config-file) (see example below). 2. Use a [Zod object](https://github.com/colinhacks/zod#objects) to define schema properties. The `z` utility will be built-in and exposed by `astro:content`. -For instance, say every `blog/` entry should have a `title`, `slug`, a list of `tags`, and an optional `image` url. We can specify each object property like so [using Zod functions](https://github.com/colinhacks/zod): +For example, if every `blog/` entry should have a `title`, list of `tags`, and an optional `image` URL, we can specify each expected property [using Zod functions](https://github.com/colinhacks/zod): ```ts // src/content/config.ts @@ -76,7 +76,6 @@ import { z, defineCollection } from 'astro:content'; const blog = defineCollection({ schema: { title: z.string(), - slug: z.string(), image: z.string().optional(), tags: z.array(z.string()), }, From 0ba83926db9acbd450b7646a31d72f9be96b5ff9 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:55:52 -0500 Subject: [PATCH 025/125] edit: refine collection-with-dashes ex Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 7b4601b378f7b..98d7705eb41f9 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -88,12 +88,12 @@ export const collections = { blog }; Browse the [**Zod quick reference**](#zod-quick-reference) for a rundown on the basics! ::: -You can also include dashes `-` in your collection name using a string as the key. For example, to configure the collection `src/content/my-newsletter`, you may do the following: +If your collection directory contains hyphens or dashes, make sure you wrap the name in quotes when defining your collections. For example, to configure the collection `src/content/my-newsletter`, you may do the following: -```ts -const myNewsletter = defineCollection({...}); - -export const collections = { 'my-newsletter': myNewsletter }; +```js "'my-newsletter'" +export const collections = { + 'my-newsletter': defineCollection({...}), +}; ``` ### Why Zod? From 1be56c7462ce1a4d3139c91a3f7ede909a2365b3 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:58:47 -0500 Subject: [PATCH 026/125] Frontmatter YAML -> Markdown and MDX Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 98d7705eb41f9..e0c109883c92d 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -123,7 +123,7 @@ You can [browse Zod's documentation](https://github.com/colinhacks/zod) for a co ### Zod quick reference -Frontmatter YAML covers strings, booleans, numbers, objects, and arrays. Here's a quick cheatsheet for each of those: +Markdown and MDX frontmatter can contain strings, booleans, numbers, objects, and arrays. Here's a quick cheatsheet for each of those: ```ts import { z, defineCollection } from 'astro:content'; From e80784991ea725559119bd5636a94d1135cd1804 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:59:23 -0500 Subject: [PATCH 027/125] edit: apparently my dashes aren't cool enough Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index e0c109883c92d..08c4a49fcc444 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -161,8 +161,8 @@ See the [**Why Zod?** example](#why-zod) above for more Zod-specific features li Astro provides 2 functions to query collections: -- `getCollection` - get all entries in a collection, or based on a filter -- `getEntry` - get a specific entry in a collection by file name +- `getCollection` β€” get all entries in a collection, or based on a filter +- `getEntry` β€” get a specific entry in a collection by file name These functions will have typed based on collections that exist. In other words, `getCollection('banana')` will raise a type error if there is no `src/content/banana/`. From 14bf26575ede2e75eb34f1f98608103ce781829e Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 14:59:48 -0500 Subject: [PATCH 028/125] edit: wording on getCollection types Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 08c4a49fcc444..b2310d8f7cebc 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -164,7 +164,7 @@ Astro provides 2 functions to query collections: - `getCollection` β€” get all entries in a collection, or based on a filter - `getEntry` β€” get a specific entry in a collection by file name -These functions will have typed based on collections that exist. In other words, `getCollection('banana')` will raise a type error if there is no `src/content/banana/`. +These functions will be typed based on collections that exist. For example, `getCollection('banana')` will raise a type error if there is no `src/content/banana/`. ```astro --- From 650e3829319dca2251f511c2690ffa4212aca029 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 15:00:15 -0500 Subject: [PATCH 029/125] edit: blog -> src/content/blog Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index b2310d8f7cebc..29bf5ae4105e4 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -169,7 +169,7 @@ These functions will be typed based on collections that exist. For example, `get ```astro --- import { getCollection, getEntry } from 'astro:content'; -// Get all `blog` entries +// Get all `src/content/blog/` entries const allBlogPosts = await getCollection('blog'); // Filter blog posts by entry properties const draftBlogPosts = await getCollection('blog', ({ id, slug, data }) => { From 6e04f2e9a67802898295494feb6bed2516a4dce8 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 15:01:11 -0500 Subject: [PATCH 030/125] edit: better directory return type explanation Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 29bf5ae4105e4..0485703751581 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -229,7 +229,7 @@ The `body` is the *raw* content of the file. This ensures builds remain performa ### Getting from nested directories -[As noted earlier](#organizing-with-nested-directories), you may organize entries into directories as well. The result will **still be a flat array** when getting a collection via `getCollection`, with the nested directory reflected in an entry’s `id`: +When getting a collection that includes files in nested directories, the result will be a flat array of entries. The nested directory structure will be reflected in each entry’s `id`. ```ts const docsEntries = await getCollection('docs'); From 3fd410383f3b78d2965dc67a80bad1713f3d6202 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 15:02:06 -0500 Subject: [PATCH 031/125] nit: indents Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 0485703751581..919bb141bcd5a 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -236,11 +236,11 @@ const docsEntries = await getCollection('docs'); console.log(docsEntries) /* [ - { id: 'en/getting-started.md', slug: 'en/getting-started', data: {...} }, - { id: 'en/structure.md', slug: 'en/structure', data: {...} }, - { id: 'es/getting-started.md', slug: 'es/getting-started', data: {...} }, - { id: 'es/structure.md', slug: 'es/structure', data: {...} }, - ... + { id: 'en/getting-started.md', slug: 'en/getting-started', data: {...} }, + { id: 'en/structure.md', slug: 'en/structure', data: {...} }, + { id: 'es/getting-started.md', slug: 'es/getting-started', data: {...} }, + { id: 'es/structure.md', slug: 'es/structure', data: {...} }, + ... ] */ ``` From f281d84cf2ce4e5c2b53931030f7f0b861930d43 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 15:02:30 -0500 Subject: [PATCH 032/125] edit: subdirectory lead-in Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 919bb141bcd5a..c61299fa422c1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -245,7 +245,7 @@ console.log(docsEntries) */ ``` -To fetch from a specific directory **within** a collection, Astro recommends `getCollection` with a filter: +To fetch from a subdirectory within a collection, you can use `getCollection` with a filter: ```astro --- From 509934ad34da790bebb7cdddf8dff5d4a124b72c Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 15:02:57 -0500 Subject: [PATCH 033/125] edit: en -> en/ Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index c61299fa422c1..4f0db07729a69 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -253,7 +253,7 @@ import { getCollection } from 'astro:content'; const enDocs = await getCollection('docs', ({ id }) => { // Where `id` is 'en/page-1.md' | 'en/page-2.md' | ... - return id.startsWith('en'); + return id.startsWith('en/'); }); --- ``` From b7d60bf668293066a234cdc744a6e399432232d4 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 22:04:41 -0500 Subject: [PATCH 034/125] edit: better file tree Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 4f0db07729a69..0e7893f6af5ee 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -335,13 +335,11 @@ Say you have a `docs` collection subdivided by locale like so: ```bash src/content/ - docs/ - en/ - getting-started.md - ... - es/ - getting-started.md - ... +└── docs/ + β”œβ”€β”€ en/ + β”‚ └── getting-started.md + └── es/ + └── getting-started.md ``` You may want all `docs/` entries to be mapped onto pages, with those nested directories respected as nested URLs. You can do the following with `getStaticPaths`: From cd3d0716c82a907362de811642a39dde7e2ac343 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 22:05:34 -0500 Subject: [PATCH 035/125] edit: remove dup file name Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 0e7893f6af5ee..05303a17700f0 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -283,8 +283,6 @@ const { Content } = await renderEntry({ ``` -This example will render the contents of `content/announcements/welcome.md`. - ### Access content headings Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `renderEntry`: From dc56c5c4e3e3a49341d86e74b298c5d20e7a6283 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 22:05:56 -0500 Subject: [PATCH 036/125] edit: better filetree on collections example Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 05303a17700f0..a07bb375c4bc2 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -31,16 +31,16 @@ What this looks like in practice: ```bash "newsletter/" "blog/" src/content/ - # All newsletters have the same frontmatter properties - newsletter/ - week-1.md - week-2.md - week-3.md - # All blog posts have the same frontmatter properties - blog/ - columbia.md - enterprise.md - endeavour.md +β”‚ # All blog posts have the same frontmatter properties +β”œβ”€β”€ blog/ +β”‚ β”œβ”€β”€ columbia.md +β”‚ β”œβ”€β”€ endeavour.md +β”‚ └── enterprise.md +β”‚ # All newsletters have the same frontmatter properties +└── newsletter/ + β”œβ”€β”€ week-1.md + β”œβ”€β”€ week-2.md + └── week-3.md ``` ### Organizing with nested directories From 98cf0926cc0ff019257de3e6dd49542373d9e346 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 22:06:51 -0500 Subject: [PATCH 037/125] edit: filetree for docs schema Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index a07bb375c4bc2..6b08442b68e43 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -49,11 +49,11 @@ Collections are considered **one level deep**, so you cannot nest collections (o ```bash src/content/ - docs/ - # docs schema applies to all nested directories πŸ‘‡ - en/ - es/ - ... +└── docs/ + β”‚ # docs schema applies to all nested directories πŸ‘‡ + β”œβ”€β”€ en/ + β”œβ”€β”€ es/ + └── ... ``` All nested directories will share the same schema defined for the top-level collection, if any (**docs** in this example). From 6fafee31e865ef40378443a38440a093577b9a8f Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 7 Dec 2022 22:13:41 -0500 Subject: [PATCH 038/125] edit: refine dynamic route section Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 6b08442b68e43..d5041911e45b1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -327,7 +327,7 @@ The remark and rehype pipelines are only run when your content is **rendered.** ## Generating pages from content collections -You might map content collections to live URLs on your site. This should be similar to globbing directories outside of `src/pages/`, [using `getStaticPaths` to generate routes dynamically.](/en/core-concepts/routing/#dynamic-routes) +You can create pages based on your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes). Use `getCollection()` inside your [`getStaticPaths()`](https://docs.astro.build/en/reference/api-reference/#getstaticpaths) function to build routes based on your collections. If you have used `Astro.glob()` to generate a dynamic route before, this might feel familiar. Say you have a `docs` collection subdivided by locale like so: From 43a2b715cf566733f2f9371e5f37be7455addbd3 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Thu, 8 Dec 2022 20:45:35 -0500 Subject: [PATCH 039/125] edit: there's always a hippo watching over us Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index d5041911e45b1..60920de003956 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -327,7 +327,7 @@ The remark and rehype pipelines are only run when your content is **rendered.** ## Generating pages from content collections -You can create pages based on your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes). Use `getCollection()` inside your [`getStaticPaths()`](https://docs.astro.build/en/reference/api-reference/#getstaticpaths) function to build routes based on your collections. If you have used `Astro.glob()` to generate a dynamic route before, this might feel familiar. +You can create pages based on your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes). Use `getCollection()` inside your [`getStaticPaths()`](/en/reference/api-reference/#getstaticpaths) function to build routes based on your collections. If you have used `Astro.glob()` to generate a dynamic route before, this might feel familiar. Say you have a `docs` collection subdivided by locale like so: From aa5b091ba9a5d5f24d84ea5f0b8c3ae4db7278d2 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Thu, 8 Dec 2022 20:47:51 -0500 Subject: [PATCH 040/125] edit: more context on props -> renderEntry Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 60920de003956..748201d221474 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -366,7 +366,7 @@ This will generate routes for every entry in our collection, mapping each entry ### Rendering post contents -You can pass each entry via `props` and use `renderEntry` to render its contents: +When generating pages with a dynamic route, you can pass each collection entry via `props` in your `getStaticPaths()` function. You can then retrieve the entry from `Astro.props` and use `renderEntry` to render its contents: ```astro "renderEntry" "props: entry" --- From 8d31687dd0e8c34852808ced5b0ce99a967afbea Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Thu, 8 Dec 2022 20:49:09 -0500 Subject: [PATCH 041/125] edit: pass entry as prop key Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 748201d221474..a430c593ed02b 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -374,14 +374,14 @@ When generating pages with a dynamic route, you can pass each collection entry v import { getCollection, renderEntry } from 'astro:content'; export async function getStaticPaths() { - const blog = await getCollection('docs'); - return blog.map(entry => ({ - // Pass blog entry as props - params: { slug: entry.slug, props: entry }, - })); + const blog = await getCollection('blog'); + return blog.map(entry => ({ + // Pass blog entry via props + params: { slug: entry.slug, props: { entry } }, + })); } -const entry = Astro.props; +const { entry } = Astro.props; const { Content } = await renderEntry(entry); --- From bcb3567386138f9d11e368173cf59fadb5b3a5ce Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 20:43:31 -0500 Subject: [PATCH 042/125] edit: getting from -> querying --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index a430c593ed02b..b429b091c6ccc 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -227,7 +227,7 @@ export const collections = { blog }; The `body` is the *raw* content of the file. This ensures builds remain performant by avoiding expensive rendering pipelines. See [**Rendering content**](#rendering-content-with-renderentry) to compile this body to a `Content` component for use in your Astro files. ::: -### Getting from nested directories +### Querying nested content directories When getting a collection that includes files in nested directories, the result will be a flat array of entries. The nested directory structure will be reflected in each entry’s `id`. From 194795f24a37bc09ac7a03456c63fb932e4f2980 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 20:46:12 -0500 Subject: [PATCH 043/125] nit: empty line before list --- src/pages/en/guides/content-collections.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index b429b091c6ccc..95872055dea10 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -6,6 +6,7 @@ i18nReady: false --- Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. You may reach for collections if you: + - **Plan to use content in multiple areas** of your site (landing pages, footers, navigation, etc). - **Have a non-trivial number of documents** to manage and fetch (example: a blog with 50+ posts). - **Want to enforce frontmatter fields,** and fail if fields are missing (example: every blog post should have a title and description). From 67052a6ab640cd97e190cc3613b0a41da4daa667 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 20:51:18 -0500 Subject: [PATCH 044/125] nit: trailing newline --- src/pages/en/guides/content-collections.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 95872055dea10..e54d23d6532ae 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -23,7 +23,6 @@ We'll be using "schema," "collection," and "entry" throughout this guide. Let's Content Collections introduce a new, reserved directory that Astro will manage for you: `src/content/`. This directory is where all content collections and frontmatter schemas live. - ## Creating a collection All entries in `src/content/` **must** be nested in a "collection" directory. This allows you to retrieve a collection of entries based on the directory name, and optionally enforce frontmatter types with a schema. In this way, collections are a bit like database tables or content types in a CMS: they help you group similar kinds of content together. From b493c8a04a75dcccd9790b3a44ba2679d56babab Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 20:55:01 -0500 Subject: [PATCH 045/125] edit: move type example into other example --- src/pages/en/guides/content-collections.md | 37 +++++----------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index e54d23d6532ae..d231357786a8c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -370,44 +370,23 @@ When generating pages with a dynamic route, you can pass each collection entry v ```astro "renderEntry" "props: entry" --- -// src/pages/docs/[...slug].astro -import { getCollection, renderEntry } from 'astro:content'; +// src/pages/blog/[...slug].astro +import { getCollection, renderEntry, CollectionEntry } from 'astro:content'; export async function getStaticPaths() { - const blog = await getCollection('blog'); - return blog.map(entry => ({ + const docs = await getCollection('docs'); + return docs.map(entry => ({ // Pass blog entry via props params: { slug: entry.slug, props: { entry } }, })); } -const { entry } = Astro.props; -const { Content } = await renderEntry(entry); ---- - -

{entry.data.title}

- -``` - -To add type safety, you can use the `CollectionEntry` utility: - -```astro ins={14} "CollectionEntry," ---- -// src/pages/docs/[...slug].astro -import { CollectionEntry, getCollection, renderEntry } from 'astro:content'; - -export async function getStaticPaths() { - const blog = await getCollection('docs'); - return blog.map(entry => ({ - // Pass blog entry as props - params: { slug: entry.slug, props: entry }, - })); +interface Props { + // Optionally use `CollectionEntry` for type safety + entry: CollectionEntry<'docs'>; } -// Get type of a `docs` entry -type Props = CollectionEntry<'docs'>; - -const entry = Astro.props; +const { entry } = Astro.props; const { Content } = await renderEntry(entry); --- From 01819fe24ba3edb81c89d485d1f8eb8b53741b01 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 20:55:24 -0500 Subject: [PATCH 046/125] edit: getting -> querying --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index d231357786a8c..82fa71d4dad35 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -157,7 +157,7 @@ defineCollection({ See the [**Why Zod?** example](#why-zod) above for more Zod-specific features like transforms. -## Getting content +## Querying content collections Astro provides 2 functions to query collections: From c8bb5dafc1af96febb2019212e360c1bcda14967 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Thu, 8 Dec 2022 21:02:44 -0500 Subject: [PATCH 047/125] edit: Markdown TM Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 82fa71d4dad35..10932265e7368 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -7,7 +7,7 @@ i18nReady: false Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. You may reach for collections if you: -- **Plan to use content in multiple areas** of your site (landing pages, footers, navigation, etc). +- **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc). - **Have a non-trivial number of documents** to manage and fetch (example: a blog with 50+ posts). - **Want to enforce frontmatter fields,** and fail if fields are missing (example: every blog post should have a title and description). From a53bab5b71486caa5ab5c1f5f374d57eec2f1a79 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:05:40 -0500 Subject: [PATCH 048/125] edit: Sarah lead-in edits --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 10932265e7368..ecd0157e22940 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -5,11 +5,11 @@ description: Content collections help organize your Markdown and type-check your i18nReady: false --- -Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. You may reach for collections if you: +Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. Collections may be helpful if you: - **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc). - **Have a non-trivial number of documents** to manage and fetch (example: a blog with 50+ posts). -- **Want to enforce frontmatter fields,** and fail if fields are missing (example: every blog post should have a title and description). +- **Want Astro to enforce frontmatter fields,** and fail if fields are missing (e.g. every blog post should have a title and description). ## Glossary From 5b55a4ff96745c9f0438be6b17d8f1ab4b18710b Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:05:52 -0500 Subject: [PATCH 049/125] edit: better schema config explainer --- src/pages/en/guides/content-collections.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ecd0157e22940..87aae910ee454 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -62,10 +62,12 @@ See [getting from nested directories](#getting-from-nested-directories) to see h ## Defining a collection schema -Schemas are an optional way to enforce frontmatter types in a collection. To configure schemas, you can create a `src/content/config.{js|mjs|ts}` file. This file should: +Schemas are an optional way to enforce frontmatter types in a collection. Astro uses [Zod](https://github.com/colinhacks/zod) to validate your frontmatter with schemas as [Zod objects](https://github.com/colinhacks/zod#objects). -1. `export` a `collections` object, with each object key corresponding to the collection's folder name. We will offer a `defineCollection` utility [similar to the `defineConfig` helper](/en/guides/configuring-astro/#the-astro-config-file) (see example below). -2. Use a [Zod object](https://github.com/colinhacks/zod#objects) to define schema properties. The `z` utility will be built-in and exposed by `astro:content`. +To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file should: + +1. Export a `collections` object, with each object key corresponding to the collection's folder name. +2. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection. For example, if every `blog/` entry should have a `title`, list of `tags`, and an optional `image` URL, we can specify each expected property [using Zod functions](https://github.com/colinhacks/zod): From 11fec3c4243386dd3e8b79f5bc43a5f323558f7d Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:07:02 -0500 Subject: [PATCH 050/125] edit: remove renderEntry individual args ex --- src/pages/en/guides/content-collections.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 87aae910ee454..beb2fe9974558 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -272,13 +272,7 @@ You can retrieve a `` component for use in your Astro files with `ren import { renderEntry, getEntry } from 'astro:content'; const announcementPost = await getEntry('announcements', 'welcome.md'); -// Pass a `getEntry` result or `getCollection` array item: const { Content } = await renderEntry(announcementPost); -// Or pass a valid ID and collection name individually: -const { Content } = await renderEntry({ - id: announcementPost.id, - collection: announcementPost.collection, -}); ---

{announcementPost.data.title}

From e8934a741d221d1336c7e2c8f074c56d1b78138c Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:18:50 -0500 Subject: [PATCH 051/125] edit: tweak return type for review --- src/pages/en/guides/content-collections.md | 34 +++++++++++++++------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index beb2fe9974558..ebecd525a8628 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -184,7 +184,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); ### Return type -Assume the `blog` collection schema looks like this: +Assume you have a `blog` collection with the following `schema`: ```ts // src/content/config.ts @@ -193,7 +193,6 @@ import { defineCollection, z } from 'astro:content'; const blog = defineCollection({ schema: { title: z.string(), - slug: z.string(), image: z.string().optional(), tags: z.array(z.string()), }, @@ -206,20 +205,18 @@ export const collections = { blog }; ```ts { - // Unique ID using file path relative to src/content/[collection] - // Ex. for content/[collection]/file-1.md... - id: 'file-1.md' | 'file-2.md' | ...; - // URL-ready slug using ID with file extension stripped - // Ex. for content/[collection]/file-1.md... - slug: 'file-1' | 'file-2' | ...; - // Inferred from collection schema // Defaults to `any` if no schema is configured data: { title: string; - slug: string; image?: string; tags: string[]; }; + // Unique ID using file path relative to src/content/[collection] + // Ex. for content/[collection]/file-1.md... + id: 'file-1.md' | 'file-2.md' | ...; + // URL-ready slug using ID with file extension stripped + // Ex. for content/[collection]/file-1.md... + slug: 'file-1' | 'file-2' | ...; // Raw body of the Markdown or MDX document body: string; } @@ -260,6 +257,23 @@ const enDocs = await getCollection('docs', ({ id }) => { --- ``` +### Collection entry types + +If a page or component uses content from a `getCollection()` or `getEntry()` query, you can use the `CollectionEntry` utility to type its props: + +```astro /CollectionEntry[(<.+>)?]/ +--- +// src/components/BlogCard.astro +import type { CollectionEntry } from 'astro:content'; +interface Props { + // Get type of a `blog` collection entry + post: CollectionEntry<'blog'>; +} +// `post.data` will match your collection schema +const { post } = Astro.props; +--- +``` + ## Rendering content with `renderEntry` You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)). From 148fe9a4a23323b7818a3a7abadaad1d330d63f4 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Thu, 8 Dec 2022 21:20:34 -0500 Subject: [PATCH 052/125] edit: fine I'll remove the lead-in I spent 15 min debating Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ebecd525a8628..5f81185ab87fb 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -13,7 +13,6 @@ Content collections help organize your Markdown or MDX and type-check your front ## Glossary -We'll be using "schema," "collection," and "entry" throughout this guide. Let's define these terms: - **Schema:** the shape and type you expect your data to have. In this case, frontmatter data. - **Collection:** a set of data that share a common schema. In this case, a set of Markdown and MDX files. From e71465cf8f28fbc77cc7603bda4a525b2cbd06a4 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:22:54 -0500 Subject: [PATCH 053/125] edit: org nested dir redraft --- src/pages/en/guides/content-collections.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ebecd525a8628..2a347c027bb4c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -45,7 +45,8 @@ src/content/ ### Organizing with nested directories -Collections are considered **one level deep**, so you cannot nest collections (or collection schemas) within other collections. However, we do allow nested directories to better organize your content. This is vital for certain use cases like internationalization: +Collections are **top-level folders** within `src/content`. You cannot nest collections, but you may use nested directories within a collection to better organize a collection's content. All nested directories will share the same schema defined for the top-level collection. +For example, you can use this structure for internationalization: ```bash src/content/ @@ -58,7 +59,7 @@ src/content/ All nested directories will share the same schema defined for the top-level collection, if any (**docs** in this example). -See [getting from nested directories](#getting-from-nested-directories) to see how folders are treated when retrieving collections. +See [querying nested directories](#querying-nested-content-directories) to see how folders are treated when retrieving collections. ## Defining a collection schema From 5a3f4e1689db9982a2c8707a78af6caed6476c3d Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:28:28 -0500 Subject: [PATCH 054/125] edit: without a glossary or emojis I'm a shallow husk of a docs writer --- src/pages/en/guides/content-collections.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 2bb2235a09807..9bc59a10e5b1c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -11,13 +11,6 @@ Content collections help organize your Markdown or MDX and type-check your front - **Have a non-trivial number of documents** to manage and fetch (example: a blog with 50+ posts). - **Want Astro to enforce frontmatter fields,** and fail if fields are missing (e.g. every blog post should have a title and description). -## Glossary - - -- **Schema:** the shape and type you expect your data to have. In this case, frontmatter data. -- **Collection:** a set of data that share a common schema. In this case, a set of Markdown and MDX files. -- **Entry:** A piece of data belonging to a given collection. In this case, a single Markdown or MDX file. - ## The content directory Content Collections introduce a new, reserved directory that Astro will manage for you: `src/content/`. This directory is where all content collections and frontmatter schemas live. From 8b5f3a98deb5854fe485d5bcab3e97b354dd0e77 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:33:19 -0500 Subject: [PATCH 055/125] edit: work glossary into content dir section --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 9bc59a10e5b1c..78cbc1f9823d7 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -13,7 +13,7 @@ Content collections help organize your Markdown or MDX and type-check your front ## The content directory -Content Collections introduce a new, reserved directory that Astro will manage for you: `src/content/`. This directory is where all content collections and frontmatter schemas live. +Astro provides a reserved directory for Markdown content, `src/content/`. This is where **collections** (folders) of Markdown/MDX **entries** (files) can be stored, with a single configuration file to define each collection's **schema** (frontmatter data types and shape). ## Creating a collection From cc7abca5f103d0196800e86adf9eef9e4f0883a1 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:50:51 -0500 Subject: [PATCH 056/125] edit: truncate dashes col name example --- src/pages/en/guides/content-collections.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 78cbc1f9823d7..0cc163cbbea5a 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -62,13 +62,13 @@ To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file 1. Export a `collections` object, with each object key corresponding to the collection's folder name. 2. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection. -For example, if every `blog/` entry should have a `title`, list of `tags`, and an optional `image` URL, we can specify each expected property [using Zod functions](https://github.com/colinhacks/zod): +For example, if every `engineering-blog/` entry should have a `title`, list of `tags`, and an optional `image` URL, you can specify each expected property [using Zod functions](https://github.com/colinhacks/zod): ```ts // src/content/config.ts import { z, defineCollection } from 'astro:content'; -const blog = defineCollection({ +const engineeringBlog = defineCollection({ schema: { title: z.string(), image: z.string().optional(), @@ -76,18 +76,9 @@ const blog = defineCollection({ }, }); -export const collections = { blog }; -``` - -:::tip -Browse the [**Zod quick reference**](#zod-quick-reference) for a rundown on the basics! -::: - -If your collection directory contains hyphens or dashes, make sure you wrap the name in quotes when defining your collections. For example, to configure the collection `src/content/my-newsletter`, you may do the following: - -```js "'my-newsletter'" export const collections = { - 'my-newsletter': defineCollection({...}), + // Don't forget 'quotes' for object keys containing dashes + 'engineering-blog': engineeringBlog, }; ``` From 1b92643235bf59ccb83ed26e7f663b8e710f35e7 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 8 Dec 2022 21:58:45 -0500 Subject: [PATCH 057/125] edit: break out collection functions to headings --- src/pages/en/guides/content-collections.md | 27 +++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 0cc163cbbea5a..115d016df3ce0 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -147,21 +147,32 @@ See the [**Why Zod?** example](#why-zod) above for more Zod-specific features li Astro provides 2 functions to query collections: -- `getCollection` β€” get all entries in a collection, or based on a filter -- `getEntry` β€” get a specific entry in a collection by file name +### `getCollection()` -These functions will be typed based on collections that exist. For example, `getCollection('banana')` will raise a type error if there is no `src/content/banana/`. +`getCollection()` returns multiple entries in a collection. It requires the name of a `collection` as a parameter. By default, it returns all items in the collection. + +It can also take a second, optional parameter: a filter function based on schema properties. This allows you to query for only some items in a collection based on `id`, `slug`, or frontmatter values via the `data` object. ```astro --- -import { getCollection, getEntry } from 'astro:content'; +import { getCollection } from 'astro:content'; // Get all `src/content/blog/` entries const allBlogPosts = await getCollection('blog'); -// Filter blog posts by entry properties -const draftBlogPosts = await getCollection('blog', ({ id, slug, data }) => { - return data.status === 'draft'; +// Only return posts with `draft: true` in the frontmatter +const draftBlogPosts = await getCollection('blog', ({ data }) => { + return data.draft === true; }); -// Get a specific blog post by file name +--- +``` + +### `getEntry()` + +`getEntry()` is function that returns a specific entry in a collection by entry ID (file path relative to the collection). Both of these are required parameters. + +```astro +--- +import { getEntry } from 'astro:content'; + const enterprise = await getEntry('blog', 'enterprise.md'); --- ``` From a2d657cfea759899b3e22d22bf5c043096f1043f Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 08:55:30 -0500 Subject: [PATCH 058/125] nit: example -> eg --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 115d016df3ce0..e5c6532d61d2f 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -8,7 +8,7 @@ i18nReady: false Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. Collections may be helpful if you: - **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc). -- **Have a non-trivial number of documents** to manage and fetch (example: a blog with 50+ posts). +- **Have a non-trivial number of documents** to manage and fetch (e.g. a blog with 50+ posts). - **Want Astro to enforce frontmatter fields,** and fail if fields are missing (e.g. every blog post should have a title and description). ## The content directory From 634df1650522274adaddcdcead5a5afc9db8492e Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 09:08:11 -0500 Subject: [PATCH 059/125] edit: refine generating pages example --- src/pages/en/guides/content-collections.md | 38 ++++++++-------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index e5c6532d61d2f..d07364353683a 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -332,42 +332,32 @@ The remark and rehype pipelines are only run when your content is **rendered.** ## Generating pages from content collections -You can create pages based on your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes). Use `getCollection()` inside your [`getStaticPaths()`](/en/reference/api-reference/#getstaticpaths) function to build routes based on your collections. If you have used `Astro.glob()` to generate a dynamic route before, this might feel familiar. +You can create pages from your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes). -Say you have a `docs` collection subdivided by locale like so: - -```bash -src/content/ -└── docs/ - β”œβ”€β”€ en/ - β”‚ └── getting-started.md - └── es/ - └── getting-started.md -``` - -You may want all `docs/` entries to be mapped onto pages, with those nested directories respected as nested URLs. You can do the following with `getStaticPaths`: +Say you have a `src/content/blog/` collection, and you want to map these entries to `/posts/*` URLs. You can create a `posts/[...slug].astro` route using `getStaticPaths` like so: ```astro "{ slug: entry.slug }" --- -// src/pages/docs/[...slug].astro +// src/pages/posts/[...slug].astro import { getCollection } from 'astro:content'; - export async function getStaticPaths() { - const blog = await getCollection('docs'); + const blog = await getCollection('blog'); // Map collection entries to pages - return blog.map(entry => ({ - // Where `entry.slug` is `en/getting-started` | `es/getting-started` | ... - params: { slug: entry.slug }, - })); + return blog.map(entry => ({ + // `entry.slug` is the filename of each blog post with `.md` removed + params: { slug: entry.slug }, + })); } --- ``` -This will generate routes for every entry in our collection, mapping each entry slug (a path relative to `src/content/docs/`) to a URL. This example will generate: -- `/docs/en/getting-started` -- `/docs/es/getting-started` +This will generate routes for every entry in our collection, mapping each entry’s slug to a URL. For example, an entry at `src/content/blog/hello-world.md` will have a slug of `hello-world`. Because this dynamic route is in `src/pages/posts/`, the final URL will be `/posts/hello-world`. + +### Generating pages with nested directories + +If you have a collection with [nested directories](#organizing-with-nested-directories) (e.g. when organising your content by locale) this will be reflected in each entry’s `slug`. For example, the collection entry `blog/en/intro.md` will have a slug of `en/intro`. -...and so on. +Using [rest parameters in your dynamic routes](/en/core-concepts/routing/#rest-parameters) like in the example above supports mapping nested slugs out-of-the-box. ### Rendering post contents From 56333d3dbdb825d3da529419332e85a27cf769d3 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 09:22:29 -0500 Subject: [PATCH 060/125] edit: redraft why zod sections --- src/pages/en/guides/content-collections.md | 64 ++++++++-------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index d07364353683a..476f4a3033b1c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -82,66 +82,50 @@ export const collections = { }; ``` -### Why Zod? +### Schema data types with Zod -We chose [Zod](https://github.com/colinhacks/zod) since it offers key benefits over plain TypeScript types. Namely: -- specifying default values for optional fields using `.default()` -- checking the *shape* of string values with built-in regexes, like `.url()` for URLs and `.email()` for emails -- transforming a frontmatter value into another value, like parsing a publish date to [a `Date` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date). +Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. Each frontmatter property must be listed in your schema object along with its data type. -```ts -{ - // "language" is optional, with a default value of english - language: z.enum(['es', 'de', 'en']).default('en'), - // allow email strings only. - // ex. "jeff" would fail to parse, but "hey@blog.biz" would pass - authorContact: z.string().email(), - // allow url strings only. - // ex. "/post" would fail, but `https://blog.biz/post` would pass - canonicalURL: z.string().url(), - // parse publishDate as a browser-standard Date object - // ex. "Bananaday" would fail to parse, but "2022-10-10" would pass - publishDate: z.string().transform(str => new Date(str)), -} -``` +You can extend any of these types with `.optional() (make property optional) or `.defaultValue(value)` (set a default value). You can also specify a set of allowable values for a frontmatter property using `enum`. -You can [browse Zod's documentation](https://github.com/colinhacks/zod) for a complete rundown of features. - -### Zod quick reference - -Markdown and MDX frontmatter can contain strings, booleans, numbers, objects, and arrays. Here's a quick cheatsheet for each of those: +The following schema illustrates each of these data types in use: ```ts import { z, defineCollection } from 'astro:content'; defineCollection({ schema: { - // Boolean isDraft: z.boolean(), - // String title: z.string(), - // Number sortOrder: z.number(), - // Optional - Extend any type with `.optional()` - footnote: z.string().optional(), - // Default value - Extend any type with `.default(value)` - author: z.string().default('Anonymous'), - // Array - // Note: array(...) is a wrapper around the type of each element - // Ex. array of strings: - tags: z.array(z.string()), - // Enum - language: z.enum(['en', 'es']), - // Object image: z.object({ src: z.string(), alt: z.string(), }), + tags: z.array(z.string()), // An array of strings + footnote: z.string().optional(), + author: z.string().default('Anonymous'), + language: z.enum(['en', 'es']), } }) ``` -See the [**Why Zod?** example](#why-zod) above for more Zod-specific features like transforms. +### Advanced schema features + +You can use all of Zod’s properties and methods with content schemas. This includes transforming a frontmatter value into another value, checking the shape of string values with built-in regexes, and more. + +```ts +{ + // Allow only strings representing email addresses + authorContact: z.string().email(), + // Allow URL strings only (e.g. `https://example.com`) + canonicalURL: z.string().url(), + // Parse publishDate as a browser-standard `Date` object + publishDate: z.string().transform(str => new Date(str)), +} +``` + +See [Zod’s documentation](https://github.com/colinhacks/zod) for a complete list of features. ## Querying content collections From 16e94cd822f4eb1cc26466b6667d7d2f1d4c7f7a Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 09:30:21 -0500 Subject: [PATCH 061/125] edit: reorder `defineCollection` instructions --- src/pages/en/guides/content-collections.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 476f4a3033b1c..83d8ea7ce3c3b 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -59,10 +59,10 @@ Schemas are an optional way to enforce frontmatter types in a collection. Astro To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file should: -1. Export a `collections` object, with each object key corresponding to the collection's folder name. -2. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection. +1. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection. +2. Export a `collections` object, with each object key corresponding to the collection's folder name. -For example, if every `engineering-blog/` entry should have a `title`, list of `tags`, and an optional `image` URL, you can specify each expected property [using Zod functions](https://github.com/colinhacks/zod): +For example, say you have a `src/content/engineering-blog` collection, where every entry should have a `title`, list of `tags`, and an optional `image` URL. You can specify each expected property [using Zod](https://github.com/colinhacks/zod): ```ts // src/content/config.ts From de6de686ad6f9091d7effed240b88c2a495614db Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 09:42:56 -0500 Subject: [PATCH 062/125] edit: return type -> data returned example --- src/pages/en/guides/content-collections.md | 96 +++++++++++----------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 83d8ea7ce3c3b..f9a49ccc4d640 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -161,80 +161,78 @@ const enterprise = await getEntry('blog', 'enterprise.md'); --- ``` -### Return type +### Data returned from a collections query -Assume you have a `blog` collection with the following `schema`: +`getCollection()` and `getEntry()` will return entries that include: + - `id` - a unique ID using the file path relative to `src/content/[collection]` + - `slug` - a URL-ready slug. Defaults to the ID without the file extension. + - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. + - `body` - a string containing the raw body of the Markdown or MDX document. + +#### Landing page example + +Given the following collection: + +```bash +src/content/ +β”œβ”€β”€ blog/ + β”œβ”€β”€ columbia.md + β”œβ”€β”€ endeavour.md + └── enterprise.md +``` +...and the following schema: ```ts // src/content/config.ts -import { defineCollection, z } from 'astro:content'; - +import { z, defineCollection } from 'astro:content'; const blog = defineCollection({ schema: { title: z.string(), - image: z.string().optional(), + slug: z.string(), tags: z.array(z.string()), + status: z.enum(['draft', 'published']).default('draft'), + publishedDate: z.string().transform((str) => new Date(str)), }, }); - export const collections = { blog }; ``` -`await getCollection('blog')` will return entries of the following type, with the type of `data` inferred from your schema: - -```ts -{ - // Defaults to `any` if no schema is configured - data: { - title: string; - image?: string; - tags: string[]; - }; - // Unique ID using file path relative to src/content/[collection] - // Ex. for content/[collection]/file-1.md... - id: 'file-1.md' | 'file-2.md' | ...; - // URL-ready slug using ID with file extension stripped - // Ex. for content/[collection]/file-1.md... - slug: 'file-1' | 'file-2' | ...; - // Raw body of the Markdown or MDX document - body: string; -} -``` +You can use `getCollection()` on an index page to retrieve each post's type-safe frontmatter and a `slug` to use for links: -:::note -The `body` is the *raw* content of the file. This ensures builds remain performant by avoiding expensive rendering pipelines. See [**Rendering content**](#rendering-content-with-renderentry) to compile this body to a `Content` component for use in your Astro files. -::: - -### Querying nested content directories - -When getting a collection that includes files in nested directories, the result will be a flat array of entries. The nested directory structure will be reflected in each entry’s `id`. +```astro +--- +// src/pages/index.astro +import { getCollection } from 'astro:content'; -```ts -const docsEntries = await getCollection('docs'); -console.log(docsEntries) -/* -[ - { id: 'en/getting-started.md', slug: 'en/getting-started', data: {...} }, - { id: 'en/structure.md', slug: 'en/structure', data: {...} }, - { id: 'es/getting-started.md', slug: 'es/getting-started', data: {...} }, - { id: 'es/structure.md', slug: 'es/structure', data: {...} }, - ... -] -*/ +// Get all published blog posts +const blogPosts = await getCollection('blog', ({ data }) => { + return data.status === 'published'; +}); +--- +
    + {allBlogPosts.map(post => ( +
  • + {post.data.title} + +
  • + ))} +
``` -To fetch from a subdirectory within a collection, you can use `getCollection` with a filter: +:::tip +Add a filtering function to `getCollections()` to return a subset of a collection's entries. For example, to fetch an entire subdirectory within a collection: ```astro --- import { getCollection } from 'astro:content'; - const enDocs = await getCollection('docs', ({ id }) => { - // Where `id` is 'en/page-1.md' | 'en/page-2.md' | ... return id.startsWith('en/'); }); --- ``` +::: ### Collection entry types @@ -244,10 +242,12 @@ If a page or component uses content from a `getCollection()` or `getEntry()` que --- // src/components/BlogCard.astro import type { CollectionEntry } from 'astro:content'; + interface Props { // Get type of a `blog` collection entry post: CollectionEntry<'blog'>; } + // `post.data` will match your collection schema const { post } = Astro.props; --- From 066092f49b8086511457358bab04e999a80ed0d9 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 09:43:35 -0500 Subject: [PATCH 063/125] edit: remove landing page example at end --- src/pages/en/guides/content-collections.md | 59 ---------------------- 1 file changed, 59 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index f9a49ccc4d640..46b90b70db12b 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -372,62 +372,3 @@ const { Content } = await renderEntry(entry);

{entry.data.title}

``` - -## Landing page example - -Say you're building a landing page for your collection of blog posts: - -```bash -src/content/ - blog/ - enterprise.md - columbia.md - endeavour.md -``` - -Each blog post has required and optional fields you'd like to type-check. You can add a `src/content/config.ts` file and configure the `blog` collection like so: - -```ts -// src/content/config.ts -import { z, defineCollection } from 'astro:content'; - -const blog = defineCollection({ - schema: { - title: z.string(), - slug: z.string(), - tags: z.array(z.string()), - status: z.enum(['draft', 'published']).default('draft'), - publishedDate: z.string().transform((str) => new Date(str)), - }, -}); - -export const collections = { blog }; -``` - -Now, you can use `getCollection` to retrieve type-safe frontmatter and slugs to use as links: - -```astro ---- -// src/pages/index.astro -import { getCollection, getEntry } from 'astro:content'; - -// Get all published blog posts -const blogPosts = await getCollection('blog', ({ data }) => { - return data.status === 'published'; -}); ---- - -
    - {allBlogPosts.map(post => ( -
  • - {/* Access frontmatter properties with `.data` */} - {post.data.title} - {/* Each property is type-safe, */} - {/* so expect nice autocomplete and red squiggles here! */} - -
  • - ))} -
-``` From 3149f64449963107b0e7c233f344b88731e5c8d6 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 09:50:07 -0500 Subject: [PATCH 064/125] edit: redraft Collections --- src/pages/en/guides/content-collections.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 46b90b70db12b..83830a7fbdfac 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -15,11 +15,15 @@ Content collections help organize your Markdown or MDX and type-check your front Astro provides a reserved directory for Markdown content, `src/content/`. This is where **collections** (folders) of Markdown/MDX **entries** (files) can be stored, with a single configuration file to define each collection's **schema** (frontmatter data types and shape). -## Creating a collection +## Collections -All entries in `src/content/` **must** be nested in a "collection" directory. This allows you to retrieve a collection of entries based on the directory name, and optionally enforce frontmatter types with a schema. In this way, collections are a bit like database tables or content types in a CMS: they help you group similar kinds of content together. +A collection is folder containing Markdown or MDX files whose frontmatter all share the same data shape and types. -What this looks like in practice: +Astro [provides built-in functions](#querying-content-collections) for querying your content data files by collection directory name. This means every content file in `src/content/` **must** belong to a collection directory. + +With this organization, you can retrieve a set of entries based on the collection name, and optionally enforce frontmatter types with a schema. + +To create a new collection, add a new directory to `src/content/`, and add Markdown or MDX entries that share frontmatter properties. The following example shows two collections: `blog` and `newsletter`. ```bash "newsletter/" "blog/" src/content/ From b2bfc8314c1165ef4c0f9a94af0104a45075add9 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 09:52:14 -0500 Subject: [PATCH 065/125] edit: add homepage preview example to rendering content --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 83830a7fbdfac..800e595bed04c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -257,9 +257,9 @@ const { post } = Astro.props; --- ``` -## Rendering content with `renderEntry` +## Rendering content -You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)). +You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), or adding post previews to your homepage. You can retrieve a `` component for use in your Astro files with `renderEntry`. For example, this page will render the contents of `content/announcements/welcome.md`: From 4e43f02dda8c6c4bf8154fe1c8b02678dcc54b71 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 10:02:40 -0500 Subject: [PATCH 066/125] edit: remove dead querying nested dirs link --- src/pages/en/guides/content-collections.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 800e595bed04c..5cbb318383b5d 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -55,8 +55,6 @@ src/content/ All nested directories will share the same schema defined for the top-level collection, if any (**docs** in this example). -See [querying nested directories](#querying-nested-content-directories) to see how folders are treated when retrieving collections. - ## Defining a collection schema Schemas are an optional way to enforce frontmatter types in a collection. Astro uses [Zod](https://github.com/colinhacks/zod) to validate your frontmatter with schemas as [Zod objects](https://github.com/colinhacks/zod#objects). From e495936c4dcc8e1aeb053157254c05762179b2ca Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 10:03:10 -0500 Subject: [PATCH 067/125] edit: remove redundant link --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5cbb318383b5d..049e16eefccaa 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -64,7 +64,7 @@ To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file 1. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection. 2. Export a `collections` object, with each object key corresponding to the collection's folder name. -For example, say you have a `src/content/engineering-blog` collection, where every entry should have a `title`, list of `tags`, and an optional `image` URL. You can specify each expected property [using Zod](https://github.com/colinhacks/zod): +For example, say you have a `src/content/engineering-blog` collection, where every entry should have a `title`, list of `tags`, and an optional `image` URL. You can specify each expected property like so: ```ts // src/content/config.ts From e929b03e8fb3ededeaf2c5dca469a14910c29df2 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 10:03:34 -0500 Subject: [PATCH 068/125] edit: object keys -> collection names --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 049e16eefccaa..c8363da2105f9 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -79,7 +79,7 @@ const engineeringBlog = defineCollection({ }); export const collections = { - // Don't forget 'quotes' for object keys containing dashes + // Don't forget 'quotes' for collection names containing dashes 'engineering-blog': engineeringBlog, }; ``` From 957dbf2e952fb9c2295613e061f05f1bf8fc1eed Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 10:03:54 -0500 Subject: [PATCH 069/125] fix: broken code comment --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index c8363da2105f9..13d2ac40d2970 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -88,7 +88,7 @@ export const collections = { Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. Each frontmatter property must be listed in your schema object along with its data type. -You can extend any of these types with `.optional() (make property optional) or `.defaultValue(value)` (set a default value). You can also specify a set of allowable values for a frontmatter property using `enum`. +You can extend any of these types with `.optional()` (make property optional) or `.defaultValue(value)` (set a default value). You can also specify a set of allowable values for a frontmatter property using `enum`. The following schema illustrates each of these data types in use: From 74ebdf847282aebe6f5a57d44930dc1015844b5c Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Fri, 9 Dec 2022 10:05:03 -0500 Subject: [PATCH 070/125] edit: landing page ex tweak --- src/pages/en/guides/content-collections.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 13d2ac40d2970..40f64b34fa160 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -171,7 +171,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - `body` - a string containing the raw body of the Markdown or MDX document. -#### Landing page example +### Landing page example Given the following collection: @@ -190,7 +190,6 @@ import { z, defineCollection } from 'astro:content'; const blog = defineCollection({ schema: { title: z.string(), - slug: z.string(), tags: z.array(z.string()), status: z.enum(['draft', 'published']).default('draft'), publishedDate: z.string().transform((str) => new Date(str)), From 5d9c06f5a5efe02ff8a71e0a70402e5ad0d63ca1 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Sat, 10 Dec 2022 13:56:18 -0500 Subject: [PATCH 071/125] edit: 2 -> two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Moritz StΓΌckler --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 40f64b34fa160..1aa66d9ce06c1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -131,7 +131,7 @@ See [Zod’s documentation](https://github.com/colinhacks/zod) for a complete li ## Querying content collections -Astro provides 2 functions to query collections: +Astro provides two functions to query collections: ### `getCollection()` From 6e25027928beff025d7f2d9a7719e5b2c3cdd1cd Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Sat, 10 Dec 2022 13:56:32 -0500 Subject: [PATCH 072/125] edit: rogue space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Moritz StΓΌckler --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 1aa66d9ce06c1..8f0b302341cfd 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -166,7 +166,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); ### Data returned from a collections query `getCollection()` and `getEntry()` will return entries that include: - - `id` - a unique ID using the file path relative to `src/content/[collection]` + - `id` - a unique ID using the file path relative to `src/content/[collection]` - `slug` - a URL-ready slug. Defaults to the ID without the file extension. - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - `body` - a string containing the raw body of the Markdown or MDX document. From 43c63d4d78e0f48b9d77660dfefe56e410d4d40a Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Sat, 10 Dec 2022 13:56:47 -0500 Subject: [PATCH 073/125] edit: no fancy apostrophes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Moritz StΓΌckler --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 8f0b302341cfd..ee7aaf72d3ad1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -336,7 +336,7 @@ export async function getStaticPaths() { --- ``` -This will generate routes for every entry in our collection, mapping each entry’s slug to a URL. For example, an entry at `src/content/blog/hello-world.md` will have a slug of `hello-world`. Because this dynamic route is in `src/pages/posts/`, the final URL will be `/posts/hello-world`. +This will generate routes for every entry in our collection, mapping each entry's slug to a URL. For example, an entry at `src/content/blog/hello-world.md` will have a slug of `hello-world`. Because this dynamic route is in `src/pages/posts/`, the final URL will be `/posts/hello-world`. ### Generating pages with nested directories From 556228c05d3af300871153de0fead1cb90a17ea0 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Sat, 10 Dec 2022 13:56:57 -0500 Subject: [PATCH 074/125] edit: no fancy apostrophes 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Moritz StΓΌckler --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ee7aaf72d3ad1..67aca87e651f1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -340,7 +340,7 @@ This will generate routes for every entry in our collection, mapping each entry' ### Generating pages with nested directories -If you have a collection with [nested directories](#organizing-with-nested-directories) (e.g. when organising your content by locale) this will be reflected in each entry’s `slug`. For example, the collection entry `blog/en/intro.md` will have a slug of `en/intro`. +If you have a collection with [nested directories](#organizing-with-nested-directories) (e.g. when organising your content by locale) this will be reflected in each entry's `slug`. For example, the collection entry `blog/en/intro.md` will have a slug of `en/intro`. Using [rest parameters in your dynamic routes](/en/core-concepts/routing/#rest-parameters) like in the example above supports mapping nested slugs out-of-the-box. From 649bd0b3220a6116ab30607a6d03ca4e96901ff3 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Sat, 10 Dec 2022 13:57:18 -0500 Subject: [PATCH 075/125] edit: include Zod for better SEO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Moritz StΓΌckler --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 67aca87e651f1..db0762ce19c83 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -86,7 +86,7 @@ export const collections = { ### Schema data types with Zod -Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. Each frontmatter property must be listed in your schema object along with its data type. +Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. Each frontmatter property must be listed in your schema object along with its data type. To define and validate this schema, we use a library called [zod](https://github.com/colinhacks/zod), which is available via the `z` import. You can extend any of these types with `.optional()` (make property optional) or `.defaultValue(value)` (set a default value). You can also specify a set of allowable values for a frontmatter property using `enum`. From 2159de011ea7d0795dcec9a637ca20d3ee4e3abf Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:17:03 -0500 Subject: [PATCH 076/125] edit: reserved directory -> special Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index db0762ce19c83..2d9d9c53cbc97 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -13,7 +13,7 @@ Content collections help organize your Markdown or MDX and type-check your front ## The content directory -Astro provides a reserved directory for Markdown content, `src/content/`. This is where **collections** (folders) of Markdown/MDX **entries** (files) can be stored, with a single configuration file to define each collection's **schema** (frontmatter data types and shape). +Astro treats the `src/content/` directory as special. This is where **collections** (folders) of Markdown/MDX **entries** (files) can be stored, with a single configuration file to define each collection's **schema** (frontmatter data types and shape). Files other than your `.md`/`.mdx` content are not permitted inside `src/content/`. ## Collections From f60eca121ec54d6ca007cbdae3ede06f6fdb2802 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:17:23 -0500 Subject: [PATCH 077/125] edit: remove `data` Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 2d9d9c53cbc97..5ba59319d9dd6 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -19,7 +19,7 @@ Astro treats the `src/content/` directory as special. This is where **collection A collection is folder containing Markdown or MDX files whose frontmatter all share the same data shape and types. -Astro [provides built-in functions](#querying-content-collections) for querying your content data files by collection directory name. This means every content file in `src/content/` **must** belong to a collection directory. +Astro [provides built-in functions](#querying-content-collections) for querying your content files by collection directory name. This means every content file in `src/content/` **must** belong to a collection directory. With this organization, you can retrieve a set of entries based on the collection name, and optionally enforce frontmatter types with a schema. From 083269eace876320b5b3cd327a7920bf30252155 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 13 Dec 2022 13:24:23 -0500 Subject: [PATCH 078/125] edit: refine collections lead-in --- src/pages/en/guides/content-collections.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5ba59319d9dd6..5b0a9ae47a91d 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -17,11 +17,9 @@ Astro treats the `src/content/` directory as special. This is where **collection ## Collections -A collection is folder containing Markdown or MDX files whose frontmatter all share the same data shape and types. +A collection is a directory in `src/content/` containing Markdown or MDX fields. Every Markdown or MDX file in `src/content/` **must** belong to a collection directory, since Astro [provides built-in functions](#querying-content-collections) for querying your content by the collection directory name. -Astro [provides built-in functions](#querying-content-collections) for querying your content files by collection directory name. This means every content file in `src/content/` **must** belong to a collection directory. - -With this organization, you can retrieve a set of entries based on the collection name, and optionally enforce frontmatter types with a schema. +As a best practice, content within a collection should share the same frontmatter shape and types. You can optionally enforce these types [by configuring a schema](/en/guides/content-collections/#defining-a-collection-schema). To create a new collection, add a new directory to `src/content/`, and add Markdown or MDX entries that share frontmatter properties. The following example shows two collections: `blog` and `newsletter`. From 57f39ee2b4be7c292e02b51b3dd54c08238cb03a Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:25:10 -0500 Subject: [PATCH 079/125] nit: `renderEntry()` Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5b0a9ae47a91d..ce1c4e3c83170 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -256,7 +256,7 @@ const { post } = Astro.props; You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), or adding post previews to your homepage. -You can retrieve a `` component for use in your Astro files with `renderEntry`. For example, this page will render the contents of `content/announcements/welcome.md`: +You can retrieve a `` component for use in your Astro files with `renderEntry()`. For example, this page will render the contents of `content/announcements/welcome.md`: ```astro "renderEntry" --- From 20215c4c5b253bb1ba5a3dc84e952bb4cb0718a3 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 13 Dec 2022 13:27:07 -0500 Subject: [PATCH 080/125] edit: have a growing number... --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ce1c4e3c83170..52ffc8d2fc4c3 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -8,7 +8,7 @@ i18nReady: false Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. Collections may be helpful if you: - **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc). -- **Have a non-trivial number of documents** to manage and fetch (e.g. a blog with 50+ posts). +- **Have a growing number of documents** to manage and fetch (e.g. a blog with 20+ posts). - **Want Astro to enforce frontmatter fields,** and fail if fields are missing (e.g. every blog post should have a title and description). ## The content directory From 32b98d1f32d63136f77aeb95a6a6891e232f745e Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:28:07 -0500 Subject: [PATCH 081/125] edit: new but also not new collection lead-in Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 52ffc8d2fc4c3..e4bdc67443977 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -21,7 +21,7 @@ A collection is a directory in `src/content/` containing Markdown or MDX fields. As a best practice, content within a collection should share the same frontmatter shape and types. You can optionally enforce these types [by configuring a schema](/en/guides/content-collections/#defining-a-collection-schema). -To create a new collection, add a new directory to `src/content/`, and add Markdown or MDX entries that share frontmatter properties. The following example shows two collections: `blog` and `newsletter`. +To create a collection, add a new directory to `src/content/`. Then, add Markdown or MDX entries that share frontmatter properties. The following example shows two collections: `blog` and `newsletter`. ```bash "newsletter/" "blog/" src/content/ From 77c09b3311ec7b8dad8e2c27a05a9c37336b0525 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:28:31 -0500 Subject: [PATCH 082/125] edit: undead URLs are pages right? Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index e4bdc67443977..71b908d7bbe1f 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -254,7 +254,7 @@ const { post } = Astro.props; ## Rendering content -You may need to render the contents of these Markdown and MDX entries as well. This is especially useful when generating live URLs from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), or adding post previews to your homepage. +You may need to render the contents of your Markdown and MDX entries as well. This is especially useful when generating pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), or adding post previews to your homepage. You can retrieve a `` component for use in your Astro files with `renderEntry()`. For example, this page will render the contents of `content/announcements/welcome.md`: From fecca4c34fa14ef1e998ee731c79430fc8d4dcd8 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:28:53 -0500 Subject: [PATCH 083/125] edit: that's a wee bit bri'ish innit Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 71b908d7bbe1f..b143d88f19249 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -338,7 +338,7 @@ This will generate routes for every entry in our collection, mapping each entry' ### Generating pages with nested directories -If you have a collection with [nested directories](#organizing-with-nested-directories) (e.g. when organising your content by locale) this will be reflected in each entry's `slug`. For example, the collection entry `blog/en/intro.md` will have a slug of `en/intro`. +If you have a collection with [nested directories](#organizing-with-nested-directories) (e.g. when organizing your content by locale) this will be reflected in each entry's `slug`. For example, the collection entry `blog/en/intro.md` will have a slug of `en/intro`. Using [rest parameters in your dynamic routes](/en/core-concepts/routing/#rest-parameters) like in the example above supports mapping nested slugs out-of-the-box. From c446fe74aea42286a42ef89c559f40a90ff577f4 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 13 Dec 2022 13:30:56 -0500 Subject: [PATCH 084/125] edit: remove superfluous file tree --- src/pages/en/guides/content-collections.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index b143d88f19249..73223844f1eca 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -171,16 +171,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); ### Landing page example -Given the following collection: - -```bash -src/content/ -β”œβ”€β”€ blog/ - β”œβ”€β”€ columbia.md - β”œβ”€β”€ endeavour.md - └── enterprise.md -``` -...and the following schema: +Given a `src/content/blog/` collection with the following schema: ```ts // src/content/config.ts From 228b20873daac4c48d4f202c7c2d3309ad14429b Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:31:45 -0500 Subject: [PATCH 085/125] edit: trailing /, newline Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 73223844f1eca..6f3080cbd4d8e 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -39,7 +39,8 @@ src/content/ ### Organizing with nested directories -Collections are **top-level folders** within `src/content`. You cannot nest collections, but you may use nested directories within a collection to better organize a collection's content. All nested directories will share the same schema defined for the top-level collection. +Collections are **top-level folders** within `src/content/`. You cannot nest collections, but you may use nested directories within a collection to better organize a collection's content. All nested directories will share the same schema defined for the top-level collection. + For example, you can use this structure for internationalization: ```bash From 0cbce489fe7b58a9c80dfd191826949b83c678e3 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:32:03 -0500 Subject: [PATCH 086/125] edit: clarify schema config Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 6f3080cbd4d8e..f772bf7be3c5d 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -63,7 +63,7 @@ To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file 1. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection. 2. Export a `collections` object, with each object key corresponding to the collection's folder name. -For example, say you have a `src/content/engineering-blog` collection, where every entry should have a `title`, list of `tags`, and an optional `image` URL. You can specify each expected property like so: +For example, say you have a `src/content/engineering-blog/` collection, where every entry should have a `title`, list of `tags`, and an optional `image` URL. You can specify each expected property in the `schema` field of `defineCollection`: ```ts // src/content/config.ts From ebc2f60f423de3caf082baa3df84349264278df0 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:32:35 -0500 Subject: [PATCH 087/125] edit: well aren't you detail orien`tag` Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index f772bf7be3c5d..7c53cfaa8c1b2 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -72,8 +72,8 @@ import { z, defineCollection } from 'astro:content'; const engineeringBlog = defineCollection({ schema: { title: z.string(), - image: z.string().optional(), tags: z.array(z.string()), + image: z.string().optional(), }, }); From 6f91765070134b0169d617e2fcdb8cc0c396f449 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:33:05 -0500 Subject: [PATCH 088/125] edit: refine frontmatter prop x data type Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 7c53cfaa8c1b2..5066c892567d1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -85,7 +85,7 @@ export const collections = { ### Schema data types with Zod -Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. Each frontmatter property must be listed in your schema object along with its data type. To define and validate this schema, we use a library called [zod](https://github.com/colinhacks/zod), which is available via the `z` import. +Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. When defining a schema, you must include every frontmatter property along with its data type. To define and validate this schema, we use a library called [Zod](https://github.com/colinhacks/zod), which is available via the `z` import. You can extend any of these types with `.optional()` (make property optional) or `.defaultValue(value)` (set a default value). You can also specify a set of allowable values for a frontmatter property using `enum`. From 7fae5bd154ed45181be13c2620076eeecb877df3 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:34:03 -0500 Subject: [PATCH 089/125] edit: refine zod schema intro Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5066c892567d1..abb381f5cb9b5 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -87,7 +87,7 @@ export const collections = { Markdown and MDX frontmatter can contain booleans, strings, numbers, objects, and arrays. When defining a schema, you must include every frontmatter property along with its data type. To define and validate this schema, we use a library called [Zod](https://github.com/colinhacks/zod), which is available via the `z` import. -You can extend any of these types with `.optional()` (make property optional) or `.defaultValue(value)` (set a default value). You can also specify a set of allowable values for a frontmatter property using `enum`. +You can extend any of these types with `.optional()` if a frontmatter property is not always required or `.defaultValue(value)` to provide a value to use when the property is not set in frontmatter. If only a limited set of values is valid for a property, you can specify these using [the `.enum()` method](https://github.com/colinhacks/zod#zod-enums). The following schema illustrates each of these data types in use: From 5d973aeb1b4ae2e8e8551c9c806abf8af359baa4 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:34:23 -0500 Subject: [PATCH 090/125] edit: whitespace in collection example Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index abb381f5cb9b5..efd8f5a317788 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -141,8 +141,10 @@ It can also take a second, optional parameter: a filter function based on schema ```astro --- import { getCollection } from 'astro:content'; + // Get all `src/content/blog/` entries const allBlogPosts = await getCollection('blog'); + // Only return posts with `draft: true` in the frontmatter const draftBlogPosts = await getCollection('blog', ({ data }) => { return data.draft === true; From 1c4b1021074ce1713d3e52eba7624a0c45687e6d Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:34:55 -0500 Subject: [PATCH 091/125] =?UTF-8?q?edit:=20CHRIS=3F=20IS=20THAT=20AN=20EMO?= =?UTF-8?q?JI=3F=20I'M=20CALLING=20THE=20POLICE=20=F0=9F=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index efd8f5a317788..a9f1244096246 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -126,7 +126,7 @@ You can use all of Zod’s properties and methods with content schemas. This inc } ``` -See [Zod’s documentation](https://github.com/colinhacks/zod) for a complete list of features. +πŸ“š See [Zod’s documentation](https://github.com/colinhacks/zod) for a complete list of features. ## Querying content collections From b7e3b650e7386eb7288b5828be923c64d4aab6a1 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:35:11 -0500 Subject: [PATCH 092/125] edit: clarify with uncompiled Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index a9f1244096246..bcaa693f50c00 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -170,7 +170,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); - `id` - a unique ID using the file path relative to `src/content/[collection]` - `slug` - a URL-ready slug. Defaults to the ID without the file extension. - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - - `body` - a string containing the raw body of the Markdown or MDX document. + - `body` - a string containing the raw, uncompiled body of the Markdown or MDX document. ### Landing page example From ec65b65e4fdee1f3612909bc3b623b2f91727365 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 13 Dec 2022 13:44:36 -0500 Subject: [PATCH 093/125] edit: refine landing page example (now usage ex) --- src/pages/en/guides/content-collections.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index bcaa693f50c00..be40f3d19f941 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -164,7 +164,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); --- ``` -### Data returned from a collections query +### Data returned from a collection query `getCollection()` and `getEntry()` will return entries that include: - `id` - a unique ID using the file path relative to `src/content/[collection]` @@ -172,9 +172,9 @@ const enterprise = await getEntry('blog', 'enterprise.md'); - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - `body` - a string containing the raw, uncompiled body of the Markdown or MDX document. -### Landing page example +### Usage example -Given a `src/content/blog/` collection with the following schema: +Say you have a `blog/` collection with the post title, publish status, and publish date in each entry's frontmatter. You may define a schema in your `src/content/config.ts` like so: ```ts // src/content/config.ts @@ -190,7 +190,7 @@ const blog = defineCollection({ export const collections = { blog }; ``` -You can use `getCollection()` on an index page to retrieve each post's type-safe frontmatter and a `slug` to use for links: +Now, say you want to generate a landing page of links to all published blog posts. You can filter out unpublished posts by calling `getCollection()` with a filter applied, and map over the results to generate links: ```astro --- From dacc5a443c7844a42cc1ad6ebf476870e32c5ca9 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:45:01 -0500 Subject: [PATCH 094/125] edit: remove unused `tags` Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index be40f3d19f941..5bc8e83622821 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -182,7 +182,6 @@ import { z, defineCollection } from 'astro:content'; const blog = defineCollection({ schema: { title: z.string(), - tags: z.array(z.string()), status: z.enum(['draft', 'published']).default('draft'), publishedDate: z.string().transform((str) => new Date(str)), }, From a59a39a764174b85575039074e5b3b356459e36f Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 13 Dec 2022 13:49:16 -0500 Subject: [PATCH 095/125] edit: move "querying nested directories" to `getCollection` docs --- src/pages/en/guides/content-collections.md | 27 +++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5bc8e83622821..7f8b4a2ae5c90 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -152,6 +152,20 @@ const draftBlogPosts = await getCollection('blog', ({ data }) => { --- ``` +#### Querying nested directories + +The filter function can also be used to query for nested directories within a collection. Since the `id` includes the full nested path, you can filter by the start of each `id` like so: + +```astro +--- +import { getCollection } from 'astro:content'; +const enDocs = await getCollection('docs', ({ id }) => { + // Return all entries in `src/content/docs/en/` + return id.startsWith('en/'); +}); +--- +``` + ### `getEntry()` `getEntry()` is function that returns a specific entry in a collection by entry ID (file path relative to the collection). Both of these are required parameters. @@ -213,19 +227,6 @@ const blogPosts = await getCollection('blog', ({ data }) => { ``` -:::tip -Add a filtering function to `getCollections()` to return a subset of a collection's entries. For example, to fetch an entire subdirectory within a collection: - -```astro ---- -import { getCollection } from 'astro:content'; -const enDocs = await getCollection('docs', ({ id }) => { - return id.startsWith('en/'); -}); ---- -``` -::: - ### Collection entry types If a page or component uses content from a `getCollection()` or `getEntry()` query, you can use the `CollectionEntry` utility to type its props: From a42ef7475adaac2d70ec2e7f8b4cf12a2f155610 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Tue, 13 Dec 2022 13:49:58 -0500 Subject: [PATCH 096/125] edit: regexcellent catch Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 7f8b4a2ae5c90..7c281311ebde1 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -231,7 +231,7 @@ const blogPosts = await getCollection('blog', ({ data }) => { If a page or component uses content from a `getCollection()` or `getEntry()` query, you can use the `CollectionEntry` utility to type its props: -```astro /CollectionEntry[(<.+>)?]/ +```astro /CollectionEntry([<.+>])?/ --- // src/components/BlogCard.astro import type { CollectionEntry } from 'astro:content'; From 4afbde020f16d658c4cbc9ee5f529085ffcf9df1 Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Tue, 13 Dec 2022 13:53:08 -0500 Subject: [PATCH 097/125] edit: usage example l3 -> l4 --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 7c281311ebde1..349ee79d082cf 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -186,7 +186,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - `body` - a string containing the raw, uncompiled body of the Markdown or MDX document. -### Usage example +#### Usage example Say you have a `blog/` collection with the post title, publish status, and publish date in each entry's frontmatter. You may define a schema in your `src/content/config.ts` like so: From 5fc82de02136c5f39f3e9b32bdb1130e8a8a6122 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:52:06 -0500 Subject: [PATCH 098/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 349ee79d082cf..ab468c3920a8d 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -52,7 +52,6 @@ src/content/ └── ... ``` -All nested directories will share the same schema defined for the top-level collection, if any (**docs** in this example). ## Defining a collection schema From 9f82c52c8c2906cbef0a9f9b0723de983acbef3f Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:52:36 -0500 Subject: [PATCH 099/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ab468c3920a8d..b64f9df75b08d 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -19,7 +19,7 @@ Astro treats the `src/content/` directory as special. This is where **collection A collection is a directory in `src/content/` containing Markdown or MDX fields. Every Markdown or MDX file in `src/content/` **must** belong to a collection directory, since Astro [provides built-in functions](#querying-content-collections) for querying your content by the collection directory name. -As a best practice, content within a collection should share the same frontmatter shape and types. You can optionally enforce these types [by configuring a schema](/en/guides/content-collections/#defining-a-collection-schema). +Content within a collection should share the same frontmatter shape and types. You can optionally enforce these types [by configuring a schema](/en/guides/content-collections/#defining-a-collection-schema). To create a collection, add a new directory to `src/content/`. Then, add Markdown or MDX entries that share frontmatter properties. The following example shows two collections: `blog` and `newsletter`. From 2fede085680ff304d979927cbe0b865e3bd7302c Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:52:45 -0500 Subject: [PATCH 100/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index b64f9df75b08d..6a4ccf3026526 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -37,7 +37,7 @@ src/content/ └── week-3.md ``` -### Organizing with nested directories +### Collections with nested directories Collections are **top-level folders** within `src/content/`. You cannot nest collections, but you may use nested directories within a collection to better organize a collection's content. All nested directories will share the same schema defined for the top-level collection. From e2a49564cd348bfec480aefca93df954cc9a659a Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:52:55 -0500 Subject: [PATCH 101/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 6a4ccf3026526..e040b4a423198 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -55,7 +55,7 @@ src/content/ ## Defining a collection schema -Schemas are an optional way to enforce frontmatter types in a collection. Astro uses [Zod](https://github.com/colinhacks/zod) to validate your frontmatter with schemas as [Zod objects](https://github.com/colinhacks/zod#objects). +Schemas are an optional way to enforce frontmatter types in a collection. Astro uses [Zod](https://github.com/colinhacks/zod) to validate your frontmatter with schemas in the form of [Zod objects](https://github.com/colinhacks/zod#objects). To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file should: From 868ab93ca5c8b8bbdba46321dd0fb245c278b155 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:53:22 -0500 Subject: [PATCH 102/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index e040b4a423198..35beea58e7f54 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -59,15 +59,25 @@ Schemas are an optional way to enforce frontmatter types in a collection. Astro To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file should: -1. Import the `defineCollection` and `z` utilities from `astro:content`. These are used to define a `schema` for each collection. -2. Export a `collections` object, with each object key corresponding to the collection's folder name. +1. Import the `defineCollection` and `z` utilities from `astro:content`. +2. Define a `schema` for each collection. +2. Export a single `collections` object, with each object key corresponding to the collection's folder name. -For example, say you have a `src/content/engineering-blog/` collection, where every entry should have a `title`, list of `tags`, and an optional `image` URL. You can specify each expected property in the `schema` field of `defineCollection`: +For example, say you maintain two collections: one for release announcements and one for blog content. Your entries at `src/content/announcements` should include a `title` and `version`. Your `src/content/engineering-blog/` collection entries should have a `title`, list of `tags`, and an optional `image` URL. + +You can specify each expected property in the `schema` field of `defineCollection`: ```ts // src/content/config.ts import { z, defineCollection } from 'astro:content'; +const releases = defineCollection({ + schema: { + title: z.string(), + version: z.number(), + }, +}); + const engineeringBlog = defineCollection({ schema: { title: z.string(), @@ -77,6 +87,7 @@ const engineeringBlog = defineCollection({ }); export const collections = { + releases: releases, // Don't forget 'quotes' for collection names containing dashes 'engineering-blog': engineeringBlog, }; From b26591145d0fabe90e24ea696c5cc5a577bdff2b Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:53:34 -0500 Subject: [PATCH 103/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 35beea58e7f54..9ad1ea5efcb3c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -164,7 +164,7 @@ const draftBlogPosts = await getCollection('blog', ({ data }) => { #### Querying nested directories -The filter function can also be used to query for nested directories within a collection. Since the `id` includes the full nested path, you can filter by the start of each `id` like so: +The filter function can also be used to query for nested directories within a collection. Since the `id` includes the full nested path, you can filter by the start of each `id` to only return items from a specific nested directory: ```astro --- From 3c546723ba6bf32c0d17be0bfca076b9e2c1cc7a Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:53:56 -0500 Subject: [PATCH 104/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 9ad1ea5efcb3c..af76f4ab31aa7 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -196,25 +196,9 @@ const enterprise = await getEntry('blog', 'enterprise.md'); - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - `body` - a string containing the raw, uncompiled body of the Markdown or MDX document. -#### Usage example - -Say you have a `blog/` collection with the post title, publish status, and publish date in each entry's frontmatter. You may define a schema in your `src/content/config.ts` like so: - -```ts -// src/content/config.ts -import { z, defineCollection } from 'astro:content'; -const blog = defineCollection({ - schema: { - title: z.string(), - status: z.enum(['draft', 'published']).default('draft'), - publishedDate: z.string().transform((str) => new Date(str)), - }, -}); -export const collections = { blog }; -``` - -Now, say you want to generate a landing page of links to all published blog posts. You can filter out unpublished posts by calling `getCollection()` with a filter applied, and map over the results to generate links: +Querying your content files with `getCollection()`or `getEntry()` allows you to use frontmatter properties from an entry's `data` object in [JSX-like expressions](/en/core-concepts/astro-components/#jsx-like-expressions) or pass props to other components, such as a layout. You can optionally add type safety with a built-in utility. +For example, you can use a `getCollection()` query to filter and then display a list of links to all your published blog posts: ```astro --- // src/pages/index.astro From 80991fec0a0d5bed81e40ce2c14344b2ec0bfab1 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:54:04 -0500 Subject: [PATCH 105/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index af76f4ab31aa7..5fc49a76bae1e 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -240,7 +240,7 @@ const { post } = Astro.props; --- ``` -## Rendering content +## Rendering page content from entries You may need to render the contents of your Markdown and MDX entries as well. This is especially useful when generating pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), or adding post previews to your homepage. From c26d987c43312e4333efc94433d5e3e9cff788be Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:54:21 -0500 Subject: [PATCH 106/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 5fc49a76bae1e..53cd487842e63 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -242,7 +242,7 @@ const { post } = Astro.props; ## Rendering page content from entries -You may need to render the contents of your Markdown and MDX entries as well. This is especially useful when generating pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), or adding post previews to your homepage. +To render the content of your Markdown and MDX entries, use the `` component returned by the `renderEntry()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. You can retrieve a `` component for use in your Astro files with `renderEntry()`. For example, this page will render the contents of `content/announcements/welcome.md`: From cca41b06efaa6f7ae56de5626b8e2e2cbbb620bd Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:59:21 -0500 Subject: [PATCH 107/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 53cd487842e63..c11d07cd0c68c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -244,19 +244,25 @@ const { post } = Astro.props; To render the content of your Markdown and MDX entries, use the `` component returned by the `renderEntry()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. -You can retrieve a `` component for use in your Astro files with `renderEntry()`. For example, this page will render the contents of `content/announcements/welcome.md`: +### `renderEntry()` + +`renderEntry()` is a function that takes an entry retrieved by `getEntry()` as a parameter and returns a `` component containing the rendered content of the Markdown or MDX file. + +For example, this page renders the contents of `content/announcements/welcome.md` and uses some of its frontmatter properties: ```astro "renderEntry" --- // src/pages/welcome-announcement.astro +import Layout from '../../layouts/Layout.astro'; import { renderEntry, getEntry } from 'astro:content'; - const announcementPost = await getEntry('announcements', 'welcome.md'); const { Content } = await renderEntry(announcementPost); --- - -

{announcementPost.data.title}

- + +

{announcementPost.data.title}

+

Written by: {announcementPost.data.author}

+ +
``` ### Access content headings From b70c7865fdaaa00d4cde7c83af5607d076ce3906 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:59:33 -0500 Subject: [PATCH 108/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index c11d07cd0c68c..ae3545e799984 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -265,9 +265,9 @@ const { Content } = await renderEntry(announcementPost); ``` -### Access content headings +### Access content headings from `renderEntry()` -Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `renderEntry`: +Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `renderEntry()`: ```astro "{ headings }" --- From 84af2d28b85595950118a7e86b73378119af1fac Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:59:40 -0500 Subject: [PATCH 109/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ae3545e799984..02d57bf08ce05 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -282,9 +282,9 @@ const blogPosts = await getCollection('blog'); })} ``` -### Access injected frontmatter +### Access injected frontmatter from renderEntry() -Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `renderEntry`: +Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `renderEntry()`: ```astro "{ injectedFrontmatter }" --- From 36f9d68c381fb07bcaa8477e7ad343513ecbe628 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 13:59:50 -0500 Subject: [PATCH 110/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 02d57bf08ce05..3299d8a0c97ff 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -303,7 +303,7 @@ Assuming `readingTime` was injected ([see our reading time example](/en/guides/m
**πŸ™‹ Why don't `getCollection` and `getEntry` contain these values?** -The remark and rehype pipelines are only run when your content is **rendered.** This lets `renderEntry` access anything generated by these plugins like injected frontmatter. To stay performant, `getCollection` and `getEntry` do not have this capability. +The remark and rehype pipelines are only run when your content is **rendered.** This lets `renderEntry()` access anything generated by these plugins like injected frontmatter. To stay performant, `getCollection()` and `getEntry()` do not have this capability.
From 9bd3c7114309ab11c8a6ebb3a149498373247218 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 14 Dec 2022 14:00:34 -0500 Subject: [PATCH 111/125] Update src/pages/en/guides/content-collections.md Co-authored-by: Sarah Rainsberger --- src/pages/en/guides/content-collections.md | 39 ++++++++++------------ 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 3299d8a0c97ff..f6b62ac397c6c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -309,32 +309,29 @@ The remark and rehype pipelines are only run when your content is **rendered.** ## Generating pages from content collections -You can create pages from your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes). +You can create pages based on your content collections using [dynamic routes](/en/core-concepts/routing/#dynamic-routes). -Say you have a `src/content/blog/` collection, and you want to map these entries to `/posts/*` URLs. You can create a `posts/[...slug].astro` route using `getStaticPaths` like so: +Use `getCollection()` inside a [`getStaticPaths()`](/en/reference/api-reference/#getstaticpaths) function to query your content entries and provide the `slug` parameter for each page. -```astro "{ slug: entry.slug }" ---- -// src/pages/posts/[...slug].astro -import { getCollection } from 'astro:content'; -export async function getStaticPaths() { - const blog = await getCollection('blog'); - // Map collection entries to pages - return blog.map(entry => ({ - // `entry.slug` is the filename of each blog post with `.md` removed - params: { slug: entry.slug }, - })); -} ---- -``` - -This will generate routes for every entry in our collection, mapping each entry's slug to a URL. For example, an entry at `src/content/blog/hello-world.md` will have a slug of `hello-world`. Because this dynamic route is in `src/pages/posts/`, the final URL will be `/posts/hello-world`. +For example, you can dynamically create a page for each entry in a `blog` collection, including nested directories, by creating a `.astro` page with a [rest parameter in its filename](/en/core-concepts/routing/#rest-parameters) to match file paths of any depth. -### Generating pages with nested directories + ```astro "{ slug: entry.slug }" + --- + // src/pages/posts/[...slug].astro + import { getCollection } from 'astro:content'; + + export async function getStaticPaths() { + const blog = await getCollection('blog'); + return blog.map(entry => ({ + params: { slug: entry.slug }, + })); + } + --- + ``` -If you have a collection with [nested directories](#organizing-with-nested-directories) (e.g. when organizing your content by locale) this will be reflected in each entry's `slug`. For example, the collection entry `blog/en/intro.md` will have a slug of `en/intro`. +This will generate page routes for every entry in the `blog` collection, mapping each entry’s slug to a URL. For example, an entry at `src/content/blog/hello-world.md` will have a slug of `hello-world` and the collection entry `src/content/blog/en/intro.md` will have a slug of `en/intro`. -Using [rest parameters in your dynamic routes](/en/core-concepts/routing/#rest-parameters) like in the example above supports mapping nested slugs out-of-the-box. +Because this dynamic route is in `src/pages/posts/`, the final URLs will be `/posts/hello-world/` and `/posts/en/intro/`. ### Rendering post contents From 94c53c7973929efe947bfe0673a0f1d4dd02f1aa Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Wed, 14 Dec 2022 14:02:07 -0500 Subject: [PATCH 112/125] edit: rendering-post-contents rework --- src/pages/en/guides/content-collections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index f6b62ac397c6c..b1a6729ac65b7 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -282,7 +282,7 @@ const blogPosts = await getCollection('blog'); })} ``` -### Access injected frontmatter from renderEntry() +### Access injected frontmatter from `renderEntry()` Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `renderEntry()`: @@ -335,7 +335,7 @@ Because this dynamic route is in `src/pages/posts/`, the final URLs will be `/po ### Rendering post contents -When generating pages with a dynamic route, you can pass each collection entry via `props` in your `getStaticPaths()` function. You can then retrieve the entry from `Astro.props` and use `renderEntry` to render its contents: +When you pass each page route an entry via `props` in your `getStaticPaths()` function, you have access to the entry from `Astro.props`. You can use its frontmatter values via the `data` object and use `renderEntry()` to render its content via a ` component. You can optionally add type safety using the `CollectionEntry` utility. ```astro "renderEntry" "props: entry" --- From 79fb7c50db73b6226ac63e065debe666a7caaa97 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Wed, 14 Dec 2022 23:24:51 +0100 Subject: [PATCH 113/125] Extend extensions --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index b1a6729ac65b7..e1a914bda7e82 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -57,7 +57,7 @@ src/content/ Schemas are an optional way to enforce frontmatter types in a collection. Astro uses [Zod](https://github.com/colinhacks/zod) to validate your frontmatter with schemas in the form of [Zod objects](https://github.com/colinhacks/zod#objects). -To configure schemas, create a `src/content/config.{js|mjs|ts}` file. This file should: +To configure schemas, create a `src/content/config.ts` file (`.js` and `.mjs` extensions are also supported). This file should: 1. Import the `defineCollection` and `z` utilities from `astro:content`. 2. Define a `schema` for each collection. From 14987a51a3cccde566438b69fe388edefd623916 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Wed, 14 Dec 2022 23:40:11 +0100 Subject: [PATCH 114/125] =?UTF-8?q?2=20green=20bullet=20points=20sitting?= =?UTF-8?q?=20on=20a=20wall=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/en/guides/content-collections.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index e1a914bda7e82..06aabd0102277 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -8,7 +8,6 @@ i18nReady: false Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. Collections may be helpful if you: - **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc). -- **Have a growing number of documents** to manage and fetch (e.g. a blog with 20+ posts). - **Want Astro to enforce frontmatter fields,** and fail if fields are missing (e.g. every blog post should have a title and description). ## The content directory From e05e9f394b6ba699ec761ffc9f2464ca0591fdfa Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 15 Dec 2022 11:20:14 -0500 Subject: [PATCH 115/125] new: add experimental note --- src/pages/en/guides/content-collections.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 06aabd0102277..1b8ecc6d1b275 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -10,6 +10,21 @@ Content collections help organize your Markdown or MDX and type-check your front - **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc). - **Want Astro to enforce frontmatter fields,** and fail if fields are missing (e.g. every blog post should have a title and description). +## Getting started + +Content Collections are experimental. To enable this feature, set the `experimental.contentCollections` flag in your Astro config: + +```js +// astro.config.mjs +import { defineConfig } from 'astro'; + +export default defineConfig({ + experimental: { + contentCollections: true, + }, +}); +``` + ## The content directory Astro treats the `src/content/` directory as special. This is where **collections** (folders) of Markdown/MDX **entries** (files) can be stored, with a single configuration file to define each collection's **schema** (frontmatter data types and shape). Files other than your `.md`/`.mdx` content are not permitted inside `src/content/`. From dcb7dcebdcd340e8a244db207590bc408364901d Mon Sep 17 00:00:00 2001 From: bholmesdev Date: Thu, 15 Dec 2022 11:25:46 -0500 Subject: [PATCH 116/125] edit: renderEntry -> render --- src/pages/en/guides/content-collections.md | 39 +++++++++++----------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 1b8ecc6d1b275..e584040869882 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -209,6 +209,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); - `slug` - a URL-ready slug. Defaults to the ID without the file extension. - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - `body` - a string containing the raw, uncompiled body of the Markdown or MDX document. + - `render()` - a function that returns the compiled body of the Markdown or MDX document via the `` component ([See complete documentation](#render)). Querying your content files with `getCollection()`or `getEntry()` allows you to use frontmatter properties from an entry's `data` object in [JSX-like expressions](/en/core-concepts/astro-components/#jsx-like-expressions) or pass props to other components, such as a layout. You can optionally add type safety with a built-in utility. @@ -256,21 +257,21 @@ const { post } = Astro.props; ## Rendering page content from entries -To render the content of your Markdown and MDX entries, use the `` component returned by the `renderEntry()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. +To render the content of your Markdown and MDX entries, use the `` component returned by the `render()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. -### `renderEntry()` +### `render()` -`renderEntry()` is a function that takes an entry retrieved by `getEntry()` as a parameter and returns a `` component containing the rendered content of the Markdown or MDX file. +`render()` is an extension function every content collection entry that returns a `` component. This contains the rendered content of the Markdown or MDX file. For example, this page renders the contents of `content/announcements/welcome.md` and uses some of its frontmatter properties: -```astro "renderEntry" +```astro "render()" --- // src/pages/welcome-announcement.astro import Layout from '../../layouts/Layout.astro'; -import { renderEntry, getEntry } from 'astro:content'; +import { getEntry } from 'astro:content'; const announcementPost = await getEntry('announcements', 'welcome.md'); -const { Content } = await renderEntry(announcementPost); +const { Content } = await announcementPost.render(); ---

{announcementPost.data.title}

@@ -279,35 +280,35 @@ const { Content } = await renderEntry(announcementPost);
``` -### Access content headings from `renderEntry()` +### Access content headings from `render()` -Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `renderEntry()`: +Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `render()`: ```astro "{ headings }" --- -import { getCollection, renderEntry } from 'astro:content'; +import { getCollection } from 'astro:content'; const blogPosts = await getCollection('blog'); --- {blogPosts.map(async (post) => { - const { headings } = await renderEntry(post); + const { headings } = await post.render(); const h1 = headings.find(h => h.depth === 1); return

{h1}

})} ``` -### Access injected frontmatter from `renderEntry()` +### Access injected frontmatter from `render()` -Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `renderEntry()`: +Astro allows you to [inject frontmatter using remark or rehype plugins.](/en/guides/markdown-content/#example-injecting-frontmatter) You can access these values using the `injectedFrontmatter` property from `render()`: ```astro "{ injectedFrontmatter }" --- -import { getCollection, renderEntry } from 'astro:content'; +import { getCollection } from 'astro:content'; const blogPosts = await getCollection('blog'); --- {blogPosts.map(async (post) => { - const { injectedFrontmatter } = await renderEntry(post); + const { injectedFrontmatter } = await post.render(); return

{post.data.title} β€” {injectedFrontmatter.readingTime}

})} ``` @@ -317,7 +318,7 @@ Assuming `readingTime` was injected ([see our reading time example](/en/guides/m
**πŸ™‹ Why don't `getCollection` and `getEntry` contain these values?** -The remark and rehype pipelines are only run when your content is **rendered.** This lets `renderEntry()` access anything generated by these plugins like injected frontmatter. To stay performant, `getCollection()` and `getEntry()` do not have this capability. +The remark and rehype pipelines are only run when your content is **rendered.** This lets `render()` access anything generated by these plugins like injected frontmatter. To stay performant, `getCollection()` and `getEntry()` do not have this capability.
@@ -349,12 +350,12 @@ Because this dynamic route is in `src/pages/posts/`, the final URLs will be `/po ### Rendering post contents -When you pass each page route an entry via `props` in your `getStaticPaths()` function, you have access to the entry from `Astro.props`. You can use its frontmatter values via the `data` object and use `renderEntry()` to render its content via a ` component. You can optionally add type safety using the `CollectionEntry` utility. +When you pass each page route an entry via `props` in your `getStaticPaths()` function, you have access to the entry from `Astro.props`. You can use its frontmatter values via the `data` object and use `render()` to render its content via a ` component. You can optionally add type safety using the `CollectionEntry` utility. -```astro "renderEntry" "props: entry" +```astro "render()" "props: entry" --- // src/pages/blog/[...slug].astro -import { getCollection, renderEntry, CollectionEntry } from 'astro:content'; +import { getCollection, CollectionEntry } from 'astro:content'; export async function getStaticPaths() { const docs = await getCollection('docs'); @@ -370,7 +371,7 @@ interface Props { } const { entry } = Astro.props; -const { Content } = await renderEntry(entry); +const { Content } = await entry.render(); ---

{entry.data.title}

From ee7083140f1f393ae4be3c66b5a40e9c532c70a4 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Fri, 16 Dec 2022 09:15:34 -0500 Subject: [PATCH 117/125] edit: a -> your wording Co-authored-by: Chris Swithinbank --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index e584040869882..1a96f5e666389 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -257,7 +257,7 @@ const { post } = Astro.props; ## Rendering page content from entries -To render the content of your Markdown and MDX entries, use the `` component returned by the `render()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. +To render the content of a Markdown or MDX entry, use the `` component returned by its `render()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. ### `render()` From 0cd4f0f431c7c8856def38fb6c73339844e35067 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Fri, 16 Dec 2022 15:27:10 +0100 Subject: [PATCH 118/125] Spaces --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 1a96f5e666389..06fcf7c71b7c4 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -101,7 +101,7 @@ const engineeringBlog = defineCollection({ }); export const collections = { - releases: releases, + releases: releases, // Don't forget 'quotes' for collection names containing dashes 'engineering-blog': engineeringBlog, }; From 61c02812e3ce5c4a6ca3addf198de62f68b03eeb Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Fri, 16 Dec 2022 15:28:05 +0100 Subject: [PATCH 119/125] Unmangle before rework --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 06fcf7c71b7c4..1b2f9bc738995 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -261,7 +261,7 @@ To render the content of a Markdown or MDX entry, use the `` componen ### `render()` -`render()` is an extension function every content collection entry that returns a `` component. This contains the rendered content of the Markdown or MDX file. +Every content collection entry includes a `render()` function that returns a `` component. This component will render the content of the Markdown or MDX file. For example, this page renders the contents of `content/announcements/welcome.md` and uses some of its frontmatter properties: From e9bac980e3e8c7aaa17be1231f10d74f2a677231 Mon Sep 17 00:00:00 2001 From: delucis Date: Fri, 16 Dec 2022 17:42:21 +0100 Subject: [PATCH 120/125] =?UTF-8?q?Rework=20=E2=80=9Crendering=20content?= =?UTF-8?q?=E2=80=9D=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/en/guides/content-collections.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 1b2f9bc738995..1aa0332efa5b2 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -255,13 +255,22 @@ const { post } = Astro.props; --- ``` -## Rendering page content from entries +## Rendering entry content -To render the content of a Markdown or MDX entry, use the `` component returned by its `render()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. +Every collection entry includes a `render()` function that gives you access to the contents of the Markdown or MDX file. This includes a `` component for rendering the document body, as well as the document headings and injected frontmatter. -### `render()` +```astro {5} +--- +// src/pages/render-example.astro +import { getEntry } from 'astro:content'; +const entry = await getEntry('blog', 'post-1.md'); +const { Content, headings, injectedFrontmatter } = await entry.render(); +--- +``` + +### Access the `` component from `render()` -Every content collection entry includes a `render()` function that returns a `` component. This component will render the content of the Markdown or MDX file. +To render the content of a Markdown or MDX entry, use the `` component returned by its `render()` function. This allows you to generate pages from your content entries (see [Generating pages from content collections](#generating-pages-from-content-collections)), add post previews to your homepage, or display your content elsewhere on your site. For example, this page renders the contents of `content/announcements/welcome.md` and uses some of its frontmatter properties: @@ -280,7 +289,7 @@ const { Content } = await announcementPost.render(); ``` -### Access content headings from `render()` +### Access headings from `render()` Astro [generates a list of headings](/en/guides/markdown-content/#exported-properties) for Markdown and MDX documents. You can access this list using the `headings` property from `render()`: From 834adfdc10d928084de5dcf1f9b5cc63ee32b76c Mon Sep 17 00:00:00 2001 From: delucis Date: Fri, 16 Dec 2022 17:51:49 +0100 Subject: [PATCH 121/125] Fix broken fragment link --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 1aa0332efa5b2..ad9e0d4d47485 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -209,7 +209,7 @@ const enterprise = await getEntry('blog', 'enterprise.md'); - `slug` - a URL-ready slug. Defaults to the ID without the file extension. - `data` - an object of frontmatter properties inferred from your collection schema. Defaults to `any` if no schema is configured. - `body` - a string containing the raw, uncompiled body of the Markdown or MDX document. - - `render()` - a function that returns the compiled body of the Markdown or MDX document via the `` component ([See complete documentation](#render)). + - `render()` - a function that returns the compiled body of the Markdown or MDX document via the `` component ([See complete documentation](#rendering-entry-content)). Querying your content files with `getCollection()`or `getEntry()` allows you to use frontmatter properties from an entry's `data` object in [JSX-like expressions](/en/core-concepts/astro-components/#jsx-like-expressions) or pass props to other components, such as a layout. You can optionally add type safety with a built-in utility. From b1fbb2f0a0b379356bca6710dd394c096844664d Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger Date: Fri, 16 Dec 2022 13:04:38 -0400 Subject: [PATCH 122/125] add parentheses to functions --- src/pages/en/guides/content-collections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index ad9e0d4d47485..33d22e63c60f3 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -325,7 +325,7 @@ const blogPosts = await getCollection('blog'); Assuming `readingTime` was injected ([see our reading time example](/en/guides/markdown-content/#example-calculate-reading-time)), it will be available on the `injectedFrontmatter` object.
-**πŸ™‹ Why don't `getCollection` and `getEntry` contain these values?** +**πŸ™‹ Why don't `getCollection()` and `getEntry()` contain these values?** The remark and rehype pipelines are only run when your content is **rendered.** This lets `render()` access anything generated by these plugins like injected frontmatter. To stay performant, `getCollection()` and `getEntry()` do not have this capability. From 8ab003752157b56299c7ee27b81c8f92810e4922 Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger Date: Fri, 16 Dec 2022 14:46:02 -0400 Subject: [PATCH 123/125] strictNullChecks --- src/pages/en/guides/content-collections.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 33d22e63c60f3..b2bce39305e58 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -25,6 +25,16 @@ export default defineConfig({ }); ``` +You will also need to update `tsconfig.json`. Add `"strictNullChecks": true` under `compilerOptions`. + +```json title="tsconfig.json" ins={3} +{ + "compilerOptions": { + "strictNullChecks": true + } +} +``` + ## The content directory Astro treats the `src/content/` directory as special. This is where **collections** (folders) of Markdown/MDX **entries** (files) can be stored, with a single configuration file to define each collection's **schema** (frontmatter data types and shape). Files other than your `.md`/`.mdx` content are not permitted inside `src/content/`. From d0ca82c0fed1ca3d260894cdd2c23fe95ecabe6d Mon Sep 17 00:00:00 2001 From: delucis Date: Fri, 16 Dec 2022 21:17:55 +0100 Subject: [PATCH 124/125] Use `` :christmas_tree: --- src/pages/en/guides/content-collections.md | 42 +++++++++++----------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index b2bce39305e58..2d50583f63fc4 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -3,6 +3,8 @@ layout: ~/layouts/MainLayout.astro title: Content Collections (Experimental) description: Content collections help organize your Markdown and type-check your frontmatter with schemas. i18nReady: false +setup: | + import FileTree from '~/components/FileTree.astro' --- Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. Collections may be helpful if you: @@ -47,19 +49,17 @@ Content within a collection should share the same frontmatter shape and types. Y To create a collection, add a new directory to `src/content/`. Then, add Markdown or MDX entries that share frontmatter properties. The following example shows two collections: `blog` and `newsletter`. -```bash "newsletter/" "blog/" -src/content/ -β”‚ # All blog posts have the same frontmatter properties -β”œβ”€β”€ blog/ -β”‚ β”œβ”€β”€ columbia.md -β”‚ β”œβ”€β”€ endeavour.md -β”‚ └── enterprise.md -β”‚ # All newsletters have the same frontmatter properties -└── newsletter/ - β”œβ”€β”€ week-1.md - β”œβ”€β”€ week-2.md - └── week-3.md -``` + +- src/content/ + - **blog/** All blog posts have the same frontmatter properties + - columbia.md + - endeavour.md + - enterprise.md + - **newsletter/** All newsletters have the same frontmatter properties + - week-1.md + - week-2.md + - week-3.md + ### Collections with nested directories @@ -67,15 +67,13 @@ Collections are **top-level folders** within `src/content/`. You cannot nest col For example, you can use this structure for internationalization: -```bash -src/content/ -└── docs/ - β”‚ # docs schema applies to all nested directories πŸ‘‡ - β”œβ”€β”€ en/ - β”œβ”€β”€ es/ - └── ... -``` - + +- src/content/ + - docs/ docs schema applies to all nested directories + - en/ + - es/ + - ... + ## Defining a collection schema From 7d7f2353d589a907085b8ed4bd25fe420af345c7 Mon Sep 17 00:00:00 2001 From: delucis Date: Fri, 16 Dec 2022 22:02:10 +0100 Subject: [PATCH 125/125] Add Since component --- src/pages/en/guides/content-collections.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pages/en/guides/content-collections.md b/src/pages/en/guides/content-collections.md index 2d50583f63fc4..56d10ad8f2f3c 100644 --- a/src/pages/en/guides/content-collections.md +++ b/src/pages/en/guides/content-collections.md @@ -5,8 +5,13 @@ description: Content collections help organize your Markdown and type-check your i18nReady: false setup: | import FileTree from '~/components/FileTree.astro' + import Since from '~/components/Since.astro' --- +

+ +

+ Content collections help organize your Markdown or MDX and type-check your frontmatter with schemas. Collections may be helpful if you: - **Plan to use Markdown content in multiple areas** of your site (landing pages, footers, navigation, etc).