I was getting an error of window undefined when using react-leaflet node module because it relies on window and of course SSR does not support window. I found next/dynamic, however, all the examples I found show how to import a component and not a node module. Is it possible to include a node module and if so how? As an example this is what I'm importing that is giving the window undefined error import { Map, TileLayer, Marker } from 'react-leaflet';
5 Answers
The issue is that next.js dynamic import fails on named exports
Looking at the source code of react-leaflet I can see that each named export can be accessed from a particular file e.g. import Map from 'react-leaflet/lib/Map'
Combine it with dynamic import without SSR
const Map = dynamic(() => import('react-leaflet/lib/Map'), {
ssr: false
});
This should do a trick for you.
6 Comments
dynamic(() => import('package-name').then((module) => module.NamedExport))A better way of getting named exports with a dynamic import is to do this:
const NamedExport = dynamic(() => import('package-name').then((module) => module.NamedExport));
Note: this will chunk the full 'package-name' package and then simply extract the named export. If you are able to path into the module package like the accepted example, that will probably be better as it will likely give you a smaller chunk.
2 Comments
I kept hitting type definition issues with the accepted answer, and I didn't want to import the whole library. This is what I came up with:
reexport/index.ts:
export { Marker, /* any other type you'll need */ } from 'react-leaflet';
Then, in your component/page, simply import anything from the module above.
const Marker = useMemo(() => dynamic<MarkerProps>(
() => import('./reexport').then(re => re.Marker),
{ ssr: false }
), []);
Note that I've wrapped the call to dynamic in a useMemo hook, and also provided a type for the props.
Comments
That error happened when you call that dependency's component (Map, TileLayer, Marker) on your component.
Window of undefined occured when your application is being rendered on server side, because window object is belong to the browser.
To avoid error of window of undefined on server side, you can use process.browser in your component.
ref: https://github.com/zeit/next.js/issues/2473?#issuecomment-362119102
Comments
for me, none of the simple solutions worked. but this one did.
"use client"
import React from "react"
import { hasWindow } from "std-env"
import { useStore } from "@/app/store/zustand"
export function Fingerprint() {
const { setFingerprint } = useStore()
React.useEffect(() => {
async function fn() {
if (hasWindow) {
const { getFingerprint } = await import("@thumbmarkjs/thumbmarkjs")
const visitorId = await getFingerprint()
setFingerprint(visitorId)
}
}
fn()
}, [setFingerprint])
return null
}