Fresh — это современный фреймворк для разработки веб-приложений на JavaScript/TypeScript, построенный поверх Deno. Он ориентирован на скорость, простоту и использование современных возможностей веб-платформы, включая рендеринг на стороне сервера (SSR) и потоковую доставку контента. Архитектурные паттерны в Fresh формируют основу организации приложений, обеспечивая масштабируемость, поддержку типов и эффективное управление состоянием.
В Fresh основная единица — компонент, который представляет собой функцию или модуль, возвращающий JSX-структуру. Каждый компонент:
useState, useEffect).Компоненты в Fresh организуются в папках routes и
islands. Паттерн Islands Architecture
позволяет рендерить статический HTML сервером, а интерактивные
компоненты загружать отдельно на клиенте. Это снижает объем
передаваемого JavaScript и ускоряет загрузку страниц.
Пример структуры проекта:
/routes
index.tsx
about.tsx
/islands
Counter.tsx
Modal.tsx
/components
Header.tsx
Footer.tsx
routes — страницы приложения, рендерятся сервером.islands — интерактивные компоненты.components — общие UI-блоки.Fresh использует SSR по умолчанию. Сервер генерирует HTML на основе маршрута и компонентов, а клиент загружает только минимальный JavaScript для интерактивности. Основные преимущества:
Пример SSR-компонента в Fresh:
import { Handlers } from "$fresh/server.ts";
export const handler: Handlers = {
GET(req, ctx) {
return ctx.render({ message: "Привет, Fresh!" });
},
};
export default function HomePage({ data }: { data: { message: string } }) {
return <h1>{data.message}</h1>;
}
Здесь ctx.render генерирует HTML на сервере с данными,
которые передаются компоненту.
Islands Architecture — ключевой подход в Fresh для гибридного рендеринга:
Пример интерактивного островка:
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 HomePage() {
return (
<div>
<h1>Главная страница</h1>
<Counter />
</div>
);
}
Здесь только Counter будет интерактивным, а остальной
HTML отрендерен сервером.
Fresh использует файловую маршрутизацию. Каждый файл
в routes автоматически становится маршрутом. Для
динамических маршрутов применяется синтаксис
[param].tsx.
Пример динамического маршрута:
/routes
posts/
[id].tsx
export const handler: Handlers = {
GET(req, ctx) {
const { id } = ctx.params;
return ctx.render({ postId: id });
},
};
export default function Post({ data }: { data: { postId: string } }) {
return <div>Пост №{data.postId}</div>;
}
Такой подход соответствует REST-подходу, где каждый ресурс имеет уникальный URL.
В Fresh состояние обычно локальное для островков
(useState). Для глобального состояния рекомендуется:
createContext)ctx.render.Пример контекста:
import { createContext } from "preact";
export const ThemeContext = createContext({ theme: "light" });
Компоненты могут использовать useContext для доступа к
состоянию.
Fresh поддерживает асинхронное получение данных через обработчики
(Handlers). Доступны следующие подходы:
Пример SSR с асинхронным fetch:
export const handler: Handlers = {
async GET(req, ctx) {
const res = await fetch("https://api.example.com/data");
const json = await res.json();
return ctx.render({ data: json });
},
};
Ключевые практики:
Архитектурные паттерны Fresh направлены на создание легковесных, быстро загружаемых и SEO-дружественных веб-приложений, где сервер и клиент эффективно разделяют ответственность за рендеринг и интерактивность.