Skip to content

Оптимизация загрузки и бандла. Изоляция сущностей tenant’ов

Одна потребность: (1) уменьшить размер начальной загрузки и время до интерактивности за счёт code splitting и ленивой загрузки; (2) не допустить, чтобы сущности (конфигурация, код, данные) одной компании (tenant) попадали в бандл или в контекст другой — критично для мультитенантности и безопасности.

Зачем это нужно (мировой опыт)

  • Performance: большие монолитные бандлы увеличивают время загрузки и парсинга; code splitting по маршрутам и по фичам — стандарт (Webpack/Vite chunks, dynamic import). Core Web Vitals и UX напрямую зависят от размера начального бандла.
  • Multi-tenancy и изоляция: в SaaS и enterprise платформах данные и конфигурация одного tenant не должны быть доступны другому. Утечка в бандл означает, что при загрузке приложения для компании A в JavaScript или в предзагруженных данных может оказаться конфигурация компании B — нарушение конфиденциальности и регуляторики (GDPR и др.).
  • Лучшие практики: конфигурация tenant подгружается после идентификации (после логина или по домену); код, специфичный для фичи/модуля, загружается лениво; общий код — в shared chunks без привязки к tenant.

Текущее состояние

  • Маршруты: компоненты страниц загружаются лениво (() => import('@/features/...')), что даёт разбиение по маршрутам. Админка, расписание, рейсы, логин и т.д. — отдельные чанки.
  • Vite: один entry, chunks формируются по динамическим импортам; нет явного разделения «базовый бандл» и «tenant-specific» или «feature-specific» чанки по политике.
  • Данные и конфигурация: домен (проекты, типы, запросы и т.д.) загружается с бэкенда после инициализации; если в ответ API попадают данные только текущего tenant и бэкенд не отдаёт чужие — утечки через сеть нет. Риск — если конфигурация или данные какого-то tenant попадут в статику (например, в build-time подстановку) или в один общий чанк с данными нескольких tenant’ов.
  • Сборка: нет разделения сборки «по tenant’ам» (отдельный бандл под каждую компанию); приложение одно, tenant определяется в рантайме (логин, домен, заголовок). Поэтому изоляция должна обеспечиваться тем, что в бандл не попадают подставляемые на сборке данные другого tenant’а, а все tenant-specific данные приходят только через API после определения контекста.

Что сделать

1. Запретить подстановку tenant-данных в бандл на сборке

  • Никакие идентификаторы tenant’ов, конфигурация конкретной компании, персональные или конфиденциальные данные не должны подставляться в код на этапе сборки (например, через env или генерируемый конфиг) так, чтобы они попали в общий бандл. Если используется сборка «под tenant» (редкий кейс), артефакты сборки должны быть строго разделены по tenant’ам и не смешиваться при раздаче.
  • Конфигурация и данные tenant — только из API (или из runtime env после аутентификации). Проверка при code review и при аудите: в репозитории и в артефактах сборки нет хардкода tenant-id и чужих данных.

2. Code splitting и ленивая загрузка

  • Критичный путь: только то, что нужно для первого экрана и для проверки auth/health. Остальное — динамический import по маршруту или по фиче (админка, тяжёлые отчёты, графические и специфичные модули). Уже используется для страниц; расширить на тяжёлые виджеты и библиотеки (например, Monaco и тяжёлые графики), если они не на первом экране.
  • Именованные чанки (Vite: manualChunks или комментарии /* webpackChunkName: "admin" */) для предсказуемого разбиения: base, vendor (Vue, router, общие библиотеки), admin, preview и т.д. Так сущности одной фичи/приложения не «перетекают» в чанк другой без необходимости.
  • Избегать импорта всего tenant-специфичного конфига в корне приложения; подгружать конфиг/словари после определения tenant (после логина или после чтения контекста из API).

3. Разделение по фичам и приложениям

  • Модули фич (features) импортировать лениво там, где они нужны. Не делать в корне один импорт «все фичи», иначе бандлер соберёт их в один чанк или в главный бандл. Так «сущности одной компании» в смысле фичи (например, модуль заказчика A) не попадут в бандл заказчика B, если у B эта фича не подключена — при условии, что подключение фич тоже идёт через динамический импорт по конфигурации.
  • Если в одном инстансе приложения несколько независимых фич: каждая со своими маршрутами и чанками; общий код — в shared. Проверить, что при входе в одну фичу не подгружаются тяжёлые чанки другой, пока пользователь туда не перешёл.

4. Аудит и процесс

  • В регламент сборки и деплоя включить проверку: в артефактах нет tenant-id и конфиденциальных данных; при необходимости — автоматический скрипт поиска паттернов (tenant id, имена компаний) в сгенерированных чанках.
  • Документировать для разработчиков: не класть в статику и в env на сборке данные, зависящие от tenant; tenant-specific — только через API после определения контекста.

Риски и ограничения

  • Избыточный code splitting увеличивает число запросов при навигации; баланс между размером начального бандла и количеством чанков. Аудит на утечку tenant-данных в артефакты нужно включить в CI; при сборке «под tenant» артефакты должны храниться и раздаваться строго раздельно.

Вывод

  • Изоляция tenant’ов: никаких подстановок tenant-данных в бандл на сборке; конфигурация и данные tenant — только из API в рантайме. Аудит артефактов и процесса.
  • Оптимизация бандла: критичный путь минимален; остальное — code splitting по маршрутам и фичам, ленивая загрузка тяжёлых модулей, именованные чанки для предсказуемого разбиения.
  • Сущности одной компании (фичи, модули) не перетекают в чанк другой за счёт ленивых импортов и отсутствия общих статических данных tenant’ов в бандле.