Dashboards

Фреймворк Fresh построен вокруг идеи минималистичных, высокопроизводительных веб-приложений на основе Deno. Dashboard в Fresh представляет собой набор страниц и компонентов, которые отображают данные в реальном времени или предоставляют пользователю визуальные отчёты и интерфейсы управления.

В основе архитектуры лежат следующие ключевые элементы:

  • Маршрутизация через файловую структуру routes/. Каждая страница Dashboard соответствует отдельному файлу или папке с файлом index.tsx.
  • Компоненты UI, создаваемые в components/, позволяют повторно использовать визуальные элементы, такие как таблицы, графики, карточки статистики.
  • Серверные обработчики (.ts или .tsx файлы) могут напрямую взаимодействовать с базой данных или внешними API, возвращая данные на клиент без необходимости полноценного бэкенда.

Структура проекта

Стандартная структура Dashboard в Fresh выглядит следующим образом:

/dashboard
  /routes
    index.tsx
    /analytics
      index.tsx
      _chart.tsx
    /users
      index.tsx
      _userCard.tsx
  /components
    NavBar.tsx
    Sidebar.tsx
    StatsCard.tsx
  /islands
    LiveChart.tsx
    Notifications.tsx
  • routes отвечает за страницы. Подпапки отражают вложенные маршруты (/analytics, /users).
  • components содержат статические элементы интерфейса.
  • islands используют концепцию islands architecture: интерактивные компоненты, которые гидратируются на клиенте, оставаясь статически отрендеренными на сервере.

Серверный рендеринг и данные

Fresh применяет серверный рендеринг (SSR) по умолчанию. Страницы Dashboard обычно получают данные через функции handler:

import { Handlers } from "$fresh/server.ts";

export const handler: Handlers = {
  async GET(_req, ctx) {
    const users = await fetch("https://api.example.com/users").then(r => r.json());
    return ctx.render({ users });
  }
};

В этом примере данные загружаются на сервере, а затем передаются в компонент страницы через ctx.render.

Работа с компонентами

Компоненты в Fresh создаются с использованием JSX/TSX и могут быть как статическими, так и интерактивными. Пример карточки статистики:

interface StatsCardProps {
  title: string;
  value: number;
}

export default function StatsCard({ title, value }: StatsCardProps) {
  return (
    <div class="p-4 bg-white rounded shadow">
      <h3 class="text-gray-500">{title}</h3>
      <p class="text-2xl font-bold">{value}</p>
    </div>
  );
}

Для интерактивных элементов применяется island:

import { useState } from "preact/hooks";

export default function LiveChart({ initialData }: { initialData: number[] }) {
  const [data, setData] = useState(initialData);

  const updateData = () => {
    const newValue = Math.floor(Math.random() * 100);
    setData([...data.slice(1), newValue]);
  };

  return (
    <div>
      <canvas id="chart"></canvas>
      <button onCl ick={updateData}>Обновить</button>
    </div>
  );
}

Island гидратируется только на клиенте, обеспечивая высокую производительность.

Навигация и управление состоянием

Для Dashboard важна удобная навигация. Fresh позволяет создавать многоуровневые меню с использованием компонентов Sidebar и NavBar:

export default function Sidebar() {
  return (
    <nav class="flex flex-col p-4 bg-gray-100 h-full">
      <a href="/dashboard" class="mb-2">Главная</a>
      <a href="/dashboard/analytics" class="mb-2">Аналитика</a>
      <a href="/dashboard/users">Пользователи</a>
    </nav>
  );
}

Состояние приложения может храниться локально в islands или управляться через Context API. Для сложных Dashboard полезно интегрировать store-подходы, например zustand или redux, но на небольших проектах локального состояния достаточно.

Интеграция с внешними API и базами данных

Dashboard часто требует отображения динамических данных. Fresh позволяет напрямую работать с внешними API или базами данных через Deno runtime:

import { Client } from "https://deno.land/x/postgres/mod.ts";

const client = new Client({ user: "user", password: "pass", database: "dashboard" });
await client.connect();

const result = await client.queryArray("SELECT * FROM users");
await client.end();

Данные можно передавать в компоненты страницы через ctx.render, обеспечивая серверный рендеринг и SEO-оптимизацию.

Оптимизация и производительность

Ключевые моменты для Dashboard:

  • Использование islands для интерактивных элементов минимизирует нагрузку на клиент.
  • SSR обеспечивает быстрый первый рендер.
  • Статические данные можно кешировать через Edge или CDN.
  • Минимизация количества запросов и агрегация данных на сервере.

Визуализация данных

Графики и диаграммы интегрируются с помощью легковесных библиотек, таких как Chart.js, или нативных canvas/ SVG. Использование islands позволяет поддерживать интерактивность без полного JS-бандла на каждой странице.

import { useEffect } FROM "preact/hooks";
import Chart from "chart.js/auto";

export default function AnalyticsChart({ data }: { data: number[] }) {
  useEffect(() => {
    const ctx = document.getElementById("chart") as HTMLCanvasElement;
    new Chart(ctx, {
      type: "line",
      data: {
        labels: data.map((_, i) => i),
        datasets: [{ label: "Продажи", data }],
      },
    });
  }, []);

  return <canvas id="chart"></canvas>;
}

Масштабирование Dashboard

Для больших проектов структура должна оставаться модульной:

  • Разделение компонентов на повторно используемые и специфичные для страниц.
  • Изоляция логики API в отдельные файлы или сервисы.
  • Использование islands только для интерактивных элементов, статические компоненты рендерить на сервере.
  • Продуманный routing и nested routes для упрощения навигации и SEO.

Fresh позволяет создавать Dashboard, которые остаются лёгкими и быстрыми даже при увеличении количества данных и страниц, благодаря серверному рендерингу, islands architecture и минимальному фронтенд-бандлу.