Search code examples
javascriptreactjstypescriptwebpacknext.js

React / Next js : Webpack throws window undefined even when component is 'use client'


I use Typescript 5, React 18, Next js 14 as a stack, and have been going through similar errors for many libs now.

I get the following error ReferenceError: window is not defined.

This comes from a third-party library which is not in my control and hence more frustrating. I found solutions like loading dynamically https://stackoverflow.com/a/63293697/490031. It comes with two problems, this is not typescript compatible and hence throws errors, irrespective of that, it doesn't work either way.

I do not get it, when the component which consumes the lib is use client, why is Webpack trying to use it on the server? any help and fixes?

Following is error log of one such case:-

./src/components/Chat/MyChat.tsx
./src/components/Chat/index.tsx
./src/components/layouts/Navigation.tsx
./src/app/page.tsx
 ⨯ node_modules/html-to-draftjs/dist/html-to-draftjs.js (1:333) @ eval
 ⨯ ReferenceError: window is not defined
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/Chat/MessageComposer/index.tsx:10:73)
    at (ssr)/./src/components/Chat/MessageComposer/index.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:1303:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/Chat/Chat/MessageInput.tsx:13:103)
    at (ssr)/./src/components/Chat/Chat/MessageInput.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:841:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/Chat/Chat/Chat.tsx:9:105)
    at (ssr)/./src/components/Chat/Chat/Chat.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:720:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/Chat/Chat/ChatPanel.tsx:12:97)
    at (ssr)/./src/components/Chat/Chat/ChatPanel.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:764:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/Chat/ChatView.tsx:14:102)
    at (ssr)/./src/components/Chat/ChatView.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:1094:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/Chat/MyChat.tsx:9:96)
    at (ssr)/./src/components/Chat/MyChat.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:1149:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/Chat/index.tsx:9:100)
    at (ssr)/./src/components/Chat/index.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:1347:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/components/layouts/Navigation.tsx:13:87)
    at (ssr)/./src/components/layouts/Navigation.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:3668:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at eval (./src/app/page.tsx:10:91)
    at (ssr)/./src/app/page.tsx (/Users/whicheveruser/company/client-project/.next/server/app/page.js:500:1)
    at __webpack_require__ (/Users/whicheveruser/company/client-project/.next/server/webpack-runtime.js:33:43)
    at JSON.parse (<anonymous>)
**null**


Solution

  • I hope the following quote from Next.js documentation helps clarify the confusion.

    "use client" is used to declare a boundary between a Server and Client Component modules. This means that by defining a "use client" in a file, all other modules imported into it, including child components, are considered part of the client bundle.

    https://nextjs.org/docs/app/building-your-application/rendering/client-components#using-client-components-in-nextjs

    Client components are rendered both client-side and server-side (SSR).

    As to why you see the above error with html-to-draftjs, the answer is pretty simple - the lib doesn't appear to be compatible with SSR at all. To overcome this limitation, you can force it to run exclusively on the client side with dynamic import (you'll probably need to dynamically import the component using the lib, not the lib itself):

    const Chat = dynamic(() => import("./Chat"), { ssr: false });
    

    I hope this helps.