Next.js Discord

Discord Forum

window is not defined

Answered
Korean bullhead posted this in #help-forum
Open in Discord
Avatar
Korean bullheadOP
Hi, i'm currently having a bug in my codebase, where NextJs tells me, that window is not defined. But I'm having a hard time to find what causes this error

The Problem is, that somehow the code does throw an error, but I can use my frontend as expected. The webapp is accessible and not showing any signs of errors. The Error only occurs in the logs. This is the error
Answered by MikeTheTechLead
Try loading it in using the dynamic ssr false trick
View full answer

57 Replies

Avatar
Korean bullheadOP
⨯ ReferenceError: window is not defined
    at __webpack_require__ (E:\distributed-rules-engine\frontend\.next\server\webpack-runtime.js:33:43)
    at __webpack_require__ (E:\distributed-rules-engine\frontend\.next\server\webpack-runtime.js:33:43)
    at __webpack_require__ (E:\distributed-rules-engine\frontend\.next\server\webpack-runtime.js:33:43)
    at __webpack_require__ (E:\distributed-rules-engine\frontend\.next\server\webpack-runtime.js:33:43)
    at __webpack_require__ (E:\distributed-rules-engine\frontend\.next\server\webpack-runtime.js:33:43)
    at eval (./src/components/data-editor/components/function/function.tsx:12:71)
    at (ssr)/./src/components/data-editor/components/function/function.tsx (E:\distributed-rules-engine\frontend\.next\server\app\app\alarms\new\page.js:1019:1)
    at __webpack_require__ (E:\distributed-rules-engine\frontend\.next\server\webpack-runtime.js:33:43)
    at eval (./src/components/data-editor/components/function/index.ts:5:67)
    at (ssr)/./src/components/data-editor/components/function/index.ts (E:\distributed-rules-
....
 GET /app/alarms/new 500 in 319ms
However it always refers to line 12 in my file, which is this import

import { functionDefinitions } from './helpers/libs';

this functionDefinitions includes raw import from libs

/* eslint-disable */
// @ts-ignore
import bigJs from '@types/big.js/index.d.ts?raw';
// @ts-ignore
import dayjs from 'dayjs/index.d.ts?raw';

// @ts-ignore
import defaultFn from './default-function.js?raw';
// @ts-ignore
import globalDts from './global.d.ts?raw';
// @ts-ignore
import http from './http.d.ts?raw';
// @ts-ignore
import zen from './zen.d.ts?raw';
// @ts-ignore
import zod from './zod.d.ts?raw';

export const functionDefinitions = {
  libs: {
    dayjs,
    'big.js': bigJs,
    zod,
    http,
    zen,
  },
  globals: {
    'global.d.ts': globalDts,
  },
};

export const defaultFunctionValue = defaultFn;

However it seems like this works too. I even adapted my nextjs config with a raw-loader
webpack: (config) => {
    config.module.rules.push({
      test: /\.(js|ts|d.ts)$/,
      resourceQuery: /raw/, // Only apply this rule if ?raw is present in the import query
      use: 'raw-loader',
    });

    return config;
  },


Would be really happy if someone knows what the problem is and might help me with it
Avatar
Can you post the code of /app/alarms/new?
Avatar
Korean bullheadOP
Sure, one moment
Avatar
American black bear
search for where you use the window. api then do a check before you use it, if it's undefined then return
Avatar
Korean bullheadOP
@American black bear I have done that already. Everything is checked against typeof undefined
Avatar
American black bear
can you share the functions in which you use the window api?
Avatar
Korean bullheadOP
app/alarms/new
'use client'
// removed imports because of file size
const NewAlarm = () => {

    const router = useRouter();
    const [currentTab, setCurrentTab] = useState<number>(0);
    const [nextButtonDisabled, setNextButtonDisabled] = useState<boolean>(false);

    const nextTab = () => {
        if (currentTab != newAlarmSteps.length - 1) {
            setCurrentTab(currentTab + 1);
        }
    }

    const previousTab = () => {
        if (currentTab != 0) {
            setCurrentTab(currentTab - 1);
        }
    }

    const save = () => {
        router.push("/app/alarms");
    }

    return (
        <div className="w-full h-full flex flex-col">
            <div className="w-full flex justify-center py-4 px-4 md:px-8">
                <Stepper steps={newAlarmSteps} currentStep={currentTab}/>
            </div>
            <div className="w-full h-full overflow-y-auto">
                {currentTab === 0 && <EventTab setNextButtonDisabled={setNextButtonDisabled} />}
                {currentTab === 1 && <DataEditorTab />}
                {currentTab === 2 && <RuleEditorTab />}
            </div>
            {currentTab !== newAlarmSteps.length - 1 && <Button onClick={() => nextTab()} disabled={nextButtonDisabled} className="fixed bottom-4 right-8">Next</Button>}
            {currentTab === newAlarmSteps.length - 1 && <Button onClick={() => save()} className="fixed bottom-4 right-8">Save</Button>}
            {currentTab !== 0 && <Button onClick={() => previousTab()} className="fixed bottom-4 left-8 md:right-28 md:left-auto">Previous</Button>}
        </div>
    )
}

export default NewAlarm;
DataEditorTab.tsx
import { DecisionGraph, DecisionGraphRef, JdmConfigProvider } from '@/components/data-editor';
import { DecisionContent } from '@/components/data-editor/helpers/graph';
import { useRef, useState } from 'react';

const DataEditorTab = () => {
  const graphRef = useRef<DecisionGraphRef>(null);

  const [graph, setGraph] = useState<DecisionContent>({ nodes: [], edges: [] });

  return (
    <div className="w-full h-full">
      <JdmConfigProvider>
        <DecisionGraph
          ref={graphRef}
          value={graph}
          onChange={(value) => setGraph(value)}
          reactFlowProOptions={{ hideAttribution: true }}
        />
      </JdmConfigProvider>
    </div>
  );
};

export default DataEditorTab;
and there goes a long route down
Avatar
American black bear
can you do ctrl+shift+F in VSCode type window. and see if there are any files that use it
Avatar
Korean bullheadOP
Multiple places e.g.
utility.ts
export const copyToClipboard = async (content: string) => {
  if (typeof window !== 'undefined') {
    if (window.isSecureContext && navigator.clipboard) {
      await navigator.clipboard.writeText(content);
    } else {
      unsecuredCopyToClipboard(content);
    }
  }
};
or graph-node.tsx

...
specification.documentationUrl
      ? {
          key: 'documentation',
          icon: <BookOutlined />,
          label: 'Documentation',
          onClick: () => typeof window !== 'undefined' && window.open(specification.documentationUrl, '_href'),
        }
      : null,
...
or AppNav.tsx
  useEffect(() => {
    if (!profileSettingsOpen) return;
    function handleClick(event: MouseEvent) {
      if (profileRef.current && !profileRef.current.contains(event.target as Node)) {
        setProfileSettingsOpen(false);
      }
    }
    if (typeof window !== 'undefined') {
      window.addEventListener("click", handleClick);
    return () => window.removeEventListener("click", handleClick);
    }
  }, [profileSettingsOpen]);
and some more places
Would you say the error comes from any of those windows, or from the raw import of the libs?
Avatar
American black bear
I am pretty sure this is what is causing the error

specification.documentationUrl
      ? {
          key: 'documentation',
          icon: <BookOutlined />,
          label: 'Documentation',
          onClick: () => typeof window !== 'undefined' && window.open(specification.documentationUrl, '_href'),
        }
      : null,
also it's better to check if the window is of type undefined then return instead of nesting the if statements:

// do this
if (typeof window === "undefined") return

// ...handle code

// instead of this

if (typeof window !== "undefined") {
  // ...code
}
Avatar
Korean bullheadOP
So, below are all my window usages:

autoszie-text-area.tsx

useEffect(() => {
      if (typeof window !== 'undefined') {
        if (!textareaRef.current) {
          return;
        }
  
        const observerCallback: ResizeObserverCallback = (entries: ResizeObserverEntry[]) => {
          window.requestAnimationFrame((): void | undefined => {
            if (!Array.isArray(entries) || entries.length === 0) {
              return;
            }
  
            recalculateRows(entries[0].target as HTMLTextAreaElement, maxRows);
          });
        };
  
        const resizeObserver = new ResizeObserver(observerCallback);
        resizeObserver.observe(textareaRef.current);
  
        return () => {
          resizeObserver.disconnect();
        };
      }
    }, [maxRows]);
graph-aside.tsx
const downloadJDM = async () => {
    try {
      const { name } = decisionGraphRaw.stateStore.getState();
      // create file in browser
      const fileName = `${name.replaceAll('.json', '')}.json`;
      const json = JSON.stringify(
        {
          contentType: DecisionContentType,
          nodes: decisionGraph.nodes,
          edges: decisionGraph.edges,
        },
        null,
        2,
      );
      const blob = new Blob([json], { type: 'application/json' });
      const href = URL.createObjectURL(blob);

      // create "a" HTLM element with href to file
      const link = typeof window !== 'undefined' && window.document.createElement('a');
      if (link) {
        link.href = href;
        link.download = fileName;
        typeof window !== 'undefined' && window.document.body.appendChild(link);
        link.click();

        // clean up "a" element & remove ObjectURL
        typeof window !== 'undefined' && window.document.body.removeChild(link);
        URL.revokeObjectURL(href);
      }
      
    } catch (e: any) {
      message.error(e.message);
    }
  };
graph-node.tsx
const menuItems = [
    specification.documentationUrl
      ? {
          key: 'documentation',
          icon: <BookOutlined />,
          label: 'Documentation',
          onClick: () => typeof window !== 'undefined' && window.open(specification.documentationUrl, '_href'),
        }
      : null,
...
InputSpecification.tsx

<GraphNode
        id={id}
        specification={specification}
        name={data.name}
        isSelected={selected}
        handleLeft={false}
        menuItems={[
          {
            key: 'documentation',
            icon: <BookOutlined />,
            label: 'Documentation',
            onClick: () => typeof window !== 'undefined' && window.open(specification.documentationUrl, '_href'),
          },
          {
            key: 'delete',
            icon: <DeleteOutlined />,
            danger: true,
            label: <SpacedText left="Delete" right={platform.shortcut('Backspace')} />,
            disabled,
            onClick: () =>
              Modal.confirm({
                icon: null,
                title: 'Delete node',
                content: (
                  <Typography.Text>
                    Are you sure you want to delete <Typography.Text strong>{data.name}</Typography.Text> node.
                  </Typography.Text>
                ),
                okButtonProps: { danger: true },
                onOk: () => graphActions.removeNodes([id]),
              }),
          },
        ]}
      />
function.tsx
useEffect(() => {
    if (window !== null && window !== undefined) {
      window.addEventListener('resize', resizeEditor);
    }
    
    return () => {
      if (window !== null && window !== undefined) {
        window.removeEventListener('resize', resizeEditor);
      }
    }
  }, [resizeEditor, editor]);
platform.ts
const isMac = typeof window !== 'undefined' ? navigator.platform.includes('Mac') : false;

const keyMaps: Record<string, string> = {
  Ctrl: '⌘',
  Backspace: '⌫',
  Alt: '⌥',
};

export const platform = {
  shortcut: (s: string): string => {
    if (!isMac) return s;

    return Object.keys(keyMaps).reduce((acc, key) => acc.replaceAll(key, keyMaps[key]), s);
  },
};
utility.ts
export const copyToClipboard = async (content: string) => {
  if (typeof window !== 'undefined') {
    if (window.isSecureContext && navigator.clipboard) {
      await navigator.clipboard.writeText(content);
    } else {
      unsecuredCopyToClipboard(content);
    }
  }
};
appnav.tsx
useEffect(() => {
    if (!profileSettingsOpen) return;
    function handleClick(event: MouseEvent) {
      if (profileRef.current && !profileRef.current.contains(event.target as Node)) {
        setProfileSettingsOpen(false);
      }
    }
    if (typeof window !== 'undefined') {
      window.addEventListener("click", handleClick);
    return () => window.removeEventListener("click", handleClick);
    }
  }, [profileSettingsOpen]);

  useEffect(() => {
    if (!hamburgerOpen) return;
    function handleClick(event: MouseEvent) {
      if (hamburgerMenuRef.current && !hamburgerMenuRef.current.contains(event.target as Node)) {
        setHamburgerOpen(false);
      }
    }
    if (typeof window !== 'undefined') {
      window.addEventListener("click", handleClick);
      return () => window.removeEventListener("click", handleClick);
    }
  }, [hamburgerOpen]);
Those were all usages of window
Alright, thanks. I will try that out later
Avatar
American black bear
in graph-node.tsx, rewrite your checking as this:

onClick: () => {
  if (typeof window === "undefined") return

  // ...handle code
}
Avatar
Korean bullheadOP
Thanks I will try it out
Avatar
Korean bullheadOP
@American black bear sorry for the late reply. I have tested it, but it is not working. The error still occurs. But I did more tests, it only occurs when I am on the /arams/new page and refresh it. When I am directing to it via the navigator, the error does not show up
Avatar
Korean bullheadOP
@American black bear @D Trombett Sorry for pinging you again, but you are currently the only help^^
The error is defenitely in the DecisionGraph component, which has those window code, I sent above. When removing the component everything works

However not even disabling ssr will solve it

const DecisionGraph = dynamic(
  () => import('@/components/data-editor').then(module => module.DecisionGraph) as any,
  { ssr: false },
) as any;
Avatar
American black bear
I am sorry but I really can't figure out what the problem is, do you mind sharing the entire DecisionGraph component and the components in which you use it in?
Avatar
Did you make sure that you rewrote every piece of code where you check window directly like this function.tsx file to "typeof window !== undefined"?

Having a direct check instead of by typeof will yield this error.
Avatar
Korean bullheadOP
The whole component is this jdm-editor

https://github.com/gorules/jdm-editor/tree/master/packages%2Fjdm-editor

Could it be a problem, that this is a react component which might use libraries that only work on client side?
Avatar
Could very much be yep
Avatar
Try loading it in using the dynamic ssr false trick
Answer
Avatar
Korean bullheadOP
Yeah I've done that previously, but unfortunately this didn't solve it
The whole thing is strange. When being in dev mode and going to the page via router push, the error does not occur. Only when pressing f5 when being on that page. And on build
Avatar
Hmm. Probably easiest to just comment everything out and start from one end to the other until you hit the error
Avatar
Korean bullheadOP
Yeah this could be the only solution. A mire in depth trace is not available right? When building it only shows that there is a window undefined in /app/alarms/new
Where the component is used, but not where in this component
Avatar
The thing is that the error is happening serverside. So you can't really see down the tree like that like you can in the browser
Avatar
Korean bullheadOP
Hm that's unfortunate
Avatar
So you only have the stacktrace that you posted earlier
Avatar
Korean bullheadOP
A direct React App might have been easier😅
Avatar
There are tools that can show the refs between which component uses which but don't think it will help you
Avatar
Korean bullheadOP
I think I might start removing the functions using window first, and will check the libraries separately afterwards
Avatar
Also if any, try deleting the ".next" folder and start the server again
Sometimes it will go haywire for no reason
Avatar
Korean bullheadOP
Have tried that multiple times too, but thanks for the tip😀
Avatar
Well good ol comment out strategy it is. It never disappoints 😂
Avatar
Korean bullheadOP
Yeah I think it's the best way too. Although being pretty ugly because it is very much code
Fortunately I will learn the codebase for this component better
Avatar
Korean bullheadOP
Finally got it working. Sorry for wasting your time
I was just rendering the Graph Component with ssr disabled, however it has a provider for antd component wrapped around it in order to make them usable in the Graph. Rendering the whole thing with ssr disabled has worked. Need to throw that part out either way.

Thank you all for helping me😀
Avatar
Great that you solved it 🙂 Cheers
Remember to mark the thread as being solved 🙂