Минификация стилей

Минификация стилей в контексте MapLibre GL JS представляет собой комплекс приёмов, направленных на уменьшение размера JSON-описания карты, ускорение его загрузки и снижение нагрузки на сеть и парсер браузера. Стиль в MapLibre GL JS — это структурированный JSON-документ, описывающий источники данных, слои, фильтры, выражения, шрифты и ресурсы отображения. Даже небольшие неоптимизированные стили могут достигать сотен килобайт, а в сложных приложениях — нескольких мегабайт.

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


Структура стиля как объект оптимизации

Стиль MapLibre GL JS включает несколько ключевых блоков:

  • sources — источники данных (vector, raster, geojson)
  • layers — визуальные слои
  • sprite — набор иконок
  • glyphs — шрифты
  • paint и layout свойства
  • выражения (expressions)
  • фильтры (filters)

Каждый из этих элементов может быть источником избыточности:

  • дублирование источников
  • неиспользуемые слои
  • повторяющиеся выражения
  • неэффективные фильтры
  • избыточные свойства paint/layout

Базовая JSON-минификация

Первый уровень оптимизации — синтаксическая минификация JSON:

  • удаление пробелов и переносов строк
  • удаление форматирования
  • устранение комментариев (если стиль генерируется вручную или через preprocessor)

Пример трансформации:

{
  "version": 8,
  "sources": {
    "osm": {
      "type": "vector",
      "url": "..."
    }
  }
}

становится:

{"version":8,"sources":{"osm":{"type":"vector","url":"..."}}

На практике это выполняется через:

  • сборщики (Webpack, Vite)
  • специализированные JSON minifier’ы
  • build pipeline (CI/CD)

Удаление неиспользуемых слоёв и источников

Один из наиболее эффективных способов уменьшения размера — устранение «мертвого» контента.

Типичные проблемы:

  • слои, не используемые в текущем интерфейсе
  • источники данных, подключённые «на будущее»
  • тестовые слои, оставшиеся в production

Оптимизация включает:

  • анализ layer.id
  • проверку связей source-layer
  • удаление orphan-слоёв

Особенно критично в больших стилях, где количество слоёв может превышать 200–500 элементов.


Оптимизация выражений (Expressions)

Выражения в MapLibre GL JS часто становятся скрытым источником избыточности.

Примеры проблем:

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

Пример неоптимального выражения:

"opacity": [
  "case",
  ["==", ["get", "type"], "road"], 1,
  ["==", ["get", "type"], "path"], 0.8,
  0.5
]

Оптимизация заключается в:

  • объединении условий через match
  • вынос общих вычислений в отдельные свойства
  • упрощении логики на уровне данных (preprocessing GeoJSON/vector tiles)

Сокращение и нормализация фильтров

Фильтры слоёв (filter) часто содержат избыточные конструкции:

  • повторяющиеся проверки
  • лишние all / any
  • вложенные условия без необходимости

Пример упрощения:

["all",
  ["==", ["get", "class"], "primary"],
  ["!=", ["get", "type"], "tunnel"]
]

может быть заменён на более компактную форму при предварительной нормализации данных.


Оптимизация sprite и glyph ресурсов

Sprite

Sprite-файл содержит набор иконок в одном изображении + JSON-описание координат.

Минификация включает:

  • удаление неиспользуемых иконок
  • агрегацию повторяющихся символов
  • пересборку atlas’а
  • переход на более плотную упаковку (packing algorithm)

Результат — уменьшение PNG/WebP и JSON-индекса.

Glyphs

Шрифтовые тайлы часто оказываются одним из самых тяжёлых ресурсов.

Оптимизация:

  • ограничение набора символов (subset fonts)
  • использование только необходимых Unicode диапазонов
  • генерация pre-baked glyph sets
  • переход на динамическую подгрузку по языкам

Упрощение источников данных

Каждый source добавляет:

  • сетевой запрос
  • метаданные
  • потенциальные зависимости слоёв

Оптимизация:

  • объединение vector tilesets
  • устранение дублирующих источников
  • переход на один универсальный source с несколькими source-layer

Сжатие стиля на уровне транспорта

После логической минификации применяется транспортное сжатие:

  • Gzip
  • Brotli (предпочтительно)

Brotli обеспечивает более высокую степень сжатия JSON благодаря:

  • повторяющимся ключам (paint, layout, type)
  • предсказуемой структуре стилей
  • длинным строковым значениям (URL, expression keys)

Компиляция стиля через build pipeline

В production-системах стиль редко хранится как «сырой JSON».

Используются промежуточные этапы:

  • TypeScript/JS генерация стиля
  • шаблонизация (theme-based styles)
  • постобработка (minify + validate)
  • оптимизация ресурсов (sprite/glyph builder)

Пайплайн позволяет:

  • удалять неиспользуемые темы
  • генерировать региональные стили
  • адаптировать стиль под zoom ranges

Оптимизация zoom-dependent слоёв

Слои с диапазонами minzoom / maxzoom могут дублироваться.

Проблемы:

  • одинаковые стили на разных zoom уровнях
  • копирование слоёв вместо параметризации

Оптимизация:

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

Сокращение paint/layout свойств

Каждый слой может содержать десятки свойств:

  • fill-color
  • line-width
  • text-size
  • icon-image

Оптимизация:

  • удаление дефолтных значений
  • вынос общих стилей в базовые слои
  • использование inheritance через type grouping

Лексическая нормализация ключей

JSON-стиль MapLibre GL JS содержит большое количество повторяющихся строковых ключей.

Оптимизация:

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

Это повышает эффективность gzip/brotli, так как повторяемость строк возрастает.


Контроль размера итогового style.json

В production важно отслеживать:

  • общий размер style.json
  • количество слоёв
  • количество выражений
  • размер sprite
  • размер glyph set

Практические ориентиры:

  • простой стиль: < 100 KB
  • средний: 100–500 KB
  • сложный: до 1–2 MB (без ресурсов)

Оптимизация часто даёт снижение размера на 40–80% без визуальных потерь.


Декомпозиция стиля как стратегия минификации

Крупные стили целесообразно разделять:

  • базовый стиль (base map)
  • тематические оверлеи
  • динамические слои (runtime injection)

Это снижает:

  • размер initial load
  • количество обязательных слоёв
  • сложность кеширования

Итеративная проверка результата

После минификации проверяются:

  • корректность рендеринга слоёв
  • отсутствие визуальных артефактов
  • консистентность zoom-уровней
  • загрузка ресурсов sprite/glyph

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