Дайджесты новостей
Рабочее место веб-разработчика с механической клавиатурой, скетчбуком архитектуры и кодом на TanStack Start 1.0.

TanStack Start 1.0: выход в стабильный релиз фреймворка без привязки к RSC

Когда экосистема React несколько лет назад свернула на рельсы React Server Components (RSC), многие из нас почувствовали легкое головокружение. Затея на бумаге выглядела заманчиво: рендерим тяжелые куски прямо на сервере, не тащим мегабайты зависимостей в браузер, а данные из базы забираем прямо внутри компонентов без лишних API-эндпоинтов.

Но на практике разработка быстро превратилась в полосу препятствий. Стоит тебе случайно прокинуть функцию обратного вызова через границу 'use client', как сборщик встречает тебя простыней невразумительных ошибок сериализации. Открываешь вкладку Network в консоли браузера, чтобы посмотреть, что пришло с бэкенда, а там вместо привычного JSON лежит каша из внутренних потоковых чанков виртуального DOM. Добавь сюда привязку к платформенным серверам конкретного облачного провайдера, и желание писать привычный веб начинает стремительно угасать.

Именно поэтому первый стабильный релиз TanStack Start 1.0, вышедший после года открытого тестирования в статусе Release Candidate, стал для фронтенд-сообщества настоящим глотком свежего воздуха. Таннер Линсли и команда TanStack пошли против модного течения и приняли смелое инженерное решение: полностью отказаться от обязательного навязывания RSC в пользу прозрачной, проверенной годами архитектуры.

Смелый отказ от серверных компонентов

Самая интригующая деталь этого релиза кроется в закулисье. Изначально, на этапе первых альфа-версий, команда TanStack честно пыталась реализовать полноценную поддержку React Server Components. Таннер Линсли открыто признал: в какой-то момент поддержка RSC воспринималась просто как формальный «входной билет», без которого сообщество и крупные компании не воспринимали бы новый метафреймворк всерьез.

Однако по мере усложнения спецификации разработчики осознали тупиковость этого пути. Чтобы заставить RSC работать стабильно, приходилось городить чудовищные компиляторные костыли, ломать привычную модель жизненного цикла хуков и жертвовать прозрачностью отладки. В итоге команда пошла на радикальный шаг: они не просто выбросили RSC из ядра TanStack Start, но и полностью переписали собственный официальный портал tanstack.com, убрав оттуда серверные компоненты.

Оказалось, что без этой прослойки сайт стал быстрее, предсказуемее и в разы проще в поддержке. Подробнее об этой философии мы уже говорили в нашем предыдущем материале о релизе TanStack Start 1.0, а теперь этот манифест независимости закреплен в стабильном мажорном статусе.

Архитектурный фундамент: роутер, RPC и Nitro

Как же устроен TanStack Start «под капотом», если в нем нет серверных компонентов? Модель здесь предельно честная и элегантная, понятная любому разработчику без докторской степени по Computer Science:

  1. Клиентская часть остается старым добрым React-приложением. Ты пишешь компоненты так, как привык: со стейтом, хуками, эффектами и контекстами.
  2. Маршрутизация целиком опирается на TanStack Router. Это файловый роутер с бескомпромиссной сквозной типизацией. Параметры URL, поисковые квери-параметры (search params) и возвращаемые типы загрузчиков строго проверяются компилятором TypeScript. Если ты переименуешь параметр в роуте, проект просто не соберется, пока ты не исправишь ссылки по всему коду.
  3. Серверный код оформляется через примитив createServerFn. Это явная декларация серверной функции, которая автоматически превращается компилятором в типобезопасный удаленный вызов процедур (RPC). Тебе не нужно вручную описывать Express-роуты или выдумывать REST-эндпоинты: ты просто вызываешь функцию, а фреймворк сам делает сетевой запрос и передает сериализованный ответ.
  4. Сборка и серверный рантайм построены на связке Vite, Vinxi и Nitro. Nitro — это тот самый всеядный движок, который генерирует легковесные изолированные артефакты под десятки различных платформ.

Хочешь упаковать приложение в минималистичный Docker-контейнер и развернуть на копеечном VPS с Node.js или быстрым рантаймом Bun? Пожалуйста. Предпочитаешь бессерверные окружения вроде AWS Lambda, Cloudflare Workers или Vercel? Никаких проблем: смена пресета развертывания сводится к одной строчке конфигурации. Никакого вендорлока и закрытых хостинговых контрактов.

Практика: создаем проект и объявляем серверную функцию

Давай посмотрим, как эта связка выглядит на практике. Инициализация чистого проекта выполняется официальной командой через терминал:

npm create @tanstack/start@latest my-start-app
cd my-start-app
npm install
npm run dev

