Fresh — это современный фреймворк для создания веб-приложений на JavaScript и TypeScript, ориентированный на серверный рендеринг с минимальной клиентской нагрузкой. Основная цель Fresh — предоставление максимально быстрой загрузки страниц, низкой задержки и удобного подхода к динамическому рендерингу без необходимости сборки большого фронтенд-бандла. Fresh построен на Deno, что обеспечивает интеграцию с современными стандартами веб-разработки и модульной системой ES.
Fresh использует концепцию islands architecture, при которой статический HTML генерируется на сервере, а интерактивные компоненты (острова) подгружаются только при необходимости. Это позволяет:
Компоненты Fresh написаны с использованием JSX, что делает их похожими на React, но без клиентского виртуального DOM. Они могут быть как статическими, так и динамическими, что особенно важно при работе с маршрутами.
Динамические маршруты в Fresh позволяют создавать страницы с переменными сегментами в URL. Такой подход необходим для отображения данных, зависящих от параметров, например, профилей пользователей, постов или товаров.
Файл динамического маршрута создается с использованием квадратных скобок в имени файла. Пример структуры:
routes/
posts/
[id].tsx
Здесь [id].tsx соответствует маршруту
/posts/:id. При обращении к /posts/123
параметр id будет равен "123".
В Fresh параметр динамического сегмента доступен через объект
params, передаваемый в функцию handler или
компонент страницы:
import { Handlers } from "$fresh/server.ts";
export const handler: Handlers = {
async GET(req, ctx) {
const { id } = ctx.params;
return new Response(`Пост с ID: ${id}`);
}
};
В JSX-компоненте параметр можно использовать через
ctx.params для генерации содержимого страницы:
export default function PostPage({ params }: { params: { id: string } }) {
return <h1>Пост ID: {params.id}</h1>;
}
Fresh поддерживает вложенные маршруты с параметрами на любом уровне структуры:
routes/
users/
[userId]/
posts/
[postId].tsx
Запрос к /users/42/posts/10 предоставит доступ к:
ctx.params.userId // "42"
ctx.params.postId // "10"
Это позволяет строить сложные структуры URL, полностью соответствующие REST-подходу.
Для динамических маршрутов важно подгружать данные на сервере. Fresh использует Server-Side Rendering (SSR), поэтому загрузка данных происходит перед генерацией HTML. Пример с API-запросом:
export const handler: Handlers = {
async GET(_req, ctx) {
const { id } = ctx.params;
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
const post = await res.json();
return ctx.render(post);
}
};
export default function PostPage({ data }: { data: any }) {
return (
<div>
<h1>{data.title}</h1>
<p>{data.body}</p>
</div>
);
}
Такой подход гарантирует, что HTML страницы сразу содержит актуальные данные без дополнительного клиентского рендеринга.
Динамические маршруты могут включать обработку некорректных
параметров или отсутствующих данных. Для этого используется объект
ctx.renderNotFound():
export const handler: Handlers = {
async GET(_req, ctx) {
const { id } = ctx.params;
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
if (res.status === 404) return ctx.renderNotFound();
const post = await res.json();
return ctx.render(post);
}
};
При вызове ctx.renderNotFound() Fresh автоматически
возвращает страницу 404.
Для динамических маршрутов Fresh предоставляет компонент
<A> для клиентской навигации без полной перезагрузки
страницы:
import { A } from "$fresh/runtime.ts";
export default function PostsList({ posts }: { posts: any[] }) {
return (
<ul>
{posts.map(post => (
<li key={post.id}>
<A href={`/posts/${post.id}`}>{post.title}</A>
</li>
))}
</ul>
);
}
Компонент <A> автоматически подгружает страницу
через JavaScript, поддерживая интерактивность без полного
перерендеринга.
Поскольку Fresh генерирует HTML на сервере, динамические страницы полностью индексируются поисковыми системами. Параметры маршрута используются для генерации уникальных URL и контента, что повышает качество SEO и позволяет строить семантическую структуру сайта без дополнительных клиентских рендеров.
ctx.renderNotFound();Динамические маршруты в Fresh обеспечивают гибкий, высокопроизводительный способ создания веб-приложений с серверным рендерингом, поддержкой вложенной структуры и полной интеграцией с современными практиками SEO и оптимизации загрузки.