This is about the compatibility issue between Webpack and Leaflet. As you may already know (github Issue, SO-Question1, SO-Question2 npm plugin against the issue, ngx-leaflet readme) leaflet manipulates its URLs to images in a way that is incompatible with webpack. If left unfixed they produce nonsense urls such as http://localhost:8000/static/frontend/marker-icon.2b3e1faf89f94a483539.png%22)marker-icon.png
as opposed to http://localhost:8000/static/frontend/marker-icon.2b3e1faf89f94a483539.png
. I can fix this with some solutions on my dev-environment, but not in my prod builds.
I have a single component that does nothing else but build a leaflet map. I have tried the given answers, I have tried the plugin, I remain without markers in my builds.
What should I be doing? What is my mistake?
My Setup
Generally I seek to deploy angular on a django backend server. All urls under "/api" belong to the Backend API, all urls under "/frontend" belong to my Angular frontend.
Leaflet is imported in my angular.json
, but only its js file.
//angular.json
...
"styles": [
"src/styles.scss",
"node_modules/font-awesome/css/font-awesome.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.js",
"node_modules/popper.js/dist/umd/popper.js",
"node_modules/leaflet/dist/leaflet.js",
"node_modules/tinymce/tinymce.min.js"
]
...
Sidenote: I am currently not using ngx-leaflet as I didn't see a reason to. I did however read up on fixes that were using ngx-leaflet as the issue lies in the general webpack-leaflet interaction as far as I understand it.
In my component I import leaflet with import * as L from "node_modules/leaflet";
as well as its Marker class specifically with import { Marker } from 'leaflet';
.
Using none of the fixes below I get markers on ng serve
, but not in ng build --prod
.
Now to my results for every solution. I looked at every solution with both ng serve
and ng build --prod
, the latter of which I ran on the dev-environment for my django backend server. Bar solution 3 they always had the same results:
1. Use leaflet-defaulticon-compatibility-plugin
//leaflet-map.component.ts
import { Marker } from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.webpack.css'; // Re-uses images from ~leaflet package
import * as L from "node_modules/leaflet";
import 'leaflet-defaulticon-compatibility';
This changed the url to the standard marker to "undefined":
Markers did not load at all.
2. Explicitly set default icon image resource
//leaflet-map.component.ts
import { Marker } from 'leaflet';
import * as L from "node_modules/leaflet";
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 caused parts of the URL to be replaced by an object:
Identical behaviour in prod. The markers did load, you could see an outline of where the image was supposed to be with a "file not found" symbol.
3. Add the leaflet images to the assets and reference them directly in the icon (also suggested in the ngx-leaflet Readme)
//leaflet-map.component.ts
import { Marker } from 'leaflet';
import * as L from "node_modules/leaflet";
...
//My function to create markers on my map
createDefaultMarker(mapMarker: MapMarker): Marker{
return L.marker([mapMarker.latitude, mapMarker.longitude], {
iconSize: [ 25, 41 ],
iconAnchor: [ 13, 41 ],
iconUrl: 'assets/marker-icon.png',
shadowUrl: 'assets/marker-shadow.png'
})
//angular.json
...
"assets": [
"src/favicon.ico",
"src/assets",
{ "glob": "**/*", "input": "node_modules/tinymce", "output": "/tinymce/" },
{ "glob": "**/*", "input": "node_modules/leaflet/dist/images", "output": "assets/"}
],
...
On ng serve: Markers themselves are visible. Fails at loading marker-shadow.png from the wrong url and without the necessary hashes in the name:
On ng build --prod: Has the nonsense URLs for marker_icon and marker_shadow: