Контекст запроса

Fresh — это современный подход к построению реактивных веб-приложений на JavaScript, ориентированный на минимизацию избыточной загрузки данных и оптимизацию взаимодействия клиента с сервером. Основная цель Fresh — обеспечить свежесть данных без излишней сложности архитектуры и сложного состояния.


Основы Fresh

В ядре Fresh лежит концепция “request-context-driven rendering”. Каждое обращение к серверу рассматривается как отдельный контекст, в котором формируется полный набор данных, необходимых для рендеринга. Это позволяет:

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

Важное отличие Fresh от классических SPA-фреймворков состоит в том, что сервер формирует почти всю страницу, а клиент отвечает только за минимальную интерактивность.


Контекст запроса

Контекст запроса (request context) — это объект, содержащий всю информацию, доступную во время обработки HTTP-запроса:

const context = {
  request: req,       // объект запроса
  params: req.params, // параметры URL
  state: {},          // временное состояние для этого запроса
  session: {},        // пользовательская сессия
};

Ключевые свойства контекста:

  • request — стандартный объект запроса, включающий заголовки, метод, URL и тело;
  • params — динамические сегменты маршрута;
  • state — временные данные, используемые только в рамках текущего запроса;
  • session — информация о пользователе, которая может быть сохранена между запросами.

Контекст создаётся автоматически при каждом HTTP-запросе, что обеспечивает изоляцию данных между пользователями и запросами.


Обновление данных в Fresh

Обновление данных в Fresh строится вокруг принципа freshness — каждый запрос получает актуальные данные. Основные подходы:

  1. Серверное обновление Сервер формирует страницу с актуальными данными при каждом запросе:

    export async function handler(context) {
      const data = await fetchDataFromDB();
      return new Response(renderPage({ data }));
    }

    Данные не кэшируются на клиенте, что предотвращает устаревшую информацию.

  2. Стратегия инкрементальной актуализации Используется для больших страниц или сложных данных:

    • базовый HTML формируется на сервере;
    • части страницы (компоненты) подгружаются асинхронно;
    • обновления выполняются через Fetch или WebSocket.

Реактивные компоненты и Fresh

Компоненты Fresh работают по принципу server-first rendering:

  • Рендеринг происходит на сервере с передачей минимального JavaScript на клиент.
  • Компоненты получают данные через контекст запроса.
  • Изменения состояния инициируются на клиенте и синхронизируются с сервером при необходимости.

Пример реактивного компонента:

export default function Counter({ initial }) {
  let count = initial;

  function increment() {
    count += 1;
    updateDOM(); // минимальное вмешательство клиента
  }

  return html`
    <div>
      <span>${count}</span>
      <button oncl ick=${increment}>+1</button>
    </div>
  `;
}

Ключевой момент — клиентская логика минимальна, а сервер формирует основное содержание страницы.


Кэширование и управление свежестью

Fresh позволяет гибко управлять кэшированием:

  • Контроль кэширования HTTP-заголовками (Cache-Control, ETag) для статических ресурсов;
  • ISR (Incremental Static Regeneration) — генерация статического контента на сервере с автоматическим обновлением по таймеру или событию;
  • Кэш на уровне компонентов — некоторые части страницы можно хранить дольше, чем весь запрос, без потери актуальности.

Пример установки кэш-заголовков:

export async function handler(context) {
  const data = await fetchDataFromDB();
  return new Response(renderPage({ data }), {
    headers: { "Cache-Control": "max-age=0, must-revalidate" }
  });
}

Такой подход гарантирует, что каждый новый запрос получает свежие данные, а кэш не блокирует обновление.


Интеграция с внешними API

Fresh особенно эффективен при работе с внешними API:

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

Пример:

export async function handler(context) {
  const userId = context.params.id;
  const profile = await fetch(`https://api.example.com/users/${userId}`).then(r => r.json());
  return new Response(renderPage({ profile }));
}

Преимущества подхода Fresh

  1. Актуальные данные при каждом запросе Исключается вероятность отображения устаревшей информации.

  2. Изоляция состояния между запросами Ошибки одного пользователя не влияют на другого.

  3. Минимальная клиентская нагрузка JavaScript на клиенте используется только для интерактивных элементов.

  4. Простота интеграции с серверными ресурсами Все данные берутся из контекста запроса или внешних API.

  5. Удобство масштабирования Серверные рендеры и реактивные компоненты позволяют легко добавлять новые страницы и функциональность без глобальных изменений состояния.


Практические рекомендации

  • Использовать контекст запроса для хранения всех временных данных и параметров маршрута.
  • Выносить интерактивную логику на минимальный клиентский JavaScript.
  • Применять кэширование только там, где данные не требуют мгновенной актуализации.
  • При работе с внешними API передавать через контекст все необходимые заголовки и параметры для аутентификации и фильтрации.
  • Организовывать структуру компонентов так, чтобы сервер рендерил базовый HTML, а клиент дополнял только интерактивность.

Fresh в JavaScript представляет собой мощный инструмент для построения быстрых, реактивных и всегда актуальных веб-приложений. Использование контекста запроса, server-first компонентов и продуманного кэширования позволяет достигать высокой производительности и надежности, при этом значительно снижая сложность клиентской логики.