@import и разрешение зависимостей в стилях

Parcel рассматривает стили как полноценные узлы графа зависимостей. Любой CSS-файл, SCSS или Less превращается в модуль, который может импортировать другие стили, ресурсы и даже JavaScript-артефакты через связанный пайплайн трансформаций. В этом контексте директива @import перестаёт быть простым текстовым включением и становится частью системы сборки, где каждый импорт формирует отдельную вершину графа.

Модель графа зависимостей стилей

При обработке стилей Parcel строит dependency graph, где каждый файл представляет модуль, а @import создаёт ребро зависимости.

Пример:

/* main.css */
@import "./reset.css";
@import "./components/button.css";

body {
  font-family: sans-serif;
}

На уровне исполнения это не означает буквальную вставку текста файлов. Parcel:

  • распознаёт директивы @import
  • создаёт отдельные узлы для reset.css и button.css
  • связывает их с main.css как зависимости
  • обрабатывает каждый файл через соответствующий трансформер (PostCSS, CSS parser и т.д.)

Результат — не конкатенация строк, а сборка графа, который затем оптимизируется.

Отличие от традиционного поведения CSS @import

В классическом браузерном CSS @import:

  • выполняется на этапе загрузки страницы
  • блокирует рендеринг
  • создаёт каскад HTTP-запросов
  • имеет ограниченные возможности оптимизации

Parcel полностью переносит разрешение импорта на этап сборки:

  • запросы отсутствуют в runtime
  • зависимости инлайнуются или бандлятся
  • порядок подключения контролируется графом
  • возможна оптимизация и дедупликация

Таким образом, @import перестаёт быть механизмом загрузки и становится декларацией зависимости.

Разрешение путей и поиск модулей

Parcel поддерживает несколько типов путей в @import:

Относительные пути

@import "./base/typography.css";
@import "../shared/grid.css";

Алгоритм:

  • путь вычисляется относительно текущего файла
  • создаётся ссылка на конкретный модуль
  • модуль добавляется в граф без дополнительного поиска

Импорт из node_modules

@import "normalize.css";
@import "bootstrap/dist/css/bootstrap.css";

Parcel:

  • ищет пакет в node_modules
  • разрешает package.json (main/module/exports)
  • подключает соответствующий CSS-файл
  • добавляет его как внешний модуль в граф

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

Интеграция с PostCSS и современным CSS

Parcel использует PostCSS как часть пайплайна, поэтому поведение @import может зависеть от конфигурации:

  • PostCSS может преобразовывать или расширять импорты
  • плагины могут добавлять вложенные правила
  • поддерживается современный CSS @import с условными расширениями

Parcel различает:

  • CSS @import как зависимость сборки
  • PostCSS-обработанные импорты как трансформации AST

В результате импорт проходит через несколько стадий:

  1. Парсинг CSS
  2. Построение AST
  3. Разрешение импортов
  4. Создание графа
  5. Трансформация через плагины
  6. Финальная генерация бандла

Инлайнинг и объединение файлов

Parcel по умолчанию стремится минимизировать количество HTTP-запросов. Поэтому CSS-зависимости:

  • либо инлайнуются в итоговый файл
  • либо объединяются в общий CSS-бандл
  • либо разделяются по чанкам при code splitting

Пример:

/* main.css */
@import "./header.css";
@import "./footer.css";

После сборки может быть получен единый файл:

/* bundle.css */
.header { ... }
.footer { ... }
body { ... }

При этом логическая структура зависимостей сохраняется внутри графа, даже если физически код объединён.

Динамические стили и code splitting

Parcel поддерживает разделение CSS по точкам входа. Если стили импортируются через разные JS-модули, граф становится многослойным:

import "./styles/admin.css";
import "./styles/public.css";

Каждый импорт создаёт отдельную ветку графа. Parcel:

  • анализирует точки входа
  • выделяет общие стили
  • формирует отдельные CSS чанки
  • предотвращает дублирование правил

Это особенно важно при масштабных приложениях, где разные страницы используют пересекающиеся стили.

Разрешение url() внутри CSS и связь с @import

Помимо @import, Parcel обрабатывает и другие зависимости в стилях:

@import "./theme/dark.css";

.button {
  background-image: url("./icons/plus.svg");
}

Здесь формируется два типа зависимостей:

  • CSS dependency (через @import)
  • asset dependency (через url())

Parcel унифицирует их в одном графе, где:

  • CSS-файлы становятся узлами модулей
  • изображения и шрифты становятся asset-узлами
  • все пути переписываются на итоговые хэши файлов

Хеширование и кэширование стилей

Каждый CSS-модуль получает:

  • контентный хэш
  • ссылку на зависимости
  • версию трансформаций

При изменении одного импортируемого файла:

  • пересобирается только затронутая ветка графа
  • остальные стили берутся из кэша
  • HMR обновляет только изменённые части

Это делает @import не затратным, несмотря на его потенциальную вложенность.

CSS Modules и @import

При использовании CSS Modules поведение @import становится более контекстным:

/* button.module.css */
@import "./base.module.css";

.button {
  composes: base from "./base.module.css";
}

Parcel:

  • изолирует локальные классы
  • предотвращает утечки имён
  • сохраняет зависимости между модулями
  • применяет хеширование классов после разрешения импортов

Таким образом, @import остаётся на уровне структуры, а namespace-изоляция применяется позже.

Особенности обработки вложенных импортов

Цепочки импортов:

/* a.css */
@import "./b.css";

/* b.css */
@import "./c.css";

Parcel:

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

Циклические зависимости не приводят к бесконечным циклам — граф фиксируется при первом посещении узла.

Условные импорты и современные расширения CSS

Хотя стандартный CSS не поддерживает условные @import, в экосистеме Parcel могут использоваться:

  • PostCSS-плагины
  • препроцессоры (Sass, Less)
  • environment-specific трансформации

Пример Sass:

@import "theme/light";
@import "theme/dark";

Parcel:

  • делегирует разрешение Sass-компилятору
  • получает итоговый AST
  • строит единый граф зависимостей уже после компиляции

Оптимизация и удаление неиспользуемых стилей

Parcel анализирует:

  • достижимость CSS-модулей
  • использование через JS-импорты
  • наличие в entry points

Если файл не попадает в граф достижимости, он исключается из бандла. Это делает @import безопасным с точки зрения избыточных подключений при корректной архитектуре приложения.

Взаимодействие @import и Hot Module Replacement

При HMR:

  • изменение импортируемого CSS-модуля
  • пересборка только затронутого узла
  • обновление зависимых модулей
  • инъекция новых стилей в DOM без полной перезагрузки

Parcel отслеживает цепочку импортов, поэтому изменение в глубоко вложенном файле автоматически поднимается вверх по графу до точки входа.

Итоговая модель поведения @import в Parcel

Внутри системы сборки:

  • @import — это декларация зависимости
  • каждый импорт — ребро в графе
  • стили рассматриваются как модульная система
  • разрешение путей унифицировано с JavaScript-импортами
  • финальный CSS формируется после полной оптимизации графа

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