Современные JavaScript-библиотеки требуют предсказуемой, компактной и оптимизированной системы сборки. Rollup ориентирован на создание библиотек, где ключевым фактором становится не столько разделение кода на чанки, сколько получение максимально чистого и эффективного итогового бандла. В контексте проектов, использующих Leaflet, это особенно важно: библиотека должна оставаться легковесной, совместимой с различными форматами модулей и не дублировать зависимости в конечном пакете.
Rollup работает на основе ES Modules и выполняет статический анализ импортов, формируя граф зависимостей. Такой подход позволяет выполнять tree-shaking — удаление неиспользуемого кода на этапе сборки, что критично для библиотек визуализации и картографии.
В основе Rollup лежит идея статического анализа импортов и экспортов. В отличие от Webpack, который может работать с динамическими зависимостями более гибко, Rollup строит строго детерминированное дерево модулей.
Tree-shaking реализуется за счёт анализа:
import и export на этапе парсинга ASTДля библиотек наподобие Leaflet это особенно важно: даже небольшое сокращение итогового бандла влияет на скорость загрузки карты и инициализации интерфейса.
Ключевым условием эффективного tree-shaking является корректная настройка поля:
{
"sideEffects": false
}
в package.json, если проект не содержит побочных
эффектов при импорте модулей.
Rollup позволяет формировать несколько типов сборок из одного исходного кода:
<script>Типичная библиотека картографического уровня должна поставлять все три варианта.
Пример конфигурации output:
export default {
input: 'src/index.js',
output: [
{
file: 'dist/library.esm.js',
format: 'es',
sourcemap: true
},
{
file: 'dist/library.cjs.js',
format: 'cjs',
exports: 'named',
sourcemap: true
},
{
file: 'dist/library.umd.js',
format: 'umd',
name: 'MyMapLibrary',
sourcemap: true
}
]
};
Leaflet как сторонняя библиотека часто не должна попадать внутрь итогового бандла. В противном случае увеличивается размер пакета и возникает дублирование при использовании CDN-версий.
Rollup позволяет исключать зависимости:
export default {
input: 'src/index.js',
external: ['leaflet'],
output: {
file: 'dist/bundle.js',
format: 'esm'
}
};
В таком случае импорт Leaflet остаётся внешним:
import L from 'leaflet';
export function createMap(id) {
return L.map(id).setView([51.505, -0.09], 13);
}
При сборке библиотек поверх Leaflet это стандартная практика: Leaflet объявляется peer dependency.
Экосистема Rollup основана на плагинах, которые расширяют базовую функциональность сборщика.
Позволяет находить модули в node_modules:
import resolve from '@rollup/plugin-node-resolve';
export default {
plugins: [
resolve()
]
};
Без этого плагина Rollup не сможет корректно обрабатывать сторонние зависимости.
Leaflet и множество вспомогательных пакетов могут быть написаны в формате CommonJS. Для их поддержки используется:
import commonjs from '@rollup/plugin-commonjs';
export default {
plugins: [
commonjs()
]
};
Этот плагин преобразует require и
module.exports в ES Module-совместимый код.
Минификация итогового бандла выполняется через terser:
import { terser } from 'rollup-plugin-terser';
export default {
plugins: [
terser()
]
};
Минификация особенно важна для UMD-сборок, которые часто загружаются напрямую в браузере.
При создании расширений для Leaflet структура проекта обычно разделяется на:
Пример структуры:
src/
index.js
core/
mapFactory.js
layers/
heatmapLayer.js
utils/
geoUtils.js
Главный модуль:
import L from 'leaflet';
import { createHeatLayer } from './layers/heatmapLayer.js';
export function initAdvancedMap(container, options = {}) {
const map = L.map(container, options);
const heatLayer = createHeatLayer(options.data);
heatLayer.addTo(map);
return map;
}
Полная конфигурация обычно включает несколько уровней оптимизации:
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
const isProd = process.env.NODE_ENV === 'production';
export default {
input: 'src/index.js',
external: ['leaflet'],
output: [
{
file: 'dist/library.esm.js',
format: 'es',
sourcemap: true
},
{
file: 'dist/library.umd.js',
format: 'umd',
name: 'AdvancedLeaflet',
globals: {
leaflet: 'L'
},
sourcemap: true
}
],
plugins: [
resolve(),
commonjs(),
isProd && terser()
]
};
Ключевой момент — корректное сопоставление globals,
которое необходимо для UMD-сборок при подключении Leaflet через CDN.
Sourcemaps обеспечивают связь между исходным кодом и итоговым бандлом. В сложных библиотеках, где Leaflet взаимодействует с множеством пользовательских слоёв, это критично.
Rollup поддерживает несколько режимов:
.map файлыoutput: {
sourcemap: true
}
При разработке картографических модулей sourcemaps позволяют отлаживать поведение слоёв непосредственно в исходных файлах, а не в минифицированном коде.
Rollup поддерживает code splitting только в ESM-режиме. Однако для библиотек, интегрирующих Leaflet, часто предпочтительнее единый бандл.
Причины:
Поэтому большинство Leaflet-надстроек используют single-bundle подход.
Сложные геопространственные библиотеки часто требуют кастомной обработки данных: GeoJSON, тайлы, векторные слои.
Rollup позволяет добавлять пользовательские плагины:
function geoJsonOptimizer() {
return {
name: 'geojson-optimizer',
transform(code, id) {
if (!id.endsWith('.geojson')) return null;
const optimized = JSON.stringify(JSON.parse(code));
return {
code: `export default ${optimized};`,
map: null
};
}
};
}
Такая обработка уменьшает размер данных и ускоряет загрузку карт.
Leaflet-плагины часто подключаются как независимые модули. Rollup
позволяет управлять их интеграцией через
peerDependencies.
package.json:
{
"peerDependencies": {
"leaflet": "^1.9.0"
}
}
Это предотвращает дублирование Leaflet в итоговой сборке.
Основные стратегии оптимизации:
external)Дополнительно можно применять анализ бандла:
rollup -c --configPlugin visualizer
Это позволяет оценить вклад каждого модуля в итоговый размер.
В библиотеке может быть несколько entry points:
export default {
input: {
main: 'src/index.js',
layers: 'src/layers/index.js',
utils: 'src/utils/index.js'
}
};
Такой подход полезен, если Leaflet-надстройка предоставляет независимые модули (например, только утилиты геометрии без рендеринга карты).
Rollup часто используется совместно с:
@rollup/plugin-typescript)Пример TypeScript-интеграции:
import typescript from '@rollup/plugin-typescript';
export default {
plugins: [
typescript()
]
};
В dev-режиме Rollup обычно используется с watch:
rollup -c -w
Это позволяет автоматически пересобирать библиотеку при изменениях. Для Leaflet-расширений это важно, так как визуальные изменения слоёв требуют постоянной проверки в браузере.
Дополнительно используется локальный сервер и live reload, но сама сборка остаётся детерминированной и быстрой благодаря отсутствию избыточной упаковки модулей.
При проектировании сборки поверх Leaflet учитываются специфические требования:
Rollup обеспечивает контроль над этими аспектами за счёт прозрачного графа модулей и отсутствия скрытых рантайм-обёрток, характерных для более тяжёлых сборщиков.