Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 64 additions & 7 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,7 @@ The map component also requires a **map provider** — a separate library that h

### MapLibre provider (recommended)

**ESM:** `maplibre-gl` is a peer dependency, install it separately:

```shell
npm install maplibre-gl
```

**UMD:** `maplibre-gl` is bundled — no separate install needed.
`maplibre-gl` is installed with this package (ESM) or bundled (UMD) — no separate install needed.

### ESRI provider (optional)

Expand All @@ -54,6 +48,69 @@ npm install ol proj4

**UMD:** `ol` and `proj4` are bundled — no separate install needed.

### Bundler configuration (ESM)

Some plugins work with more than one map provider. They load an adapter for your provider at runtime, and each adapter imports its own map engine. Only the adapter for your provider is ever loaded in the browser, but your bundler still builds every adapter, so it fails to resolve the engines you haven't installed:

```
Module not found: Error: Can't resolve 'ol/layer/Vector.js'
```

Tell your bundler to ignore the engines for the providers you don't use. Plugins that need this say so at the top of their documentation.

| Provider | Ignore | Pattern |
|---|---|---|
| MapLibre | `ol`, `proj4`, `@arcgis/core` | `/^(ol\|proj4\|@arcgis\/core)(\/\|$)/` |
| OpenLayers | `@arcgis/core` | `/^@arcgis\/core(\/\|$)/` |
| ESRI | `ol`, `proj4` | `/^(ol\|proj4)(\/\|$)/` |

The examples below are for the MapLibre provider. For another provider, swap in its pattern.

**Webpack**

```js
import webpack from 'webpack'

export default {
// ...
plugins: [
new webpack.IgnorePlugin({ resourceRegExp: /^(ol|proj4|@arcgis\/core)(\/|$)/ })
]
}
```

**Vite** (production builds; the dev server only warns)

```js
export default {
build: {
rollupOptions: { // rolldownOptions in Vite 8+
external: [/^(ol|proj4|@arcgis\/core)(\/|$)/]
}
}
}
```

**Rollup**

```js
export default {
// ...
external: [/^(ol|proj4|@arcgis\/core)(\/|$)/]
}
```

**esbuild**

```js
await esbuild.build({
// ...
external: ['ol', 'ol/*', 'proj4', '@arcgis/core', '@arcgis/core/*']
})
```

The ignored engines are only used by adapters for other providers, which are never loaded, so nothing is missing at runtime. If you switch provider, update the pattern to match.

## Basic usage

**ESM** — add a container element to your HTML and initialise the map in your JavaScript:
Expand Down
3 changes: 3 additions & 0 deletions docs/plugins/datasets.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The datasets plugin renders GeoJSON and vector tile datasets on the map, with su
> [!IMPORTANT]
> **Upgrading?** This plugin no longer renders key of symbols itself — that button and panel have been removed. Add the [Map Key](./map-key.md) plugin to restore it. Your `showInKey` config is unaffected and needs no changes.

> [!IMPORTANT]
> **Using a bundler (ESM)?** This plugin includes adapters for more than one map provider, so your bundler needs to ignore the map engines you haven't installed. See [Bundler configuration](../getting-started.md#bundler-configuration-esm).

## ESM usage

