Публикация и распространение плагинов

Плагины для OpenLayers представляют собой самостоятельные модули, расширяющие базовую функциональность библиотеки без изменения её ядра. Экосистема расширений строится вокруг принципов модульности, совместимости версий и предсказуемого подключения зависимостей. При публикации и распространении ключевую роль играет корректная упаковка, описание API, управление зависимостями и стратегия версионирования.

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

Типовая структура:

  • расширение источников данных (Source)
  • кастомные слои (Layer)
  • взаимодействия (Interaction)
  • утилиты проекции и преобразований
  • визуальные оверлеи (Overlay)

Главная идея — не дублировать функциональность ядра, а подключаться к его жизненному циклу через публичные API.

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

Структура npm-пакета

Распространение плагинов для OpenLayers чаще всего осуществляется через Node.js и npm-экосистему.

Базовая структура пакета:

  • src/ — исходный код
  • dist/ — собранные артефакты
  • package.json — метаданные пакета
  • README.md — документация
  • types/ или встроенные .d.ts — типы TypeScript
  • test/ — тесты
  • rollup.config.js / vite.config.js / webpack.config.js — конфигурация сборки

Ключевые поля package.json:

  • name — уникальное имя (желательно scoped: @scope/ol-plugin-name)
  • version — версия по SemVer
  • main — CommonJS точка входа
  • module — ES module сборка
  • types — TypeScript декларации
  • sideEffects — управление tree-shaking
  • peerDependencies — зависимость от OpenLayers
  • exports — современная карта экспорта модулей

Управление зависимостями и peerDependencies

Критически важно не включать OpenLayers внутрь бандла плагина. Библиотека должна поставляться как peerDependency.

Пример:

  • peerDependencies:

    • ol: >=7.0.0

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

Неправильный подход — добавление OpenLayers в dependencies, что приводит к увеличению bundle size и возможным runtime конфликтам.

ES Modules и система экспорта

Современные плагины ориентируются на ES Modules.

Рекомендуемая структура экспорта:

  • именованные экспорты для функций и классов
  • отдельные entry points для тяжелых модулей
  • поддержка tree-shaking

Пример exports:

{
  "exports": {
    ".": {
      "import": "./dist/index.esm.js",
      "require": "./dist/index.cjs.js"
    },
    "./layer": "./dist/layer.esm.js",
    "./interaction": "./dist/interaction.esm.js"
  }
}

Это позволяет импортировать только нужные части плагина:

import { CustomLayer } from 'ol-plugin';

или

import { CustomInteraction } from 'ol-plugin/interaction';

Сборка и бандлинг

Наиболее распространённый инструмент — Rollup.

Цели сборки:

  • генерация ESM и CJS артефактов
  • минимизация
  • удаление неиспользуемого кода
  • сохранение совместимости с tree-shaking

Типичная конфигурация включает:

  • @rollup/plugin-node-resolve
  • @rollup/plugin-commonjs
  • rollup-plugin-terser
  • typescript или babel

Особое внимание уделяется external-зависимостям:

external: ['ol']

Это предотвращает включение OpenLayers в итоговый bundle.

TypeScript поддержка

Большинство современных плагинов поставляются с типизацией.

Подходы:

  • написание кода сразу на TypeScript
  • генерация .d.ts через tsc
  • использование composite projects для монорепозиториев

Типы должны точно отражать API OpenLayers, особенно:

  • Map
  • View
  • Layer
  • Source
  • Feature

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

Совместимость версий

Плагины строго привязаны к версиям OpenLayers.

Практика:

  • мажорная версия плагина соответствует диапазону OL
  • фиксируется диапазон peerDependencies
  • ведётся compatibility matrix

Пример:

  • plugin v2.x → OpenLayers 7.x
  • plugin v3.x → OpenLayers 8.x

Любые breaking changes в OpenLayers требуют пересмотра API плагина.

Публикация в npm

Процесс публикации включает:

  • проверку сборки
  • запуск тестов
  • обновление версии (npm version)
  • публикацию через npm publish

Для scoped-пакетов:

npm publish --access public

Важно соблюдать:

  • уникальность имени
  • корректность semver
  • наличие README и лицензии

Распространение через GitHub

Параллельно с npm часто используется GitHub:

  • релизы (Releases)
  • теги версий
  • changelog
  • issue tracker
  • CI через GitHub Actions

Релиз обычно включает:

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

CDN-дистрибуция

Для быстрых подключений используются CDN-сервисы:

  • unpkg
  • jsDelivr

Плагин должен предоставлять UMD-сборку:

window.OlPluginName

Однако UMD рассматривается как вторичный формат, основной — ESM.

Документация API

Документация должна описывать:

  • назначение каждого модуля
  • параметры конструкторов
  • события
  • зависимости от Map lifecycle

Структура:

  • описание установки
  • примеры использования
  • API reference
  • ограничения
  • примеры интеграции с существующей картой

Пример важного раздела — интеграция с Map:

  • добавление слоя
  • подключение взаимодействия
  • удаление ресурсов

Тестирование

Плагины требуют многоуровневого тестирования:

  • unit-тесты (логика)
  • integration-тесты (с OpenLayers Map)
  • визуальные тесты (рендеринг)

Инструменты:

  • Jest / Vitest
  • Playwright (для визуальной проверки)
  • headless canvas окружения

Особое внимание уделяется:

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

CI/CD пайплайн

Автоматизация включает:

  • линтинг (ESLint)
  • тесты
  • сборку
  • проверку типов
  • публикацию

Стандартный pipeline:

  1. checkout
  2. install
  3. test
  4. build
  5. release

Часто используется semantic-release для автоматического управления версиями.

Безопасность и устойчивость

Плагины должны исключать:

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

Также важно:

  • контроль входных GeoJSON данных
  • защита от перегрузки feature-массивами
  • ограничение частоты перерисовки

Нейминг и организация пакетов

Рекомендуется:

  • scoped packages (@org/ol-*)
  • единообразные префиксы
  • ясная семантика имени

Примеры:

  • @gis/ol-cluster-layer
  • @maptools/ol-draw-enhancer

Имя должно отражать тип расширения и его назначение.

Пример структуры плагина

src/
  index.ts
  layer/
    CustomLayer.ts
  interaction/
    SelectInteraction.ts
  utils/
    projection.ts
dist/
types/
package.json
README.md

Основной entry:

export { CustomLayer } from './layer/CustomLayer';
export { SelectInteraction } from './interaction/SelectInteraction';

Поддержка расширяемости

Хорошо спроектированный плагин предусматривает:

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

События часто реализуются через расширение стандартного event system OpenLayers.

Версионирование и миграции

Миграции оформляются через:

  • changelog
  • migration guides
  • deprecated API warnings

Удаление функций происходит только в мажорных версиях.

Экосистема и взаимодействие плагинов

Плагины должны быть совместимыми между собой:

  • отсутствие конфликтов глобальных стилей
  • независимые namespace событий
  • отсутствие монополии на Map instance

В крупных системах плагины собираются в единый registry, где определяется порядок инициализации и приоритет взаимодействий.