Astro 4.10

Автор
Matthew Phillips

Вышел Astro 4.10 с экспериментальными типобезопасными переменными окружения, а также улучшениями Container API и Rewrites.

Основные новинки:

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

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

Experimental: astro:env

Astro 4.10 представляет экспериментальный встроенный модуль astro:env для удобной работы с переменными окружения.

Переменные окружения позволяют настраивать приложение разными значениями в разных средах. Но это сложно:

  • часть переменных нужна на клиенте, часть — только на сервере;
  • серверные переменные часто секреты — API-ключи, которые нельзя показывать на клиенте и встраивать в server build;
  • некоторые переменные обязательны, другие — опциональны;
  • переменные задаются в shell, .env или build config;
  • рантаймы вроде Cloudflare и Deno имеют разные API чтения переменных — разница dev/prod.

Мы создали astro:env для структуры и контроля через схему прямо в конфиге:

import { defineConfig, envField } from 'astro/config';
export default defineConfig({
experimental: {
env: {
schema: {
API_PORT: envField.number({
context: 'server',
access: 'secret',
default: 7000
}),
PUBLIC_DASHBOARD_V2: envField.boolean({
context: 'server',
access: 'public',
default: false
}),
}
}
}
})

Используйте переменные через импорт из astro:env/server и astro:env/client:

import { PUBLIC_DASHBOARD_V2, getSecret } from 'astro:env/server';
if (PUBLIC_DASHBOARD_V2) {
const API_PORT = getSecret("API_PORT") // number
await fetch(`https://my-secret-api.com:${API_PORT}/v2`)
}

Клиентский astro:env/client — в компонентах, скриптах и любом клиентском коде. Например, показать улучшенную функцию только при включённом feature flag:

import { SOME_FEATURE_FLAG } from 'astro:env/client';
export default function() {
return (
<section>
{ SOME_FEATURE_FLAG && (
<div id="fancy-enhanced-feature"></div>
)}
...
</section>
)
}

Для переменных вне схемы — getSecret(), работает в любом рантайме (Cloudflare, Node.js, Deno).

import { getSecret } from 'astro:env/server';
function getServerEndpoint(num: number) {
return getSecret(`BACKUP_SERVER_${num}`); // string | undefined
}

astro:env экспериментален и может измениться. Спасибо Florian Lefebvre за RFC и реализацию! Обратная связь: RFC.

Rewrite for all HTTP methods

Rewriting — экспериментальная функция из 4.9. Первая версия была для GET. В 4.10 rewrites работают для любых запросов через клонирование исходного request.

Пример rewrite в middleware для направления на версию API по умолчанию:

import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(({ request, url }, next) => {
if(request.method === 'POST' && url.pathname === '/api') {
return next('/api/v2');
}
});

При rewrite создаётся новый request с новым URL. Заголовки и body копируются.

Embedding Astro

В 4.9 мы представили Container API — рендеринг Astro-компонентов вне Astro. Первый фокус — тестирование: container, container.renderToString(), проверка HTML.

Мы знали, что API захотят использовать иначе. В 4.10 можно рендерить любые компоненты из astro build — вне Astro-сайта!

Демо: Astro-in-PHP. Не судите строго, PHP-эксперты! 😅

Часть с container:

import * as components from './dist/server/all.mjs';
import { renderers } from './dist/server/renderers.mjs';
import { manifest } from './dist/server/entry.mjs';
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
const container = await AstroContainer.create({
manifest,
renderers,
resolve(s) {
const found = manifest.entryModules[s];
if(found) {
return `/astro-project/dist/client/${found}`;
}
return found;
}
});
const html = await container.renderToString(components.ReactWrapper);
// Log to the console so that PHP injects the HTML into its page.
console.log(html);

Container API низкоуровневый — отражает внутренний рендеринг Astro. Ждём интеграции от сообщества для упрощения встраивания. Попробуйте и покажите, куда добавили Astro!

Container API helpers

Добавлены хелперы для Container API в Vite-окружениях (vitest, Astro integrations и т.д.) при рендеринге UI framework компонентов.

Больше не нужно знать прямые пути к client/server rendering scripts каждого пакета. getContainerRenderer() даёт нужные скрипты из официальных интеграций (@astrojs/react, @astrojs/preact, @astrojs/solid-js, @astrojs/svelte, @astrojs/vue, @astrojs/lit, @astrojs/mdx). Обновите интеграции одновременно!

loadRenderers() из astro:container загружает renderers из каждого пакета:

import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import ReactWrapper from '../src/components/ReactWrapper.astro';
import { loadRenderers } from "astro:container";
import { getContainerRenderer } from "@astrojs/react";
test('ReactWrapper with react renderer', async () => {
const renderers = await loadRenderers([getContainerRenderer()])
const renderers = [
{
name: '@astrojs/react',
clientEntrypoint: '@astrojs/react/client.js',
serverEntrypoint: '@astrojs/react/server.js',
},
];
const container = await AstroContainer.create({
renderers,
});
const result = await container.renderToString(ReactWrapper);
expect(result).toContain('Counter');
expect(result).toContain('Count: <!-- -->5');
});

Изменение типа renderers также позволит средам без Vite загружать renderer modules вручную.

Подробнее: документация Container API.

Bug Fixes

Как обычно, Astro 4.10 включает исправления и улучшения, не вошедшие в этот пост! Полные release notes, и полное раскрытие релиза 4.10 с Astro Together! Спасибо Sarah, Erika, Bjorn, Ema, Chris, Florian и всем остальным контрибьюторам релиза.

Play