23

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 5

22

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.

Sign up to request clarification or add additional context in comments.

6 Comments

Hi @iurii, I am facing the same issue, except I'm using three.js in next.js. I want to load the example module called TrackballControls, I want to import it like an es6 module in my useEffect function. I've tried using dynamic import without ssr inside my useEffect function (or i'm not sure if I have to use it in the beginning and then somehow call it later in the useEffect). And my issue is, it is a constructor object which I need to import, so how do I use it like a constructor instead of a react component?
This is the latest link to the dynamic import feature on the nextjs readme github.com/zeit/next.js#dynamic-import
this is not a solution that works for every module. Isn't it in any way supported by next? This is a critical feature.
A better way of getting named exports is dynamic(() => import('package-name').then((module) => module.NamedExport))
The answer from @WillP. should be the correct answer
|
17

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

Seems its not for packages? github.com/vercel/next.js/discussions/…
If only god allowed me to find your comment sooner instead of me breaking my head on why this code wasnt working
3

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

1

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

0

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.