Streaming SSR

Streaming SSR (Server-Side Rendering с потоковой выдачей) в TanStack Router позволяет серверу отправлять HTML-контент клиенту постепенно по мере его готовности, снижая время до первого отображения и улучшая пользовательский опыт. В отличие от классического SSR, где весь HTML формируется перед отправкой, потоковая отрисовка отдает части страницы сразу после их готовности, позволяя браузеру рендерить их по мере поступления.

Принципы работы Streaming SSR

  1. Роуты как асинхронные узлы TanStack Router организует маршрутизацию через дерево маршрутов, где каждый маршрут может иметь асинхронные загрузчики данных. При потоковом SSR каждый узел дерева рендерится сразу после завершения загрузки своих данных, без ожидания завершения всех дочерних маршрутов.

  2. Suspense и отложенная загрузка Использование React Suspense совместно с TanStack Router позволяет рендерить placeholder-элементы для участков страницы, которые ещё не готовы. После загрузки данных Suspense автоматически заменяет их на реальный контент.

  3. Потоковая передача HTML Серверная функция renderToPipeableStream (или аналог в используемом фреймворке) формирует поток HTML. TanStack Router интегрируется с этим процессом через метод router.render(), который возвращает React-элементы с уже подключенными асинхронными загрузчиками. Эти элементы могут быть переданы в поток и отправлены клиенту по мере готовности.

Настройка потокового SSR

  1. Определение маршрутов Каждый маршрут определяется с возможностью асинхронной загрузки данных через loader:

    import { createRouter } from '@tanstack/router';
    
    const router = createRouter({
      routes: [
        {
          path: '/',
          component: HomePage,
          loader: async () => {
            return fetch('/api/home').then(res => res.json());
          },
        },
        {
          path: '/profile/:id',
          component: ProfilePage,
          loader: async ({ params }) => {
            return fetch(`/api/user/${params.id}`).then(res => res.json());
          },
        },
      ],
    });

    Асинхронный loader для каждого маршрута позволяет рендерить части страницы сразу после готовности данных.

  2. Серверная функция для потоковой выдачи Потоковый SSR предполагает использование потокового API фреймворка:

    import { renderToPipeableStream } from 'react-dom/server';
    import express from 'express';
    import { RouterProvider } from '@tanstack/router';
    
    const app = express();
    
    app.get('*', (req, res) => {
      const stream = renderToPipeableStream(
        <RouterProvider router={router} initialLocation={req.url} />,
        {
          onShellReady() {
            res.setHeader('Content-Type', 'text/html');
            stream.pipe(res);
          },
          onAllReady() {
            // Можно выполнить дополнительные действия после полного рендера
          },
          onError(err) {
            console.error(err);
          },
        }
      );
    });

    Ключевой момент: onShellReady позволяет отправить клиенту основу страницы как можно раньше, а отдельные маршруты будут подгружаться по мере готовности.

Управление загрузкой данных

  • Prefetching TanStack Router поддерживает предзагрузку данных для маршрутов, которые могут быть посещены следующим шагом. В потоковом SSR это помогает заранее инициировать асинхронные запросы, сокращая время ожидания рендера дочерних маршрутов.

  • Deferred data Можно использовать defer-объекты для передачи данных, которые могут загружаться после отправки основного контента:

    import { defer } from '@tanstack/router';
    
    const loader = async () => {
      return defer({
        mainData: fetch('/api/main').then(res => res.json()),
        extraData: fetch('/api/extra').then(res => res.json()),
      });
    };

    Потоковый SSR будет рендерить mainData сразу, а extraData загрузится позже без блокировки отрисовки.

Интеграция с Suspense и ErrorBoundary

  • Suspense Позволяет рендерить fallback-контент до готовности данных:

    import { Suspense } from 'react';
    
    <Suspense fallback={<div>Загрузка...</div>}>
      <RouteComponent />
    </Suspense>
  • ErrorBoundary Обрабатывает ошибки асинхронных загрузчиков без прерывания потока SSR:

    import { ErrorBoundary } from '@tanstack/router';
    
    <ErrorBoundary fallback={<div>Произошла ошибка</div>}>
      <Suspense fallback={<div>Загрузка...</div>}>
        <RouteComponent />
      </Suspense>
    </ErrorBoundary>

Оптимизация потокового SSR

  1. Приоритет рендеринга маршрутов Можно настраивать порядок рендеринга по важности, чтобы первыми отдавались ключевые элементы страницы.
  2. Кэширование данных Асинхронные загрузчики могут использовать серверный кэш, чтобы повторная генерация HTML происходила быстрее.
  3. Минимизация блокирующих ресурсов Скрипты и стили подключаются после отправки shell, чтобы потоковое отображение страницы происходило максимально быстро.

Преимущества использования Streaming SSR в TanStack Router

  • Уменьшение времени до первого отображения (Time to First Paint).
  • Поддержка асинхронной загрузки данных на уровне маршрутов.
  • Гибкая интеграция с Suspense и ErrorBoundary для плавного UX.
  • Возможность отправки части страницы сразу, даже если остальные данные ещё загружаются.

Streaming SSR превращает серверный рендеринг в динамичный процесс, где браузер начинает отображать содержимое сразу, а TanStack Router обеспечивает корректное управление асинхронными маршрутами и данными, делая приложения быстрыми и отзывчивыми.