Внутри проекта клиентский и серверный код разделяются абсолютно прозрачно. Создадим файл с серверной функцией app/functions/posts.ts. Обрати внимание, как здесь нативно подключается библиотека валидации Zod:

import { createServerFn } from '@tanstack/react-start';
import { z } from 'zod';

// Декларация строго типизированной серверной функции
export const getPostById = createServerFn({ method: 'GET' })
  .inputValidator(z.object({ id: z.string() }))
  .handler(async ({ data }) => {
    // Этот код гарантированно исполняется только на сервере:
    // здесь можно безопасно обращаться к базам данных и приватным секретам
    const response = await fetch(`https://api.example.com/posts/${data.id}`, {
      headers: { Authorization: `Bearer ${process.env.INTERNAL_API_SECRET}` },
    });

    if (!response.ok) {
      throw new Error('Запрошенная статья не найдена на бэкенде');
    }

    return (await response.json()) as { title: string; body: string };
  });

Теперь подключим эту функцию к файловому маршруту в файле app/routes/posts/$postId.tsx. Механизм loader заберет данные на сервере при первичном SSR или сделает фоновый RPC-запрос при клиентском переходе:

import { createFileRoute } from '@tanstack/react-router';
import { getPostById } from '../../functions/posts';

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    // Прямой вызов серверной функции с автодополнением типов
    return await getPostById({ data: { id: params.postId } });
  },
  component: PostComponent,
});

function PostComponent() {
  const post = Route.useLoaderData();

  return (
    <article className="post-container">
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </article>
  );
}

Все чисто, прозрачно и отлаживается в две секунды. В сетевой вкладке ты видишь аккуратный HTTP-запрос, в коде работает идеальный автокомплит TypeScript, а сборщик не ругается на невозможность сериализовать скрытые классы.

Бенчмарки: сухие цифры против хайпа

Отказ от громоздкой архитектурной надстройки дал вполне ощутимые аппаратные дивиденды. В синтетических и нагрузочных тестах на идентичных типовых приложениях TanStack Start продемонстрировал впечатляющие результаты:

Сравнительная инфографика бенчмарков пропускной способности SSR и ускорения сборки TanStack Start.

  • Пропускная способность SSR: фреймворк обрабатывает в 2.9–8.6 раз больше динамических запросов в секунду по сравнению с Next.js 16.4. Причина проста: серверу не нужно строить дерево сериализации RSC-чанков и парсить сложные метаданные на каждый входящий запрос.
  • Скорость холодной и горячей сборки: за счет использования чистого Vite и оптимизированного пайплайна генерации типов полное время компиляции проекта с проверкой типов (typecheck) сократилось примерно в 1.7 раза.

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

Нюанс нумерации версий в npm

Если ты заглянешь в официальный реестр npm, то увидишь, что пакет @tanstack/react-start имеет версию 1.169.x вместо ожидавшейся круглой 1.0.0. Не пугайся: команда синхронизировала версионирование Start с пакетами ядра TanStack Router, чтобы упростить управление монорепозиторием и не плодить несовместимости зависимостей. Публичный релиз 1.0 знаменует именно стабилизацию архитектуры и фиксацию контракта обратной совместимости.

Трезвый взгляд на компромиссы и безопасность

Было бы нечестно рисовать исключительно идеальную картину. У любого архитектурного выбора есть своя цена, и TanStack Start — не исключение:

  1. Безопасность мутаций (CSRF): Поскольку серверные функции createServerFn могут принимать HTTP POST-запросы напрямую, для любых изменяющих состояние действий необходимо явно подключать middleware защиты от межсайтовой подделки запросов (createCsrfMiddleware). В Next.js базовая защита для Server Actions встроена глубже.
  2. Зрелость экосистемы плагинов: Next.js существует больше восьми лет. Под него написаны тысячи готовых интеграций с CMS, сервисами аналитики и библиотеками авторизации (вроде NextAuth/Auth.js). В TanStack Start многие вещи вроде аутентификации придется настраивать более осознанно и руками, хотя интеграция с Better Auth и Clerk здесь уже работает «из коробки».
  3. Границы перехода: Если твой проект уже глубоко завязан на асинхронные серверные компоненты Next.js со сложным стримингом Suspense-островов по всей глубине DOM-дерева, переписывать его на Start «в лоб» не имеет смысла — миграция потребует переосмысления архитектуры слоя данных.

Но если ты начинаешь новый проект или устал бороться с черным ящиком чужих платформенных соглашений, TanStack Start 1.0 предлагает самый здравый и прагматичный стек в современном фронтенде: честный React, кристально чистые типы и полный контроль над собственным кодом.