Closed thj-dk closed 7 years ago
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.
looks like this may be linked to https://github.com/Leaflet/Leaflet/issues/4968 and https://github.com/Leaflet/Leaflet/pull/5041
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:
@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.
For those using TypeScript with strict checks, I had to do this:
import L from 'leaflet';
delete L.Icon.Default.prototype['_getIconUrl' as any as keyof L.Icon.Default];
L.Icon.Default.mergeOptions({
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png').default,
iconUrl: require('leaflet/dist/images/marker-icon.png').default,
shadowUrl: require('leaflet/dist/images/marker-shadow.png').default
});
For anyone attempting to use leaflet in an expo react native app, the marker image also won't load. A workaround is to use expo-asset, npx expo install expo-asset
, and then place an icon in the assets folder. Then you'll need to get a uri using expo-asset
and use that as the iconUrl
for the leaflet icon.
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from "leaflet";
import { Asset } from "expo-asset";
import React from "react";
import { StyleSheet } from "react-native";
const WebMap = () => {
const icon = require('../../../assets/icon.png');
const iconURI = Asset.fromModule(icon).uri;
const leafletIcon = new L.Icon({
iconUrl: iconURI,
iconSize: [30, 30],
iconAnchor: [22, 94],
popupAnchor: [-3, -76],
});
return (
<MapContainer
center={[51.505, -0.09]}
zoom={13}
scrollWheelZoom={true}
style={styles.container}
>
<TileLayer
url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
/>
<Marker position={[51.505, -0.09]} icon={leafletIcon}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
);
};
const styles = StyleSheet.create({
container: {
width: "500px",
height: "500px",
},
});
export default WebMap;
npm install url-loader --save-dev
module.exports = { module: { rules: [ { test: /.(png|jpe?g|gif|svg)$/i, use: [ { loader: 'url-loader', options: { limit: 8192, // files smaller than 8KB will be inlined as Base64 URLs fallback: 'file-loader', // larger files will use file-loader name: 'images/[name].[hash].[ext]', }, }, ], }, ], }, };
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:
The limit of the url-loader is temporary while debugging this issue.
Any help will be much appreciated!