Chartjs plugin zoom Reference error: window is not defined

381 views Asked by At

In Nextjs application while I'm run the command for build and export there was an ReferenceError

I've attached the screenshot for your reference..

When remove the import of chartjs-plugin-zoom from the project, the build and export works properly.. enter image description here

3

There are 3 answers

2
skorphil On

This is because nextjs by default use server-side rendering. And zoom-plugin requires window object, but it is not available since the component is rendered on a node.

To make work component which relies on browser API , next/dynamic import can be used

chart-with-zoom.jsx

import zoomPlugin from 'chartjs-plugin-zoom'; // require window in order to be imported

ChartJS.register(zoomPlugin)

export default function ChartZoom() {
...

app.jsx

import dynamic from 'next/dynamic';

const ChartZoom = dynamic(() => import('PATH TO chart-with-zoom'), {
  ssr: false, // Disable server-side rendering
});

...
return <ChartZoom />
0
Ayush_Raj On

So I found a solution to this problem after putting my brains. Here it goes

Suppose you are importing the "chartjs-plugin-zoom" in page.tsx then move all the code to a component name lets call ComponentA.tsx and then import this component in page.tsx dynamically and also wrap it with a NoSSR component. Example code Page.tsx

   "use client";
import React from "react";
import NoSSR from "./components/NoSSR";
import dynamic from "next/dynamic";
const ComponentA = dynamic(() => import("./components/ComponentA"), {
    ssr: true,
});

const Page = () => {
    return (
        <NoSSR>
            <ComponentA />
        </NoSSR>
    );
};

export default Page;

NoSSR.tsx

import * as React from "react";

const useEnhancedEffect =
    typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;

type Props = {
    defer?: boolean;
    fallback?: JSX.Element;
    children: React.ReactNode;
};
/**
 * NoSSR purposely removes components from the subject of Server Side Rendering (SSR).
 *
 * This component can be useful in a variety of situations:
 * - Escape hatch for broken dependencies not supporting SSR.
 * - Improve the time-to-first paint on the client by only rendering above the fold.
 * - Reduce the rendering time on the server.
 * - Under too heavy server load, you can turn on service degradation.
 */
function NoSSR(props: Props) {
    const { children, defer = false, fallback = null } = props;
    const [mountedState, setMountedState] = React.useState(false);

    useEnhancedEffect(() => {
        if (!defer) {
            setMountedState(true);
        }
    }, [defer]);

    React.useEffect(() => {
        if (defer) {
            setMountedState(true);
        }
    }, [defer]);

    // eslint-disable-next-line react/jsx-no-useless-fragment
    return <>{mountedState ? children : fallback}</>;
}

export default NoSSR;
0
Begatim On

In my case, I had to slightly modify the solution from skorphil. If you try to register the zoom plugin outside the component you will still get the same error. That's why you need to do it inside the component as following:

useEffect(() => {
if (typeof window !== "undefined")
  import("chartjs-plugin-zoom").then((plugin) => {
    ChartJS.register(plugin.default);
  });
}, []);

This makes sure that the plugin code will not run in the server.