Работа с MapLibre GL JS в связке с Vite начинается с установки основных пакетов. В экосистеме Vite предпочтение отдаётся ESM-модулям, поэтому MapLibre GL JS подключается напрямую как модуль без дополнительных сборщиков.
npm install maplibre-gl
npm install vite
Дополнительно требуется CSS-файл библиотеки, поскольку визуальная часть карты зависит от встроенных стилей.
Базовая инициализация карты строится вокруг импорта библиотеки и контейнера DOM:
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
const map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [37.6173, 55.7558],
zoom: 10
});
Контейнер для карты создаётся в HTML:
<div id="map" style="width: 100%; height: 100vh;"></div>
Vite использует нативные ES-модули и строгую систему обработки зависимостей. MapLibre GL JS, в свою очередь, использует Web Worker для рендеринга тайлов и слоя карты. В классических сборщиках этот процесс скрыт, но в Vite требуется явная настройка worker-скрипта.
Основная проблема связана с загрузкой worker файла. При
отсутствии конфигурации карта может не отображаться или выдавать ошибки
WebGL pipeline.
MapLibre GL JS требует корректного указания пути к worker-файлу:
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
maplibregl.workerUrl = new URL(
'maplibre-gl/dist/maplibre-gl-csp-worker',
import.meta.url
).toString();
const map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [37.6173, 55.7558],
zoom: 10
});
Использование new URL(..., import.meta.url) позволяет
Vite корректно обработать worker как отдельный ассет и включить его в
сборку.
CSS MapLibre GL JS должен импортироваться как модульный ресурс:
import 'maplibre-gl/dist/maplibre-gl.css';
Vite автоматически инлайнит или выносит стили в отдельный бандл в зависимости от режима сборки.
При использовании кастомных иконок или изображений для слоёв
(например, addImage) необходимо учитывать, что пути к
ресурсам должны быть либо импортированы, либо размещены в
public директории:
map.loadImage('/icons/marker.png', (error, image) => {
if (error) return;
map.addImage('marker', image);
});
Базовая конфигурация Vite может оставаться минимальной, однако в
некоторых случаях требуется корректировка optimizeDeps для
предотвращения проблем с pre-bundling:
import { defineConfig } from 'vite';
export default defineConfig({
optimizeDeps: {
include: ['maplibre-gl']
}
});
При использовании старых версий зависимостей может возникать необходимость исключения MapLibre из оптимизации:
optimizeDeps: {
exclude: ['maplibre-gl']
}
При развертывании на поддиректории важно учитывать параметр
base в Vite-конфигурации. MapLibre GL JS загружает ресурсы
относительно текущего окружения, поэтому неправильный base может
привести к ошибкам загрузки worker и стилей.
export default defineConfig({
base: '/app/'
});
В этом случае worker URL также корректно резолвится благодаря
import.meta.url, что предотвращает необходимость ручной
настройки путей.
MapLibre GL JS предоставляет встроенные типы, поэтому интеграция с TypeScript минимально затратна.
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
const map: maplibregl.Map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [0, 0],
zoom: 2
});
Типизация событий карты позволяет безопасно работать с интерактивными слоями:
map.on('click', (e) => {
const coordinates = e.lngLat;
});
Vite поддерживает динамический импорт, что позволяет загружать MapLibre GL JS только при необходимости. Это снижает начальный размер бандла.
async function initMap() {
const maplibregl = await import('maplibre-gl');
await import('maplibre-gl/dist/maplibre-gl.css');
maplibregl.workerUrl = new URL(
'maplibre-gl/dist/maplibre-gl-csp-worker',
import.meta.url
).toString();
new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [0, 0],
zoom: 3
});
}
Такой подход часто используется в приложениях, где карта является второстепенным элементом интерфейса.
Vite предоставляет доступ к .env переменным через
import.meta.env. В контексте MapLibre GL JS это
используется для управления стилями и API endpoints.
const map = new maplibregl.Map({
container: 'map',
style: import.meta.env.VITE_MAP_STYLE_URL,
center: [30, 50],
zoom: 4
});
Пример .env:
VITE_MAP_STYLE_URL=https://example.com/style.json
MapLibre GL JS полностью совместим со спецификацией Mapbox Style. В Vite-проекте стили могут храниться локально:
import style from './style.json';
const map = new maplibregl.Map({
container: 'map',
style
});
Vite позволяет импортировать JSON напрямую как модуль, что упрощает работу с конфигурацией карты.
При работе с картой важно учитывать ошибки загрузки тайлов и стилей:
map.on('error', (e) => {
console.error('Map error:', e.error);
});
В Vite окружении такие ошибки часто связаны с неправильными путями к worker или отсутствием CORS-заголовков на сервере тайлов.
Vite в production режиме оптимизирует статические ресурсы, однако MapLibre GL JS имеет собственные механизмы кэширования тайлов и шейдеров WebGL.
Для повышения производительности используются следующие подходы:
MapLibre GL JS зависит от WebGL и window, поэтому не
совместим с SSR напрямую. В Vite-проектах с SSR требуется условная
инициализация:
if (typeof window !== 'undefined') {
import('maplibre-gl').then((maplibregl) => {
// инициализация карты
});
}
В противном случае серверная сборка будет падать из-за отсутствия браузерного окружения.
При расширении функциональности применяются дополнительные плагины Vite для работы с ресурсами:
Пример подключения SVG как модуля:
import marker from './marker.svg?url';
map.loadImage(marker, (error, image) => {
if (!error) map.addImage('marker', image);
});
После инициализации карты добавление данных осуществляется через стандартные API MapLibre:
map.on('load', () => {
map.addSource('points', {
type: 'geojson',
data: '/data/points.geojson'
});
map.addLayer({
id: 'points-layer',
type: 'circle',
source: 'points',
paint: {
'circle-radius': 6,
'circle-color': '#ff0000'
}
});
});
Vite автоматически обслуживает статические GeoJSON файлы из
public директории.
Типичная структура проекта с MapLibre GL JS включает разделение логики карты и UI:
src/
map/
map.js
layers.js
sources.js
components/
MapContainer.vue
styles/
map.css
public/
data/
icons/
Такое разделение упрощает масштабирование карты и внедрение сложных визуализаций.
Vite поддерживает HMR, однако MapLibre GL JS требует осторожности. Повторная инициализация карты без уничтожения предыдущего экземпляра приводит к утечкам памяти WebGL.
Корректный подход включает очистку:
let map;
export function initMap() {
if (map) {
map.remove();
}
map = new maplibregl.Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json'
});
}
HMR-сценарии требуют полного пересоздания canvas при изменениях модуля карты.