React-leaflet: Issues importing leaflet.css when using webpack

Created on 18 Nov 2016  路  23Comments  路  Source: PaulLeCam/react-leaflet

I'm seeing a strange issue when importing node_modules/leaflet/dist/leaflet.css, and it's most likely related to my webpack configuration.

When loading a map with a marker, I'm seeing the following GET request:
http://localhost:9091/2273e3d8ad9264b7daa5bdbf8e6b47f8.png%22)marker-icon.png

What appends %22)marker-icon.png? If I remove that and request the URL, the image is there. So webpack has the correct image bundled, i presume.

Here's our webpack loader configurations:

module: {
  loaders: [
    {
      test: /\.js$/,
      loaders: ['babel'],
      exclude: /node_modules/,
      include: __dirname
    },
    {
      test: /\.json$/,
      loader: "json-loader"
    },
    {
      test: /\.(sass|scss)$/,
      loaders: ['style', 'css', 'resolve-url', 'sass?sourceMap']
    },
    {
      test: /\.css$/,
      loaders: ['style', 'css'],
    },
    {
      test: /\.(woff2?|ttf|eot|jpe?g|png|gif|svg)$/,
      loader: 'url?limit=1'
    }
  ]
}

The limit of the url-loader is temporary while debugging this issue.

Any help will be much appreciated!

Most helpful comment

My solution to solve this problem:

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'),
});

but if anybody has some nicer solution, please share :)

All 23 comments

I have the same issue. But previously it worked. I just updated react-leaflet and it started to work as mentioned in the comment above.

Leaflet changed the way it loads image assets based on the CSS URL, please refer to their documentation as there is no specific logic regarding the CSS and assets in this lib.

I'm aware. I haven't been able to locate this issue in their docs, and I thought that most people here used it with webpack, so I was hoping that some could share a solution.

My solution to solve this problem:

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'),
});

but if anybody has some nicer solution, please share :)

Thanks for the workaround, @PTihomir. I had to go with the delete L.Icon.Default.prototype._getIconUrl; option; doing L.Icon.Default.imagePath = '.'; resulted in a . being prepended to a data URI (e.g. .data:img/png;base64......), probably due to something in my webpack config.

Closing as it's not an issue that can be fixed in this lib

Closing as it's not an issue that can be fixed in this lib

Maybe a warning or something like that in the README?

I guess most people using react-leaflet will use Webpack and will run into the same problem, loosing quite some of time to find the reason (like me)...

Thank you @PTihomir, this worked:

import L from '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'),
});

I used @PTihomir solution, but had to change the import statement to a require variable. I also had to use the delete method as the '.' prepended the path with a '.' and the problem remained.

var L = require('leaflet');

Hope this saves someone else some time.

You need to use file-loader for webpack.

@yoursdearboy mind getting more specific? What options do I put where?

@yoursdearboy more details would indeed be appreciated. I am using file-loader (I couldn't even build w/o adding it in b/c of the leaflet CSS), but still have the error we're all dealing with here. Did you figure out a different way to get this working?

Hi @Harti @knackjason. I've made a demo to investigate this issue. See the 2nd and 3rd commits for errors descriptions and solutions.

I think the problem here is with file name generation (specifically with hash). Removing it is a major
downside of this solution. I'd like to ask webpack community for help and provide this demo but didn't have time yet.

@yoursdearboy ah, ok. I see what you doing.

I combined your idea with the workaround above and have this working with Leaflet 1.3.1 and Webpack 4.8.2:

webpack.config.js

...
module: {
...
    {
        test: /\.(png|svg|jpg|gif)$/,
        use: [{
            loader: 'file-loader',
            options: {
                name:'img/[name]_[hash:7].[ext]',
            }
        }]
    }]
},
...

app.js

import L from 'leaflet';

import 'leaflet/dist/leaflet.css';

// stupid hack so that leaflet's images work after going through webpack
import marker from 'leaflet/dist/images/marker-icon.png';
import marker2x from 'leaflet/dist/images/marker-icon-2x.png';
import markerShadow from 'leaflet/dist/images/marker-shadow.png';

delete L.Icon.Default.prototype._getIconUrl;

L.Icon.Default.mergeOptions({
    iconRetinaUrl: marker2x,
    iconUrl: marker,
    shadowUrl: markerShadow
});

```

@knackjason Doesn't @PTihomir solution work without this? I'd like to understand why the hash is broken.

@yoursdearboy ah, yes that is the case. The extra Webpack config is unnecessary. I'm still pretty new to Webpack, so ... yeah.

I read through a bunch of Leaflet issues related to this issue the other day. Some of them explain what's going on with the hash getting messed up. These two have most of the information that I was able to track down. It's pretty sad to me that this has been an issue for 2 years now.

https://github.com/Leaflet/Leaflet/issues/4968
https://github.com/Leaflet/Leaflet/pull/5771

Thank you @knackjason, you saved a me a good hour of debugging!

@georgiana-gligor @PTihomir is really the one you should be thanking. I'm glad you didn't have to spend the time debugging though. :smile:

I experienced a s similar issue in my mithril-leaflet component. Although @PTihomir's approach solved the problem, it also requires all users to perform such actions before using the map component, which is not very elegant.

As an alternative approach, you may consider the following:

  • In my leaflet-map component, I perform the same actions as @PTihomir does.
  • In my build step (using webpack), I declare leaflet (and mithril) as external so webpack won't complain about missing libraries. This also means that I my component does not have a dependency on Leaflet nor Mithril (which can be a good thing, so new versions of Leaflet do not require an update of my component, as long as it doesn't break anything).
  • Finally, the application using my component also needs to import Leaflet as well as my component.

@PTihomir Thanks a lot. Despite solutions by others still it is the best approach.

I still have this issue with current version using create-react-app. @knackjason solution (changes on app.js only) works. Please reopen issue.

I used what @knackjason added to his app.js file in my app/javascript/packs/application.js file in a Rails 6 app. I didn't make his webpack.config.js additions anywhere. My Rails app has no Node.js, Vue.js, React.js or similar. Leaflet installed with Yarn.

Thank you and to whomever else helped get this worked. I also posted to help others dealing with Rails Webpacker startup issues.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

acpower7 picture acpower7  路  4Comments

fborghi picture fborghi  路  3Comments

josdejong picture josdejong  路  4Comments

mrafei picture mrafei  路  4Comments

samankhademi picture samankhademi  路  3Comments