Astro 5.10

Автор
Matt Kane

🎥 На этот раз в прямом эфире — и мы всегда отзывчивы к вашим потребностям.

Astro 5.10: responsive images для всех, экспериментальные live content collections, улучшения CSP и многое другое!

Чтобы обновить существующий проект, используйте CLI @astrojs/upgrade. Или обновите вручную:

# Рекомендуется:
npx @astrojs/upgrade
# Вручную:
npm install astro@latest
pnpm upgrade astro --latest
yarn upgrade astro --latest

Experimental live content collections

Live content collections — загрузка контента в runtime вместо build time.

Build-time collections идеальны для редко меняющегося контента. Live collections — для частых обновлений и персонализации.

How it works

Live loaders выполняются при посещении страниц. Для производительности — build-time где возможно; live — для актуальности и фильтрации по пользователю.

astro.config.mjs
export default defineConfig({
experimental: {
liveContentCollections: true,
},
});

src/live.config.ts:

src/live.config.ts
import { defineLiveCollection } from 'astro:content';
import { storeLoader } from './loaders/store';
export const products = defineLiveCollection({
type: 'live',
loader: storeLoader({
apiKey: process.env.STORE_API_KEY,
endpoint: 'https://api.mystore.com/v1',
}),
});

Fetching live data

getLiveCollection() и getLiveEntry():

src/pages/products/[slug].astro
---
import { getLiveEntry } from 'astro:content';
const { entry: product, error } = await getLiveEntry(
'products',
Astro.params.slug,
);
if (error) {
console.error('Failed to load product:', error);
return Astro.rewrite('/404');
}
---
<h1>{product.data.name}</h1>
<p>
{
Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
product.data.price,
)
}
</p>

Rendering live content

src/pages/products/[slug].astro
---
import { getLiveEntry, render } from 'astro:content';
const { entry: product, error } = await getLiveEntry(
'products',
Astro.params.slug,
);
if (error) {
console.error('Failed to load product:', error);
return Astro.rewrite('/404');
}
const { Content } = await render(product);
---
<h1>{product.data.name}</h1>
<Content />

Flexible filtering

src/pages/products.astro
---
import { getLiveCollection } from 'astro:content';
const { entries, error } = await getLiveCollection('products', {
category: 'electronics',
priceRange: { min: 10, max: 100 },
});
---

Error handling

Результат с data или error — предсказуемое поведение в runtime.

Type safety

Полная типобезопасность API и query options.

experimental live content collections documentation. RFC.

Responsive images are now stable

Responsive images стабильны и готовы к production!

Автоматические srcset, sizes и стили — меньше layout shift, лучше Core Web Vitals.

Get started with responsive images

layout: constrained, fixed, full-width:

astro.config.mjs
export default defineConfig({
image: {
responsiveStyles: true,
layout: 'constrained',
},
});
<Image
src="/hero.jpg"
alt="A panoramic view of the mountains"
layout="full-width"
/>

Priority loading:

<Image src="/hero.jpg" alt="Hero image" priority />

priorityloading="eager", decoding="sync", fetchpriority="high". Не более одного на страницу — для LCP element.

Enhanced cropping controls:

<Image
src="/profile.jpg"
alt="Profile photo"
fit="cover"
position="center top"
width={300}
height={300}
/>

Upgrading from experimental responsive images

Удалите experimental flag, перенесите image.experimental в stable:

astro.config.mjs
export default defineConfig({
experimental: {
responsiveImages: true,
},
image: {
responsiveStyles: true,
},
});

Images guide.

Improvements to experimental Content Security Policy

Astro 5.9 — experimental CSP meta tags. 5.10: Response headers, включая static pages. On-demand — headers вместо meta (лучше в Chrome, больше директив). Static — через adapters с experimentalStaticHeaders:

astro.config.mjs
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';
export default defineConfig({
adapter: netlify({
experimentalStaticHeaders: true,
}),
experimental: {
csp: true,
},
});

experimental CSP documentation.

Customizable Cloudflare Workers entrypoint

Durable Objects, Queues, Cron Triggers требуют custom entrypoint. workerEntryPoint:

astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
adapter: cloudflare({
workerEntryPoint: {
path: 'src/worker.ts',
namedExports: ['MyDurableObject']
}
}),
});
src/worker.ts
import type { SSRManifest } from 'astro';
import { App } from 'astro/app';
import { handle } from '@astrojs/cloudflare/handler'
import { DurableObject } from 'cloudflare:workers';
class MyDurableObject extends DurableObject<Env> {
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env)
}
}
export function createExports(manifest: SSRManifest) {
const app = new App(manifest);
return {
default: {
async fetch(request, env, ctx) {
await env.MY_QUEUE.send("log");
return handle(manifest, app, request, env, ctx);
},
async queue(batch, _env) {
let messages = JSON.stringify(batch.messages);
console.log(`consumed from our queue: ${messages}`);
}
} satisfies ExportedHandler<Env>,
MyDurableObject,
}
}

Cloudflare adapter documentation.

Спасибо Alexander Niebuhr!

Bug fixes

С релиза 5.9changelog.

Community

Команда Astro:

Ben Holmes, Caleb Jasik, Chris Swithinbank, Emanuele Stoppa, Erika, Florian Lefebvre, Fred Schott, Fuzzy, HiDeoo, Luiz Ferraz, Matt Kane, Matthew Phillips, Nate Moore, Reuben Tier, Sarah Rainsberger, and Yan Thomas.

Спасибо Alexander Niebuhr, Anshul Gupta, Armand Philippot, benosmac, Han Seung Min - 한승민, Junseong Park, kato takeshi, knj, liruifengv, Martin Haug, Martin Trapp, Nin3, Paul Valladares, Quinn Blenkinsop, Thomas Bonnet, and zaitovalisher