Сборка с использованием webpack

Архитектура клиентской сборки

MapLibre GL JS использует Web Workers, динамическую загрузку ресурсов и WebGL-контекст, поэтому интеграция с bundler требует корректной настройки обработки модулей, worker-скриптов и статики. В webpack-проекте ключевыми становятся:

  • точка входа приложения (entry)
  • корректная обработка maplibre-gl как ESM/CommonJS зависимости
  • настройка загрузки worker-файлов
  • подключение CSS-стилей библиотеки
  • управление статическими ресурсами (sprites, glyphs, style.json)

Установка зависимостей

Базовый набор пакетов включает саму библиотеку и инструменты сборки:

npm install maplibre-gl
npm install -D webpack webpack-cli webpack-dev-server
npm install -D babel-loader @babel/core @babel/preset-env
npm install -D css-loader style-loader

При использовании TypeScript дополнительно подключается:

npm install -D typescript ts-loader

Базовая конфигурация webpack

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

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  devServer: {
    static: './dist',
    port: 8080
  },
  module: {
    rules: []
  }
};

Подключение MapLibre GL JS в проект

Библиотека импортируется как модуль:

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
});

Обработка CSS MapLibre GL JS

CSS библиотеки содержит стили для контролов, canvas и popups. Без корректной загрузки интерфейс карты отображается некорректно.

Настройка webpack:

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
};

Обработка Web Workers

MapLibre GL JS активно использует Web Workers для рендеринга тайлов и обработки стилей. В webpack 5 применяется встроенная поддержка worker через new URL.

module.exports = {
  module: {
    rules: [
      {
        test: /maplibre-gl.*\.js$/,
        type: 'asset/resource'
      }
    ]
  }
};

Более надёжный подход — явное указание worker source:

import maplibregl from 'maplibre-gl';

maplibregl.workerUrl = new URL(
  'maplibre-gl/dist/maplibre-gl-csp-worker.js',
  import.meta.url
);

При использовании CommonJS:

maplibregl.workerUrl = require('maplibre-gl/dist/maplibre-gl-csp-worker.js');

Альтернативная настройка worker-loader (устаревающий подход)

В старых конфигурациях используется worker-loader:

npm install -D worker-loader
{
  test: /maplibre-gl.*\.js$/,
  use: { loader: 'worker-loader' }
}

Подключение стилей карты и ресурсов

MapLibre GL JS зависит от внешних ресурсов:

  • sprites (иконки)
  • glyphs (шрифты)
  • tiles (векторные тайлы)

Пример style.json:

{
  "version": 8,
  "sources": {
    "osm": {
      "type": "vector",
      "tiles": ["https://tiles.example.com/{z}/{x}/{y}.pbf"]
    }
  },
  "sprite": "https://tiles.example.com/sprite",
  "glyphs": "https://tiles.example.com/fonts/{fontstack}/{range}.pbf",
  "layers": []
}

При локальной разработке часто требуется проксирование или копирование ресурсов в dist.

Использование copy-webpack-plugin

Для статических файлов:

npm install -D copy-webpack-plugin
const CopyPlugin = require('copy-webpack-plugin');

module.exports = {
  plugins: [
    new CopyPlugin({
      patterns: [
        { from: 'public', to: '' }
      ]
    })
  ]
};

Оптимизация сборки

MapLibre GL JS является достаточно тяжёлой библиотекой, поэтому важны:

Tree shaking

Webpack 5 поддерживает ESM, что позволяет удалять неиспользуемый код при корректном импорте.

module.exports = {
  optimization: {
    usedExports: true,
    splitChunks: {
      chunks: 'all'
    }
  }
};

Разделение чанков

Вынос maplibre-gl в отдельный бандл:

optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]maplibre-gl[\\/]/,
        name: 'maplibre',
        chunks: 'all'
      }
    }
  }
}

Работа с TypeScript

Конфигурация ts-loader:

module: {
  rules: [
    {
      test: /\.ts$/,
      use: 'ts-loader',
      exclude: /node_modules/
    }
  ]
},
resolve: {
  extensions: ['.ts', '.js']
}

Пример инициализации:

import maplibregl from 'maplibre-gl';

const map: maplibregl.Map = new maplibregl.Map({
  container: 'map',
  style: 'https://demotiles.maplibre.org/style.json'
});

Алиасы и совместимость модулей

Иногда требуется принудительно указать ESM-версию:

resolve: {
  alias: {
    'maplibre-gl': 'maplibre-gl/dist/maplibre-gl.js'
  }
}

Обработка ошибок сборки

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

Worker не загружается

Причина — отсутствие корректного workerUrl. Решение:

maplibregl.workerUrl = new URL(
  'maplibre-gl/dist/maplibre-gl-csp-worker.js',
  import.meta.url
);

Отсутствие CSS

Причина — не подключён style-loader/css-loader.

Ошибки WebGL

Причина — отсутствие поддержки GPU или неправильный контекст canvas.

Использование режима production

module.exports = {
  mode: 'production',
  devtool: 'source-map'
};

Минификация уменьшает размер bundle, но важно сохранять source maps для отладки WebGL-логики.

Интеграция с HTML-шаблоном

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
};

HTML:

<div id="map" style="width: 100%; height: 100vh;"></div>

Производительность и загрузка

При работе с MapLibre GL JS в webpack-сборке критичны:

  • кэширование чанков
  • CDN для тайлов и glyphs
  • ленивое подключение дополнительных слоёв
  • минимизация JSON style-файлов

Эффективная структура бандла снижает время инициализации карты и ускоряет первый рендер WebGL-контекста.