Leaflet Marker not found production env

I got a problem with leaflet.

Everything is working fine in development, but in production, my app isn’t able to locate the marker-icon.png and marker-shadow.png images.

It is looking for the path assets/station/images/marker-icon.png

Leaflet js is including like this in my html.erb file

<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.5/leaflet.js"></script>

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.5/leaflet.css" />

If someone can help!

8 thoughts on “Leaflet Marker not found production env”

  1. This is a known bug in Leaflet, the root issue is that Leaflet’s icon image location is been wrongly referenced during bundling.

    You can verify that this is your issue, buy validating this parameter (in run time): L.Icon.Default.prototype._getIconUrl().
    The correct value should be <some_directory>/leaflet/dist/images/.
    However if this bug is happening to you, it’s value is: data:image/png;base64,iVBO....K5CYII=")undefined

    There are different solutions (work around) depending on which bundle-loader you are using (Vanila WebPack, Angular-Cli – superset of WebPack, etc…).

    You can see the original issue here (as well as different solutions depending on your bandle-loader):
    https://github.com/Leaflet/Leaflet/issues/4968

    If you are using Angular-Cli this solution will work for you.
    Add this code somewhere before setting the Maker:

    import { icon, Marker } from 'leaflet';
    const iconRetinaUrl = 'assets/marker-icon-2x.png';
    const iconUrl = 'assets/marker-icon.png';
    const shadowUrl = 'assets/marker-shadow.png';
    const iconDefault = icon({
      iconRetinaUrl,
      iconUrl,
      shadowUrl,
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -34],
      tooltipAnchor: [16, -28],
      shadowSize: [41, 41]
    });
    Marker.prototype.options.icon = iconDefault;
    

    (this code will change the broken Marker’s url, to a valid image from your assets folder).

    And add this code at you angular.json (for Angular version >= 6.x) or at your angular-cli.json (for Angular version <= 5.x):

    "assets":
    [
       "src/favicon.ico",
       "src/assets",
       {
          "glob": "**/*",
          "input": "node_modules/leaflet/dist/images/", // you may need to change this path, according to your files structure
          "output": "./assets/"
       }
    ] ...
    

    (this code will copy the original Marker images to the /assets folder so angular-cli could load them)

    Reply
  2. Perhaps try upgrading to current version of leaflet- I have never encountered this problem with the marker icons.

    https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.2/leaflet.css
    https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.2/leaflet.js
    
    Reply
  3. I ran into a similar issue using Parcel as the bundler in combination with TypeScript and Leaflet v1.4 (installed via npm, as well as its typings) and solved it using Gil’s answer in a slightly different way.

    import 'leaflet/dist/leaflet.css';
    import 'leaflet-draw/dist/leaflet.draw.css';
    import L, {
      LatLngExpression,
      FeatureGroup,
      TileLayerOptions,
      LayerEvent,
      LeafletMouseEvent,
      Marker,
      Layer,
      icon,
      LayerGroup,
      GeoJSON
    } from 'leaflet';
    import 'leaflet-draw';
    import iconRetinaUrl from './assets/marker-icon-2x.png';
    import iconUrl from './assets/marker-icon.png';
    import shadowUrl from './assets/marker-shadow.png';
    
    // Assign the imported image assets before you do anything with Leaflet.
    Marker.prototype.options.icon = icon({
      iconRetinaUrl,
      iconUrl,
      shadowUrl,
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -34],
      tooltipAnchor: [16, -28],
      shadowSize: [41, 41],
    });
    

    And in another file, I added the required declarations so TypeScript allows me to import png images, e.g.

    declare module "*.png" {
      const content: string;
      export default content;
    }
    

    Also notice that, in case you use a Leaflet plugin that requires access to these images, you may need to explicitly assign it too, e.g. the Leaflet draw plugin required it as well. Example:

            map.addLayer(drawLayer);
            const drawControl = new L.Control.Draw({
              draw: {
                circle: false,
                circlemarker: false,
                marker: {
                  icon: Marker.prototype.options.icon, // Assign icon explicitly
                },
              },
              edit: {
                featureGroup: drawLayer,
              },
            });
            map.addControl(drawControl);
            map.on(L.Draw.Event.CREATED, event => {
              const layer = (event as LayerEvent).layer;
              drawLayer.addLayer(layer);
            });
    
    Reply
  4. Below code worked for me

    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")
    });
    
    Reply
  5. Working in Angular 10

    For me worked copy paste PNGs files to assets and one command

    ngOnInit() { L.Icon.Default.ImagePath = "assests/leaflet/" }

    Reply
  6. @GilEpshtain ‘s answer worked for me on Angular 9.1.9.

    Additional note – for debugging purposes, you should be able to confirm that the change to angular.json#assets specified by @GilEpshtain has taken effect, by putting one of the icon URLs directly into your browser. For instance http://localhost:4200/assets/marker-icon.png should show you the marker icon.

    Reply
  7. You can change the current path of the icon in leaflet css.
    So don’t use the url leaflet.css, download the file and change it.

    .leaflet-default-icon-path {
        background-image: url(https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png);
    }
    
    Reply

Leave a Comment