Чанкинг в Turbopack: меньше запросов или кода

3 сентября 2026 года команда Turbopack в Vercel опубликовала статью How Turbopack chunks your JavaScript — разбор того, как бандлер решает, какой модуль попадёт в какой файл, и почему единственно верного разбиения не существует. Важнее другое: статья раскрывает модель стоимости, которая молча работала в каждой сборке, а Next.js 16.3 позволяет её настроить.

Проблема: две цели тянут в разные стороны

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

Обратный вариант — по чанку на страницу. Ничего лишнего не отправляется, но общий компонент вроде <Footer /> оказывается внутри чанка каждой страницы. Посетитель, открывший четыре страницы, скачает этот футер четыре раза.

Ещё мельче — чанк на модуль. Дублирование исчезает, но появляются сотни крошечных запросов. HTTP/2 сделал запрос дешевле, но не бесплатным, а сжатие работает хуже на множестве мелких файлов: gzip не видит повторов за границей одного файла.

Что изменилось: слияние как ставка на вероятность

Ответ Turbopack — сливать мелкие чанки в более крупные, но только внутри chunk group, то есть набора чанков, которые загружаются вместе для одного маршрута. Такое слияние безопасно по построению: оно не может добавить того, что страница и так не грузила.

Сложнее ответить, когда слияние окупается, и ответ здесь статистический. Рассматривая слияние чанка A с чанком B, Turbopack считает, сколько групп используют только A, только B и оба сразу, а затем взвешивает выгоду против издержек. Если посетитель открыл одну страницу и ушёл, слияние выигрывает всегда. При переходе оно выигрывает только тогда, когда второй странице нужны оба чанка; иначе объединённый файл там бесполезен и A скачивается повторно. Чтобы взвесить эти два сценария, алгоритм исходит из того, что две трети сессий состоят из одной страницы.

Цифры, которые команда измерила на реальной сессии из восьми переходов по nextjs.org:

| Стратегия | Скачано кода | Запросов | | --- | --- | --- | | Без слияния | 561.6 KiB | 96 | | Настройки по умолчанию | 554.8 KiB | 38 | | Один чанк на группу | 610.0 KiB | 15 |

Значения по умолчанию сократили число запросов более чем вдвое и при этом отправили чуть меньше кода. Максимальное слияние снизило запросы сильнее, но за сессию передало примерно на 10% больше кода.

Модель стала настраиваемой

Алгоритм ограничивали две вещи: слияние решается на этапе сборки, до того как кто-либо зашёл на сайт, и ему приходится угадывать, как люди по нему перемещаются. Next.js 16.3 бьёт по обеим.

next.config.ts
import type { NextConfig } from 'next'

const nextConfig = {
  experimental: {
    turbopackChunking: {
      // выпускать неслитые варианты рядом со слитыми
      generateComponentChunks: true,
      minComponentChunkSize: 20000,
      // по умолчанию 0.67 — bounce rate хорошая оценка
      firstPageLoadPriority: 0.5,
      // маршруты, с которых обычно начинают
      priorityRoutes: [/^\/$/, /^\/pricing/],
      minChunkSize: 50000,
      maxChunkCountPerGroup: 40,
    },
    turbopackCjsTreeShaking: true,
    turbopackSharedRuntime: true,
  },
} satisfies NextConfig

export default nextConfig

generateComponentChunks — самая интересная идея. Каждый слитый чанк дополнительно выпускает составляющие его компонентные чанки, и во время запроса рантайм выбирает то, что дешевле: объединённый файл или только недостающие части. Работает и в обратную сторону: чанк, уже загруженный в составе слитого файла, отдельно не запрашивается.

firstPageLoadPriority и priorityRoutes заменяют общую догадку формой вашего сайта. Высокий bounce rate говорит в пользу быстрой первой загрузки, активная навигация — наоборот. В анонсе описан и параметр clusters — группы маршрутов, которые обычно посещают вместе.

Рядом с ними turbopackSharedRuntime заменяет постраничные рантайм-чанки одним общим, экономя блокирующий запрос и около 10 KB клиентского JavaScript на каждом переходе после первого. А turbopackCjsTreeShaking распространяет удаление мёртвого кода на модули CJS, которые прежде отправляли неиспользуемые импорты прямо в браузер.

Оговорки на практике

Все эти флаги экспериментальные, и документация Next.js прямо говорит, что для продакшена они пока не рекомендуются. Пороговые размеры измеряются в байтах несжатого и неминифицированного кода — примерно впятеро больше итоговой выдачи, так что minChunkSize: 50000 это не файл в 50 KB. И таблица с nextjs.org — не ваша таблица: документационный сайт с активными переходами выигрывает от меньшего слияния, одиночный лендинг — ровно от обратного. Измерьте ту сессию, которая вам важна, поменяйте одно значение, измерьте снова.

Вывод

Чанкинг — не внутренняя деталь бандлера, а ставка на поведение ваших посетителей. До сих пор эту ставку делали за вас на этапе сборки и по усреднённым допущениям. Next.js 16.3 позволяет заменить допущение собственной аналитикой и передаёт часть решения рантайму, где реальное состояние кэша уже известно.

Первоисточник: How Turbopack chunks your JavaScript. О более быстрых инструментах сборки в том же релизе — TypeScript 7: нативный компилятор, в 10 раз быстрее.