Fresh — это современный фреймворк для разработки веб-приложений на JavaScript и TypeScript, ориентированный на минимизацию времени загрузки страниц и оптимизацию производительности за счёт рендеринга на стороне сервера. В основе Fresh лежит концепция islands architecture, где интерактивные компоненты загружаются на клиент только по необходимости, а остальной контент остаётся статическим.
Рендеринг на сервере (SSR) В Fresh большинство страниц рендерится на сервере, что позволяет получать полностью сформированный HTML без лишних скриптов на начальном этапе. Это улучшает SEO и ускоряет первую отрисовку страницы (Time to First Paint).
Islands architecture Каждый интерактивный компонент на странице изолирован в виде «острова». Это означает:
Отсутствие сборщика по умолчанию Fresh
использует возможности нативного ES-модулей в браузере. Это сокращает
время сборки и упрощает конфигурацию проекта. Каждый модуль
импортируется напрямую через
<script type="module">.
Типичный проект на Fresh имеет следующие элементы:
routes/ — каталог с маршрутами. Каждый
файл соответствует URL-пути.components/ — интерактивные компоненты
(острова).islands/ — папка для компонентов,
которые будут подгружаться на клиент.static/ — статические файлы:
изображения, CSS, шрифты.main.ts или main.js —
точка входа приложения.Страница создаётся как модуль, экспортирующий функцию
handler или JSX-компонент:
/** routes/index.tsx */
import { h } from "preact";
export default function Home() {
return (
<div>
<h1>Главная страница</h1>
<p>Контент загружается с сервера.</p>
</div>
);
}
Если нужно сделать интерактивный компонент, его помещают в папку
islands:
/** islands/Counter.tsx */
import { useState } from "preact/hooks";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onCl ick={() => setCount(count + 1)}>
Кликнули {count} раз
</button>
);
}
И подключают на странице:
import Counter from "../islands/Counter.tsx";
export default function Home() {
return (
<div>
<h1>Главная страница</h1>
<Counter />
</div>
);
}
Fresh поддерживает fetch API и интеграцию с базами
данных. Данные можно загружать на сервере до рендеринга страницы,
используя функции handler:
/** routes/posts.tsx */
import { h } from "preact";
export async function handler(req) {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
const posts = await res.json();
return new Response(
JSON.stringify(posts),
{ headers: { "Content-Type": "application/json" } }
);
}
Далее данные можно использовать в JSX:
export default function Posts({ data }) {
return (
<ul>
{data.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Fresh удобно использовать для построения приложений с API на стороне сервера. Можно комбинировать SSR и клиентские запросы к внешним API. Например:
/** routes/api/data.ts */
export async function handler(req) {
const data = { message: "Привет из API!" };
return new Response(JSON.stringify(data), {
headers: { "Content-Type": "application/json" },
});
}
На клиенте данные можно получить через fetch:
import { useEffect, useState } from "preact/hooks";
export default function ApiData() {
const [message, setMessage] = useState("");
useEffect(() => {
fetch("/api/data")
.then(res => res.json())
.then(data => setMessage(data.message));
}, []);
return <p>{message}</p>;
}
Fresh обеспечивает следующие возможности:
Для интеграции с OpenAPI можно генерировать типы TypeScript на основе спецификации API. Это обеспечивает:
import { paths } from "./openapi-types";
async function getUsers() {
const response = await fetch("/api/users");
const data: paths["/users"]["get"]["responses"]["200"]["content"]["application/json"] = await response.json();
return data;
}
Использование Fresh совместно с OpenAPI позволяет создавать безопасные, быстрые и типизированные веб-приложения, минимизируя ручное написание обёрток для API и уменьшая риск ошибок.