Lazy mode: ленивая компиляция в dev

При разработке крупных приложений время запуска dev-сервера и скорость пересборки становятся критически важными факторами. По мере роста количества модулей Parcel вынужден анализировать всё больше файлов, строить граф зависимостей и выполнять преобразования для каждого ресурса. Даже несмотря на высокую производительность Parcel, в больших проектах первоначальная сборка может занимать заметное время.

Для решения этой проблемы в Parcel предусмотрен Lazy mode — режим ленивой компиляции, при котором сборка выполняется только для тех частей приложения, которые реально используются в данный момент.


Назначение Lazy mode

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

  1. Запускается dev-сервер.
  2. Parcel анализирует точки входа.
  3. Строится полный граф зависимостей.
  4. Компилируются все необходимые бандлы.
  5. Браузер получает готовые ресурсы.

Даже если разработчик работает лишь с одной страницей приложения, Parcel всё равно подготавливает весь набор ресурсов, связанных с проектом.

Lazy mode меняет эту стратегию.

Вместо предварительной компиляции всего проекта Parcel:

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

Такой подход значительно сокращает время запуска dev-сервера.


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

Предположим, приложение содержит несколько независимых страниц:

src/
├── index.html
├── admin.html
├── profile.html
└── reports.html

При стандартном запуске:

parcel serve src/*.html

Parcel подготовит ресурсы для всех страниц.

В режиме Lazy:

parcel serve src/*.html --lazy

происходит следующее:

  1. Сервер запускается практически сразу.
  2. Ни одна страница не компилируется заранее.
  3. Пользователь открывает index.html.
  4. Только теперь начинается сборка ресурсов для этой страницы.
  5. Остальные страницы остаются несобранными до первого обращения.

Если затем открыть:

/admin.html

Parcel выполнит отдельную компиляцию только для административной части проекта.


Активация режима

Для запуска используется флаг:

parcel serve src/index.html --lazy

или

parcel src/index.html --lazy

После запуска все бандлы становятся ленивыми по умолчанию.


Поведение при первом запросе

Рассмотрим последовательность событий.

Запуск сервера:

parcel serve src/index.html --lazy

Открытие страницы в браузере:

http://localhost:1234

В этот момент:

  1. Браузер отправляет запрос.
  2. Parcel обнаруживает отсутствие собранного бандла.
  3. Запускается компиляция.
  4. Формируется результат.
  5. Ресурс передаётся клиенту.

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

Все последующие обращения используют уже готовый результат.


Взаимодействие с кэшем

Lazy mode тесно связан с системой кэширования Parcel.

После первой компиляции:

index.js

результат сохраняется в кэше.

Повторный запрос:

index.js

не требует новой сборки.

Если файл изменяется:

console.log("Updated");

Parcel инвалидирует соответствующую часть кэша и выполняет пересборку только изменённых модулей.

Таким образом достигается сочетание:

  • ленивой компиляции;
  • инкрементальной сборки;
  • постоянного кэширования.

Работа с несколькими точками входа

Наиболее заметный эффект Lazy mode проявляется в проектах с большим количеством entry points.

Например:

src/
├── public/
│   ├── home.html
│   ├── catalog.html
│   ├── contacts.html
│   └── blog.html
│
├── admin/
│   ├── dashboard.html
│   ├── users.html
│   └── reports.html
│
└── account/
    ├── login.html
    └── profile.html

Запуск:

parcel serve "src/**/*.html" --lazy

В обычном режиме Parcel начал бы компиляцию ресурсов для всех страниц.

В Lazy mode:

  • открытие home.html не вызывает сборку административных страниц;
  • открытие dashboard.html не затрагивает блог;
  • сборка выполняется исключительно по факту обращения.

Для крупных монорепозиториев это может сокращать время старта в несколько раз.


Lazy mode и динамический импорт

Parcel отлично работает с динамическими импортами.

Пример:

button.addEventListener("click", async () => {
  const module = await import("./chart.js");
  module.renderChart();
});

Без Lazy mode Parcel заранее подготавливает все необходимые чанки.

С Lazy mode процесс становится ещё более отложенным:

  1. Страница открывается.
  2. Основной бандл собирается.
  3. Файл chart.js не компилируется.
  4. Пользователь нажимает кнопку.
  5. Браузер запрашивает чанк.
  6. Parcel собирает его при первом обращении.

