
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
leaflet-node
Advanced tools
Leaflet for Node.js - Run Leaflet maps in headless Node environments with full TypeScript support
Leaflet-node brings the full Leaflet map API to Node.js so you can render maps without a browser.
Reuse the same map setup for server-side image generation, automated tests, and CI pipelines.
@napi-rs/canvasleaflet ^1.9.0npm install leaflet-node leaflet
yarn add leaflet-node leaflet
pnpm add leaflet-node leaflet
bun add leaflet-node leaflet
import L from 'leaflet-node';
const container = document.createElement('div');
container.style.width = '600px';
container.style.height = '400px';
const map = L.map(container);
map.setView([51.505538, -0.090005], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
map.setSize(600, 400);
await new Promise((resolve) => setTimeout(resolve, 1000));
await map.saveImage('map.png');
Leaflet-node can run inside Jest with either the default jsdom environment for API-only tests or the node environment for full canvas rendering.
Use the default environment and mock Leaflet to avoid creating a native canvas:
// tests/setup.ts
import { jest } from '@jest/globals';
const L = require('leaflet-node');
jest.doMock('leaflet', () => L);
Switch to the node environment so leaflet-node can provide its own jsdom instance and native canvas bindings:
/**
* @jest-environment node
*/
import L from 'leaflet-node';
test('render map', async () => {
const container = document.createElement('div');
const map = L.map(container);
map.setView([51.505538, -0.090005], 13);
map.setSize(512, 512);
await map.saveImage('map.png');
});
Tile Loading Warnings:
You may see warnings about "dynamic import callback" or "experimental-vm-modules" when running tests with tile layers in Jest. This is a Jest limitation with VM modules and doesn't affect the actual rendering—tiles that load successfully are rendered correctly.
To suppress these warnings, you can:
NODE_OPTIONS='--experimental-vm-modules' jest
// jest.config.js
export default {
testEnvironment: 'node',
globals: {
'ts-jest': {
isolatedModules: true
}
}
};
[!TIP] Need a ready-to-use map in tests?
leaflet-node/testingexposescreateTestMap,cleanupTestMaps,waitForTiles, andwaitForMapReadyhelpers that work in both Vitest and Jest.
import { createTestMap, waitForMapReady } from 'leaflet-node/testing';
const map = createTestMap({ width: 400, height: 300 });
await waitForMapReady(map);
Maps can be exported to disk or kept in-memory:
// Save to disk with optional encoder options
await map.saveImage('map.jpeg', { format: 'jpeg', quality: 0.85 });
// Get a Buffer for further processing
const pngBuffer = await map.toBuffer('png');
If you need full control of the canvas, use map.toBuffer() and write the result yourself:
import { promises as fs } from 'fs';
const buffer = await map.toBuffer('png');
await fs.writeFile('map.png', buffer);
Wait for tiles (with optional progress callbacks) before exporting:
import { waitForTiles } from 'leaflet-node/testing';
const layer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
layer.addTo(map);
await waitForTiles(layer, {
timeout: 60_000,
onProgress: ({ loaded, total }) => {
console.log(`Loaded ${loaded}/${total} tiles`);
},
});
Or wait for every tile layer on a map at once:
import { waitForMapReady } from 'leaflet-node/testing';
await waitForMapReady(map, {
onTileProgress: (layer, progress) => {
console.log(layer.getAttribution(), progress);
},
});
📚 View the full documentation and live examples at jburnhams.github.io/leaflet-node.
Leaflet-node automatically attempts to register the bundled Noto Sans fallback fonts. In
environments where document.currentScript is unavailable (for example, Node.js test
runners without a DOM shim), you can provide an explicit path to the font assets to
avoid warning messages:
process.env.LEAFLET_NODE_FONT_BASE_PATH = '/absolute/path/to/NotoSans-Regular.ttf';
const L = await import('leaflet-node');
Alternatively, you can set the base path programmatically after importing the package:
import L, { setFontAssetBasePath } from 'leaflet-node';
setFontAssetBasePath('/absolute/path/to/NotoSans-Regular.ttf');
The base path can point directly to a font file or to a directory containing the
bundled NotoSans-Regular.ttf asset.
Leaflet-node honours standard proxy environment variables:
export HTTPS_PROXY=http://proxy.example.com:8080
export HTTP_PROXY=http://proxy.example.com:8080
Set them before running exports to route tile downloads through your proxy.
L.map() for every render.Promise.all() when your server has headroom.map.remove() and drop references once you are done with a map so Node.js can reclaim resources.Questions? Open an issue on GitHub.
FAQs
Leaflet for Node.js - Run Leaflet maps in headless Node environments with full TypeScript support
We found that leaflet-node demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.