Фреймворк Fresh представляет собой современную платформу для разработки веб-приложений на JavaScript с использованием Deno. При переходе с Nuxt важно понимать различия в архитектуре, рендеринге и управлении состоянием, чтобы корректно перенести существующий проект.
Nuxt использует традиционную структуру pages,
components, store, plugins и
assets. В Fresh структура упрощена:
pages. Каждая страница соответствует файлу с расширением
.tsx или .ts.client-only, но с более строгим
разделением клиентского и серверного кода.Особенность: в Fresh отсутствует глобальный стор. Управление состоянием клиентских компонентов выполняется через собственные хуки или сторонние библиотеки (например, Zustand, Redux Toolkit).
Nuxt поддерживает SSR и SSG, включая гибридные подходы. Fresh
ориентирован на SSR по умолчанию, с возможностью
статической генерации страниц через deno task prebuild.
Основные моменты при миграции:
routes/*.tsx) экспортируют функцию
handler(req: Request), которая возвращает HTML.<Island />, где Island — компонент, импортированный
из islands/.fetch,
Deno.readTextFile, и т.д.), что заменяет Nuxt
asyncData и fetch.Пример серверной функции в Fresh:
export const handler: Handlers = {
async GET(req, ctx) {
const data = await fetch("https://api.example.com/posts").then(res => res.json());
return ctx.render({ posts: data });
},
};
Nuxt компоненты рендерятся как на сервере, так и на клиенте. Fresh разделяет:
Пример Island:
/** 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>
);
}
Использование в маршруте:
/** routes/index.tsx */
import Counter from "../islands/Counter.tsx";
export default function Home() {
return (
<div>
<h1>Главная страница</h1>
<Counter />
</div>
);
}
Nuxt предлагает Vuex или Composition API. Fresh не имеет встроенного хранилища, поэтому миграция потребует:
useState, useEffect).createContext и useContext.Пример глобального состояния через Context:
/** components/Store.tsx */
import { createContext } from "preact";
import { useState } from "preact/hooks";
export const CounterContext = createContext(null);
export function CounterProvider({ children }) {
const [count, setCount] = useState(0);
return (
<CounterContext.Provider value={{ count, setCount }}>
{children}
</CounterContext.Provider>
);
}
В Nuxt маршруты генерируются автоматически по файлам в
pages/. Fresh использует похожий принцип, но с расширением
.tsx и явным экспортом обработчика. Отличия:
[id].tsx.Request внутри handler.Пример динамического маршрута:
/** routes/posts/[id].tsx */
export const handler: Handlers = {
async GET(req, ctx) {
const { id } = ctx.params;
const post = await fetch(`https://api.example.com/posts/${id}`).then(res => res.json());
return ctx.render({ post });
},
};
В Nuxt asyncData выполняется перед рендерингом страницы.
В Fresh аналогично:
handler может извлекать данные через
fetch или работу с файловой системой.services.Пример сервисного слоя:
// services/posts.ts
export async function getPost(id: string) {
const res = await fetch(`https://api.example.com/posts/${id}`);
return res.json();
}
Использование в маршруте:
import { getPost } from "../services/posts.ts";
export const handler: Handlers = {
async GET(req, ctx) {
const post = await getPost(ctx.params.id);
return ctx.render({ post });
},
};
static/, аналог Nuxt
static.import "./style.css";.Nuxt предоставляет serverMiddleware и api/.
Fresh использует обработчики (Handlers) в маршрутах.
Разница:
Пример middleware:
export function authMiddleware(handler: Handlers): Handlers {
return {
async GET(req, ctx) {
const token = req.headers.get("Authorization");
if (!token) return new Response("Unauthorized", { status: 401 });
return handler.GET(req, ctx);
},
};
}
Fresh ориентирован на минимизацию JavaScript на клиенте. Основные принципы:
islands).При миграции следует выделять только действительно интерактивные части приложения в islands и максимально переносить логику на сервер.
Миграция с Nuxt на Fresh требует пересмотра подхода к рендерингу, состоянию и структуре проекта. Основное внимание уделяется разделению серверной и клиентской логики, использованию islands для интерактивности и организации маршрутов через обработчики. Такой подход обеспечивает высокую производительность и упрощает поддержку больших приложений.