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.