```js
Expand Down
5 changes: 4 additions & 1 deletion docs/plugins/draw.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Draw Plugin

The draw plugin lets users draw and edit point, polygon and line features on the map — placing vertices by click, tap, or keyboard, snapping to existing map layers, and validating geometry as it's built. Polygons can also be split and merged. It works identically with both the MapLibre and OpenLayers map providers, determining the correct adapter to use from the `mapProvider` passed to `InteractiveMap` — there's nothing to configure.
The draw plugin lets users draw and edit point, polygon and line features on the map — placing vertices by click, tap, or keyboard, snapping to existing map layers, and validating geometry as it's built. Polygons can also be split and merged. It works identically with both the MapLibre and OpenLayers map providers, determining the correct adapter to use from the `mapProvider` passed to `InteractiveMap` — there's nothing to configure in the plugin itself.

> [!IMPORTANT]
> **Using a bundler (ESM)?** This plugin includes adapters for more than one map provider, so your bundler needs to ignore the map engines you haven't installed. See [Bundler configuration](../getting-started.md#bundler-configuration-esm).

## ESM usage

Expand Down
42 changes: 18 additions & 24 deletions rollup.esm.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const PREACT_EXTERNALS = [
// dependency so it auto-installs for consumers and is resolved transparently.
const BABEL_RUNTIME_EXTERNAL = /@babel\/runtime/

const createESMConfig = (entryPath, outDir, isCore = false, manualChunks = null, extraExternals = []) => {
const createESMConfig = (entryPath, outDir, isCore = false, manualChunks = null, chunkNames = {}) => {
const esmDir = path.resolve(__dirname, outDir)
// Use the parent dir as output.dir so CSS can be emitted to css/index.css
// (a sibling subdir) without Rollup 4's ban on ".." in emitted file names.
Expand All @@ -104,12 +104,13 @@ const createESMConfig = (entryPath, outDir, isCore = false, manualChunks = null,
: [
...PREACT_EXTERNALS,
BABEL_RUNTIME_EXTERNAL,
// maplibre-gl is externalised so ESM consumers get a single shared
// instance from their own node_modules rather than a 1 MB copy bundled
// into the provider. (UMD keeps it bundled — no bundler available there.)
// Map engines (optional peers) are externalised so consumers share one copy
// from their own node_modules; they ignore the engines they don't install
// (see docs/getting-started.md). UMD keeps them bundled.
'maplibre-gl',
/^@arcgis\/core/,
...extraExternals
/^ol\//,
'proj4',
/^@arcgis\/core/
],

plugins: [
Expand Down Expand Up @@ -196,7 +197,7 @@ const createESMConfig = (entryPath, outDir, isCore = false, manualChunks = null,
// - anything else → im-shell.js (the sync InteractiveMap + shared utils chunk)
chunkFileNames: isCore
? (chunk) => chunk.name === 'initialiseApp' ? 'esm/im-core.js' : 'esm/im-shell.js'
: 'esm/[name].js',
: (chunk) => `esm/${chunkNames[chunk.name] || chunk.name}.js`,
// Rollup ignores webpack magic comments; manualChunks is how we assign
// meaningful names to lazy-loaded splits.
// Core: no manualChunks — Rollup's natural algorithm keeps shared source
Expand Down Expand Up @@ -234,7 +235,6 @@ const ALL_BUILDS = [
{
entryPath: './providers/beta/openlayers/src/index.js',
outDir: 'providers/beta/openlayers/dist/esm',
extraExternals: [/^ol\//, 'proj4'],
manualChunks: (id) => id.includes('/openlayersProvider') ? 'im-openlayers-provider' : undefined
},

Expand Down Expand Up @@ -262,13 +262,9 @@ const ALL_BUILDS = [
{
entryPath: './plugins/datasets/src/index.js',
outDir: 'plugins/datasets/dist/esm',
manualChunks: (id) => {
if (id.includes('/manifest')) { return 'im-datasets-plugin' }
if (id.includes('maplibreLayerAdapter')) { return 'im-datasets-ml-adapter' }
if (id.includes('openlayersLayerAdapter')) { return 'im-datasets-ol-adapter' }
if (id.includes('esriLayerAdapter')) { return 'im-datasets-esri-adapter' }
return undefined
}
// Adapters renamed rather than in manualChunks — see the draw build below
manualChunks: (id) => id.includes('/manifest') ? 'im-datasets-plugin' : undefined,
chunkNames: { maplibreLayerAdapter: 'im-datasets-ml-adapter', openlayersLayerAdapter: 'im-datasets-ol-adapter', esriLayerAdapter: 'im-datasets-esri-adapter' }
},
{
entryPath: './plugins/beta/map-styles/src/index.js',
Expand All @@ -278,13 +274,12 @@ const ALL_BUILDS = [
{
entryPath: './plugins/draw/src/index.js',
outDir: 'plugins/draw/dist/esm',
extraExternals: [/^ol\//],
manualChunks: (id) => {
if (id.includes('/manifest')) { return 'im-draw-plugin' }
if (id.includes('MaplibreDrawAdapter')) { return 'im-draw-ml-adapter' }
if (id.includes('OLDrawAdapter')) { return 'im-draw-ol-adapter' }
return undefined
}
// Adapters are renamed rather than put in manualChunks: manual chunks absorb their
// dependencies, which put helpers shared by both adapters inside the MapLibre one, so
// OpenLayers hosts downloaded the whole MapLibre adapter. Left to Rollup, shared
// helpers get a small chunk of their own.
manualChunks: (id) => id.includes('/manifest') ? 'im-draw-plugin' : undefined,
chunkNames: { MaplibreDrawAdapter: 'im-draw-ml-adapter', OLDrawAdapter: 'im-draw-ol-adapter' }
},
{
entryPath: './plugins/beta/draw-ml/src/index.js',
Expand All @@ -299,7 +294,6 @@ const ALL_BUILDS = [
{
entryPath: './plugins/beta/draw-ol/src/index.js',
outDir: 'plugins/beta/draw-ol/dist/esm',
extraExternals: [/^ol\//],
manualChunks: (id) => id.includes('/manifest') ? 'im-draw-ol-plugin' : undefined
},
{
Expand All @@ -326,5 +320,5 @@ const buildsToRun = BUILD_TARGET
: ALL_BUILDS

export default buildsToRun.map(b =>
createESMConfig(b.entryPath, b.outDir, b.isCore || false, b.manualChunks || null, b.extraExternals || [])
createESMConfig(b.entryPath, b.outDir, b.isCore || false, b.manualChunks || null, b.chunkNames)
)
6 changes: 5 additions & 1 deletion webpack.umd.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path, { dirname } from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs'

import webpack from 'webpack'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
import RemoveEmptyScriptsPlugin from 'webpack-remove-empty-scripts'
Expand Down Expand Up @@ -30,7 +31,10 @@ const createUMDConfig = (entryName, entryPath, libraryPath, outDir, isCore = fal
}),
new RemoveFilesPlugin({
before: { include: [path.resolve(__dirname, outDir)] }
})
}),
// There's no Esri provider in UMD, so Esri code can never run here: leave out
// @arcgis/core and the datasets Esri adapter rather than bundling ~100 MB of chunks.
new webpack.IgnorePlugin({ resourceRegExp: /^@arcgis\/core|esriLayerAdapter/ })
]

if (isCore) {
Expand Down
Loading