
🍿 Minor Changes
-
#11657
a23c69dThanks @bluwy! - Deprecates the option for route-generating files to export a dynamic value forprerender. Only static values are now supported (e.g.export const prerender = trueor= false). This allows for better treeshaking and bundling configuration in the future.Adds a new
"astro:route:setup"hook to the Integrations API to allow you to dynamically set options for a route at build or request time through an integration, such as enabling on-demand server rendering.To migrate from a dynamic export to the new hook, update or remove any dynamic
prerenderexports from individual routing files:src/pages/blog/[slug].astro export const prerender = import.meta.env.PRERENDERInstead, create an integration with the
"astro:route:setup"hook and update the route’sprerenderoption:astro.config.mjs import { defineConfig } from 'astro/config';import { loadEnv } from 'vite';export default defineConfig({integrations: [setPrerender()],});function setPrerender() {const { PRERENDER } = loadEnv(process.env.NODE_ENV, process.cwd(), '');return {name: 'set-prerender',hooks: {'astro:route:setup': ({ route }) => {if (route.component.endsWith('/blog/[slug].astro')) {route.prerender = PRERENDER;}},},};} -
#11360
a79a8b0Thanks @ascorbic! - Adds a newinjectTypes()utility to the Integration API and refactors how type generation worksUse
injectTypes()in theastro:config:donehook to inject types into your user’s project by adding a new a*.d.tsfile.The
filenameproperty will be used to generate a file at/.astro/integrations/<normalized_integration_name>/<normalized_filename>.d.tsand must end with".d.ts".The
contentproperty will create the body of the file, and must be valid TypeScript.Additionally,
injectTypes()returns a URL to the normalized path so you can overwrite its content later on, or manipulate it in any way you want.my-integration/index.js export default {name: 'my-integration','astro:config:done': ({ injectTypes }) => {injectTypes({filename: 'types.d.ts',content: "declare module 'virtual:my-integration' {}",});},};Codegen has been refactored. Although
src/env.d.tswill continue to work as is, we recommend you update it:/// <reference types="astro/client" />/// <reference path="../.astro/types.d.ts" />/// <reference path="../.astro/env.d.ts" />/// <reference path="../.astro/actions.d.ts" /> -
#11605
d3d99fbThanks @jcayzac! - Adds a new propertymetato Astro’s built-in<Code />component.This allows you to provide a value for Shiki’s
metaattribute to pass options to transformers.The following example passes an option to highlight lines 1 and 3 to Shiki’s
tranformerMetaHighlight:src/components/Card.astro ---import { Code } from 'astro:components';import { transformerMetaHighlight } from '@shikijs/transformers';---<Code code={code} lang="js" transformers={[transformerMetaHighlight()]} meta="{1,3}" /> -
#11360
a79a8b0Thanks @ascorbic! - Adds support for Intellisense features (e.g. code completion, quick hints) for your content collection entries in compatible editors under theexperimental.contentIntellisenseflag.import { defineConfig } from 'astro';export default defineConfig({experimental: {contentIntellisense: true,},});When enabled, this feature will generate and add JSON schemas to the
.astrodirectory in your project. These files can be used by the Astro language server to provide Intellisense inside content files (.md,.mdx,.mdoc).Note that at this time, this also require enabling the
astro.content-intellisenseoption in your editor, or passing thecontentIntellisense: trueinitialization parameter to the Astro language server for editors using it directly.See the experimental content Intellisense docs for more information updates as this feature develops.
-
#11360
a79a8b0Thanks @ascorbic! - Adds experimental support for the Content Layer API.The new Content Layer API builds upon content collections, taking them beyond local files in
src/content/and allowing you to fetch content from anywhere, including remote APIs. These new collections work alongside your existing content collections, and you can migrate them to the new API at your own pace. There are significant improvements to performance with large collections of local files.Getting started
To try out the new Content Layer API, enable it in your Astro config:
import { defineConfig } from 'astro';export default defineConfig({experimental: {contentLayer: true,},});You can then create collections in your
src/content/config.tsusing the Content Layer API.Loading your content
The core of the new Content Layer API is the loader, a function that fetches content from a source and caches it in a local data store. Astro 4.14 ships with built-in
glob()andfile()loaders to handle your local Markdown, MDX, Markdoc, and JSON files:src/content/config.ts import { defineCollection, z } from 'astro:content';import { glob } from 'astro/loaders';const blog = defineCollection({// The ID is a slug generated from the path of the file relative to `base`loader: glob({ pattern: '**/*.md', base: './src/data/blog' }),schema: z.object({title: z.string(),description: z.string(),publishDate: z.coerce.date(),}),});export const collections = { blog };You can then query using the existing content collections functions, and enjoy a simplified
render()function to display your content:---import { getEntry, render } from 'astro:content';const post = await getEntry('blog', Astro.params.slug);const { Content } = await render(entry);---<Content />Creating a loader
You’re not restricted to the built-in loaders – we hope you’ll try building your own. You can fetch content from anywhere and return an array of entries:
src/content/config.ts const countries = defineCollection({loader: async () => {const response = await fetch('https://restcountries.com/v3.1/all');const data = await response.json();// Must return an array of entries with an id property,// or an object with IDs as keys and entries as valuesreturn data.map((country) => ({id: country.cca3,...country,}));},// optionally add a schema to validate the data and make it type-safe for users// schema: z.object...});export const collections = { countries };For more advanced loading logic, you can define an object loader. This allows incremental updates and conditional loading, and gives full access to the data store. It also allows a loader to define its own schema, including generating it dynamically based on the source API. See the the Content Layer API RFC for more details.
Sharing your loaders
Loaders are better when they’re shared. You can create a package that exports a loader and publish it to npm, and then anyone can use it on their site. We’re excited to see what the community comes up with! To get started, take a look at some examples. Here’s how to load content using an RSS/Atom feed loader:
src/content/config.ts import { defineCollection } from 'astro:content';import { feedLoader } from '@ascorbic/feed-loader';const podcasts = defineCollection({loader: feedLoader({url: 'https://feeds.99percentinvisible.org/99percentinvisible',}),});export const collections = { podcasts };Learn more
To find out more about using the Content Layer API, check out the Content Layer RFC and share your feedback.
🐞 Patch Changes
-
#11716
f4057c1Thanks @florian-lefebvre! - Fixes content types sync in dev -
#11645
849e4c6Thanks @bluwy! - Refactors internally to usenode:utilparseArgsinstead ofyargs-parser -
#11712
791d809Thanks @matthewp! - Fix mixed use of base + trailingSlash in Server Islands -
#11709
3d8ae76Thanks @matthewp! - Fix adapter causing Netlify to break