Fresh — это современный фреймворк для разработки веб-приложений на JavaScript и TypeScript, ориентированный на серверную генерацию страниц с минимальным JavaScript на клиенте. Основная цель — упрощение работы с состоянием, потоками данных и рендерингом без необходимости сложных клиентских SPA-архитектур.
Fresh построен на принципах Islands Architecture, где основная страница рендерится на сервере, а интерактивные элементы (islands) подключаются по мере необходимости. Такая модель позволяет:
Модель данных в Fresh ориентирована на иммутабельность и чистоту функций рендеринга. Данные, полученные на сервере, передаются в компоненты как пропсы, что гарантирует предсказуемость поведения интерфейса.
Состояние в Fresh делится на три уровня:
Серверное состояние формируется на этапе рендеринга страницы. Для его
получения используются функции типа handler:
export const handler = {
GET(req, ctx) {
const data = fetchDataFromDB();
return ctx.render({ data });
},
};
Интерактивные элементы используют локальное состояние через стандартные React-подобные подходы:
import { useState } from "preact/hooks";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onCl ick={() => setCount(count + 1)}>
{count}
</button>
);
}
Для управления общими данными рекомендуется использовать контексты:
import { createContext } from "preact";
import { useContext } from "preact/hooks";
const ThemeContext = createContext("light");
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemedButton() {
const { theme, setTheme } = useContext(ThemeContext);
return <button onCl ick={() => setTheme(theme === "light" ? "dark" : "light")}>{theme}</button>;
}
Fresh передаёт серверные данные на клиент через props, автоматически сериализуемые в JSON. Для сложных типов (например, Date или Map) требуется ручная сериализация:
return ctx.render({ date: date.toISOString() });
На клиенте их можно десериализовать обратно:
const date = new Date(props.date);
Такой подход гарантирует безопасность данных и избежание утечек состояния между пользователями.
Fresh минимизирует клиентский JavaScript, поэтому интерактивные элементы должны быть максимально локализованными. Рекомендации:
В Fresh формы и события часто обрабатываются на сервере, а клиентский код служит лишь для улучшения UX:
export const handler = {
POST: async (req, ctx) => {
const formData = await req.formData();
const name = formData.get("name");
saveToDB(name);
return ctx.render({ message: `Saved ${name}` });
},
};
Если требуется мгновенная реакция на изменения, можно подключить island-компонент, который управляет локальным состоянием и обновляет DOM без полной перезагрузки страницы.
Эта архитектура позволяет создавать веб-приложения с предсказуемым поведением, высокой производительностью и лёгким управлением состоянием, сочетая лучшие практики серверного рендеринга и реактивных интерфейсов.