В результате одновременно работают два механизма оптимизации:

  • code splitting;
  • ленивая компиляция.

Разница между Lazy mode и code splitting

Эти технологии часто путают.

Code Splitting

Разделяет приложение на несколько файлов.

Пример:

import("./admin.js");

Результат:

main.js
admin.js

Загрузка происходит по требованию.

Lazy Mode

Не влияет на структуру бандлов.

Он определяет момент их компиляции.

Даже если чанк уже существует логически в графе зависимостей, Parcel не станет его собирать до реального запроса.


Влияние на время запуска

Представим приложение:

5000 модулей
50 страниц
200 динамических чанков

Стандартный режим:

Запуск сервера
↓
Построение графа
↓
Компиляция всех бандлов
↓
Готовность

Lazy mode:

Запуск сервера
↓
Построение графа
↓
Готовность
↓
Компиляция только по запросу

Чем больше проект, тем ощутимее разница.


Влияние на потребление памяти

Предварительная сборка большого количества ресурсов требует хранения:

  • промежуточных AST;
  • исходных карт зависимостей;
  • результатов трансформаций;
  • выходных артефактов.

При использовании Lazy mode количество одновременно обработанных ресурсов уменьшается.

Следствия:

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

Использование в монорепозиториях

Монорепозитории часто содержат:

apps/
packages/
shared/
tools/
docs/

Приложение может включать десятки независимых веб-интерфейсов.

Например:

parcel serve apps/*/index.html --lazy

При таком подходе разработчик открывает только один сервис:

apps/shop

Parcel не тратит ресурсы на:

apps/admin
apps/docs
apps/analytics
apps/crm

пока они не будут запрошены.


Ограничения Lazy mode

Несмотря на преимущества, существуют особенности, которые необходимо учитывать.

Более медленный первый запрос

Первая загрузка ресурса включает время компиляции.

Например:

Request
↓
Compile
↓
Response

Из-за этого первая загрузка страницы может оказаться заметно медленнее.


Не подходит для измерения производительности

Lazy mode предназначен исключительно для разработки.

Для оценки реальной производительности приложения необходимо использовать production-сборку:

parcel build

или запускать dev-сервер без ленивой компиляции.


Возможность скрытых ошибок

Если часть приложения не открывалась во время работы:

/settings

Parcel может никогда не собрать соответствующий код.

Ошибка в этом разделе проявится только после первого обращения.

По этой причине перед релизом необходимо проверять все маршруты приложения.


Совместимость с HMR

Lazy mode полностью совместим с Hot Module Replacement.

После первой сборки модуля:

export const version = 1;

изменение файла:

export const version = 2;

вызывает обычный цикл HMR:

  1. обнаружение изменения;
  2. пересборка затронутого модуля;
  3. отправка обновления клиенту;
  4. обновление страницы без полной перезагрузки.

Поведение системы горячей замены остаётся прежним.


Сценарии, где Lazy mode особенно полезен

Крупные корпоративные приложения

CRM
ERP
Backoffice
Admin Panel

Сотни страниц редко используются одновременно.


Многомодульные платформы

Analytics
Billing
Reports
Support
Marketing

Каждый раздел компилируется независимо.


Микрофронтенды

host
catalog
checkout
profile
payments

Отдельные части системы собираются только по факту обращения.


Проекты с большим количеством динамических импортов

await import("./editor.js");
await import("./charts.js");
await import("./reports.js");
await import("./pdf.js");

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


Комбинирование с другими возможностями Parcel

Lazy mode особенно эффективен вместе с:

  • файловым кэшем Parcel;
  • Hot Module Replacement;
  • динамическими импортами;
  • code splitting;
  • множественными точками входа;
  • монорепозиторной структурой проекта.

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


Практический пример

Структура проекта:

src/
├── index.html
├── admin.html
├── profile.html
├── index.js
├── admin.js
└── profile.js

Запуск:

parcel serve src/*.html --lazy

Сценарий работы:

Старт сервера
↓
Открытие index.html
↓
Сборка index.js
↓
Работа с главной страницей
↓
Открытие profile.html
↓
Сборка profile.js
↓
Открытие admin.html
↓
Сборка admin.js

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