This is really tricky. There are several hurdles you face.
First hurdle: importing the Leaflet CSS files from your node_modules
folder
and incorporating this into your Webpack build.
The canonical form for this is as follows:
@import url("~leaflet/dist/leaflet.css");
The tilde is a documented but obscure shortcut for a vendored module found under
node_modules
. There's no way to avoid hardcoding the path dist/leaflet.css
.
Once you've done this, you'll have a non-broken map view, but you still won't
be able to view marker images. You'll be seeing that the CSS attempts to load
images but isn't able to load them. Then you'll try to apply file-loader
, but
due to a similar issue to one described on React,
you'll note that file-loader
or url-loader
generate broken paths with
strange hashing symbols in them.
Luckily, there's a fix for this! You'll notice this solution in the thread, from user PThomir:
import L from 'leaflet';
L.Icon.Default.imagePath = '.';
// OR
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
iconUrl: require('leaflet/dist/images/marker-icon.png'),
shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});
This is now getting very close. However, you'll try to adapt this, using
import
instead of require
, because TypeScript doesn't know about require
.
You'll get examples like this:
Cannot find module 'leaflet/dist/images/marker-icon-2x.png'
But you'll look for the file and it'll clearly be there. Puzzling. Until you
realize you've missed a key point: Webpack's require
and TypeScript's import
are completely different animals. More specifically: Only Webpack's require
knows about Webpack's loaders. So when you might try to import the PNG,
import iconRetinaUrl from 'leaflet/dist/images/marker-icon-2x.png';
This is actually intercepted by the TypeScript compiler and causes a compile
error. We need to find some way to use Webpack's require
from typescript.
Luckily this isn't too difficult. You need to create a type signature for this
call as such.
// This is required to use Webpack loaders, cf https://stackoverflow.com/a/36151803/257169
declare function require(string): any;
Put this somewhere in your search path for modules, as webpack-require.d.ts
.
Remember you don't explicitly import .d.ts
file. So now just use require
in your entry.ts
file as before.
My eventual snippet looked as follows:
const leaflet = require('leaflet');
delete leaflet.Icon.Default.prototype._getIconUrl;
const iconRetinaUrl = require('leaflet/dist/images/marker-icon-2x.png');
const iconUrl = require('leaflet/dist/images/marker-icon.png');
const shadowUrl = require('leaflet/dist/images/marker-shadow.png');
leaflet.Icon.Default.mergeOptions({ iconRetinaUrl, iconUrl, shadowUrl })
But remember, none of this will work without that .d.ts
file, otherwise tsc
is just going to wonder what the hell you mean by require
.