Recently I was working on a custom touring map for an article on Local Memory. The site is built with Gatsby, and I use Leaflet for mapping. I use React-Leaflet for some convenience with treating the Leaflet maps as React components.
The problem comes when running gatsby build
. In the Node.js environment, there is no window
object, and Webpack fails to build the first page it encounters where a React-Leaflet Map
component is rendered.
The fix is to make a check against the window
object in the page’s render()
function before using a Map
component:
render() {
if (typeof window !== 'undefined') {
return (
<div ref={this.mapWrapperRef} className="map-wrapper">
<Map ref={this.mapRef}
style={{height: '540px'}}
>
<TileLayer
url="https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png"
attribution='© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
/>
</Map>
</div>
);
}
return null;
}
This was enough to avoid the Webpack error, but the problem was that the map would intermittently fail to display in the built version.
The problem was returning null
from the render()
function which meant that there was not an element in the DOM to mount the map on when it was ready. Outputting an empty wrapper <div>
rather than nothing at all from the render()
function when not in a browser environment satisfies both conditions.
render() {
return (
<div ref={this.mapWrapperRef} className="map-wrapper">
{(typeof window !== 'undefined') ? (
<Map ref={this.mapRef}
style={{height: '540px'}}
>
<TileLayer
url="https://tiles.wmflabs.org/bw-mapnik/{z}/{x}/{y}.png"
attribution='© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
/>
</Map>
) : null}
</div>
);
}
A related Webpack related build error can be fixed with the following in your gatsby-node.js
so that the build doesn’t fail on pages that import react-leaflet
because of the absence of a browser environment:
exports.onCreateWebpackConfig = ({ stage, rules, loaders, actions }) => {
switch (stage) {
case 'build-html':
actions.setWebpackConfig({
module: {
rules: [
{
test: /react-leaflet/,
use: [loaders.null()]
}
]
}
});
break;
}
};