How do I import to import L from "leaflet" in Next.js?

Viewed 1146

As I am bringing in leaflet into my development in next js , it doesnt support server side rendering (ssr) , therefore i have to import the library like this and off the ssr

import React, {Component} from "react";
import dynamic from 'next/dynamic';


const L = dynamic(
    () => import("leaflet/"),
    { ssr: false }
)


const Map = dynamic(
    () => import("react-leaflet/lib/Map"),
    { ssr: false }
)

const Marker = dynamic(
    () => import("react-leaflet/lib/Marker"),
    { ssr: false }
)
const TileLayer = dynamic(
    () => import("react-leaflet/lib/TileLayer"),
    { ssr: false }
)

const Popup = dynamic(
    () => import("react-leaflet/lib/Popup"),
    { ssr: false }
)


var myIcon = L.icon({
  iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png',
  iconSize: [38, 95],
  iconAnchor: [22, 94],
  //popupAnchor: [-3, -76],
  //shadowUrl: 'my-icon-shadow.png',
  //shadowSize: [68, 95],
  //shadowAnchor: [22, 94]
});

class Benemap extends Component {


    state = {
        lat: 1.3521,
        lng: 103.8198,
        zoom: 13,
      }
    //  var myIcon = L.icon({
    //    iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png',
    //    iconSize: [38, 95],
    //    iconAnchor: [22, 94],
    //    popupAnchor: [-3, -76],
    //});


    render () {
        const position = [this.state.lat, this.state.lng]
        return (
            //<h1>Hi!</h1> 
            <Map className="map" center={position} zoom={this.state.zoom}>
            <TileLayer
              attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
              url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
            />
            <Marker position={position}
            icon = {myIcon}
            >
              <Popup>
                A pretty CSS3 popup. <br /> Easily customizable.
              </Popup>
            </Marker>
          </Map>
        );
    }

}

export default Benemap; 

Well wanted to create an Icon.....


const L = dynamic(
    () => import("leaflet/"),
    { ssr: false }
)

var myIcon = L.icon({
  iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png',
  iconSize: [38, 95],
  iconAnchor: [22, 94],
  //popupAnchor: [-3, -76],
  //shadowUrl: 'my-icon-shadow.png',
  //shadowSize: [68, 95],
  //shadowAnchor: [22, 94]
});

but Next.js showed me this Issue, once i run the local development server

I am sure other people are facing the same problem as me, but i cant to seem to find other solution to this problem online, therefore I am posting it here for the benefit for others once and for all....

Update 22/11/2020, found the solution, thanks to Antoni Kepinski

....
import dynamic from 'next/dynamic';
....

#I dynamic imported the components instead (That require client side rendering), ssr as false, this way I can work with the client components and import the dependencies as usual, not like the initial code where I have to dynamically import the dependencies one by one. 

Only downside to this is that the client side components will render slower than the server side components.

const Benemap = dynamic(() => import('../components/analytics/Benemap'), {
    loading: () => 'Loading...',
    ssr: false,
});

// use back with auth
export default withAuth(function Home({ initialState, secondinitialState }) {
    console.log('one');
    const isAuthenticated = useIsAuthenticated();
    const name = getName();
    const role = getRole();
    console.log(name);
    
    //console.log(initialState);
    //console.log(secondinitialState);
    return (
        <div className='flex flex-col h-screen'>
            <Header />
            <SubHeader name={name} role={role} />
            <div className='antialiased bg-gray-200 flex-grow'>
                <Graph1 data={initialState} />
                <Benemap name={name} />
                <Graph2 anotherdata={secondinitialState} />
            </div>

            <Footer />
        </div>
    );
});
2 Answers

Change:

const L = dynamic(
    () => import("leaflet/"),
    { ssr: false }
)

To:

import('leaflet').then(obj => L)

The Next.js dynamic import only works with React Components. Therefore I would recommend to use the pure dynamic import (not the one from next/dynamic).

Related