Концепция островной архитектуры

Fresh — фреймворк для JavaScript/TypeScript, построенный вокруг идеи островной архитектуры (island architecture). В отличие от классических SPA и даже большинства SSR-фреймворков, Fresh рассматривает интерактивность как точечное свойство страницы, а не как обязательное состояние всего приложения.

Ключевая установка: HTML по умолчанию статичен, JavaScript подключается только там, где он действительно нужен.


Проблема монолитной интерактивности

Традиционные подходы (SPA, hybrid SSR) имеют общие черты:

  • загрузка большого JavaScript-бандла;
  • инициализация всего приложения на клиенте;
  • гидратация всей страницы, даже если интерактивны лишь отдельные элементы.

Это приводит к:

  • увеличению Time to Interactive;
  • росту потребления памяти;
  • ненужной работе браузера;
  • ухудшению производительности на слабых устройствах.

Островная архитектура решает эту проблему, разделяя страницу на статическое море HTML и интерактивные острова.


Сущность островной архитектуры

Страница состоит из двух типов компонентов:

1. Серверные компоненты (Server Components) Рендерятся исключительно на сервере. Не попадают в клиентский JavaScript. Не имеют состояния в браузере.

2. Острова (Islands) Изолированные интерактивные компоненты. Гидратируются отдельно. Загружают JavaScript только для себя.

Каждый остров — автономная единица, не зависящая от глобального состояния страницы.


Как Fresh реализует острова

Fresh использует строгую файловую конвенцию:

routes/
  index.tsx
islands/
  Counter.tsx
  • Всё, что находится в routes/, считается серверным.
  • Всё, что находится в islands/, автоматически становится интерактивным.

При использовании island-компонента внутри server-компонента Fresh:

  • рендерит его HTML на сервере;
  • добавляет минимальный маркер для клиента;
  • подключает JavaScript только для этого острова.

Серверный рендеринг без клиентского JS

Обычный компонент маршрута:

export default function Home() {
  return (
    <main>
      <h1>Статическая страница</h1>
      <p>Этот HTML не требует JavaScript.</p>
    </main>
  );
}

Результат:

  • чистый HTML;
  • нулевой JavaScript;
  • мгновенная отрисовка.

Это фундаментальное отличие Fresh от фреймворков, где даже «статическая» страница часто требует загрузки runtime.


Пример острова

Компонент в 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>
  );
}

Использование в маршруте:

import Counter from "../islands/Counter.tsx";

export default function Home() {
  return (
    <div>
      <h1>Счётчик</h1>
      <Counter />
    </div>
  );
}

Fresh автоматически:

  • определяет границу интерактивности;
  • гидратирует только Counter;
  • не подключает Preact runtime для остальной страницы.

Гидратация по требованию

Fresh применяет частичную гидратацию:

  • каждый остров гидратируется независимо;
  • отсутствие глобального root-приложения;
  • отсутствие общего состояния.

Это исключает типичные проблемы:

  • cascading re-render;
  • глобальные side-effects;
  • сложные схемы state management.

Отсутствие бандлинга

Одна из ключевых особенностей Fresh — полный отказ от сборки:

  • используется нативный ES Modules;
  • зависимости загружаются по URL;
  • Deno выполняет кэширование автоматически.

Для островной архитектуры это критично:

  • каждый остров загружает только свои зависимости;
  • отсутствует единый бандл для всего приложения;
  • уменьшается время холодного старта.

Изоляция как архитектурный принцип

Каждый island:

  • не знает о других island-компонентах;
  • не полагается на глобальное состояние;
  • может быть удалён без побочных эффектов.

Это приводит к:

  • высокой модульности;
  • предсказуемому поведению;
  • упрощённому тестированию.

Изоляция реализована не на уровне соглашений, а на уровне самой архитектуры фреймворка.


Server-first подход

Fresh исходит из предположения, что:

  • серверный рендеринг — норма;
  • клиентский JavaScript — исключение.

Это меняет стиль проектирования интерфейсов:

  • сначала структура и данные;
  • затем интерактивность;
  • затем оптимизация клиентского кода.

В результате HTML снова становится первичным артефактом.


Отсутствие глобального состояния

Fresh намеренно не предлагает:

  • глобальный store;
  • контексты уровня приложения;
  • middleware для клиента.

Состояние либо:

  • живёт на сервере;
  • локально внутри island;
  • передаётся через props.

Это устраняет целый класс ошибок, связанных с синхронизацией и повторной гидратацией.


Производительность как следствие архитектуры

Островная архитектура в Fresh даёт измеримые эффекты:

  • минимальный JavaScript payload;
  • быстрый First Contentful Paint;
  • низкий Time to Interactive;
  • высокая устойчивость к медленным сетям.

Оптимизация достигается не настройками, а самой моделью.


Отличие от других island-подходов

В отличие от гибридных решений:

  • Fresh не требует специального синтаксиса для islands;
  • не использует директивы (client:load, client:idle);
  • не допускает случайной глобальной гидратации.

Остров определяется строго местоположением файла, а не аннотациями.


Архитектурные ограничения как преимущество

Fresh намеренно ограничивает возможности:

  • нельзя случайно сделать весь проект интерактивным;
  • нельзя подключить клиентский JS без явного острова;
  • нельзя создать «скрытую» зависимость от браузера.

Эти ограничения формируют дисциплину проектирования и упрощают поддержку кода.


Островная архитектура как философия

В Fresh island architecture — не оптимизация и не паттерн, а базовая философия:

  • HTML прежде JavaScript;
  • сервер прежде клиента;
  • локальная интерактивность вместо глобальной.

Фреймворк не навязывает сложность, а делает её осознанным выбором.