pacocoursey / next-themes

Perfect Next.js dark mode in 2 lines of code. Support System preference and any other theme with no flashing
https://next-themes-example.vercel.app/
MIT License
5.24k stars 192 forks source link

i cannot add Providers component at layout.tsx for webpack error #194

Closed saramjh closed 8 months ago

saramjh commented 1 year ago

i was following tutorial of Nextjs 13 of this youtube and then error was occured at that part of 12:10.

error message is following below `Unhandled Runtime Error TypeError: webpack_require.n is not a function. (In 'webpack_require.n(reactWEBPACK_IMPORTED_MODULE_0)', 'webpack_require.n' is undefined) Call Stack eval

[native code] (app-pages-browser)/./node_modules/next-themes/dist/index.module.js

file:///Users/urs/DEV/blog-next-13/.next/static/chunks/app/layout.js (18:5)

/_next/static/chunks/webpack.js (704:35) __webpack_require__ file:///Users/urs/DEV/blog-next-13/.next/static/chunks/webpack.js (37:37) eval [native code] (app-pages-browser)/./app/components/Providers.tsx /_next/static/chunks/app/layout.js (50:5) file:///Users/urs/DEV/blog-next-13/.next/static/chunks/webpack.js (704:35) __webpack_require__ /_next/static/chunks/webpack.js (37:37)` isn't next-themes right version for nextjs13 or something? `{ "name": "blog-next-13", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@types/node": "20.4.2", "@types/react": "18.2.15", "@types/react-dom": "18.2.7", "autoprefixer": "10.4.14", "eslint": "8.45.0", "eslint-config-next": "13.4.10", "next": "^13.4.11", "next-themes": "^0.2.1", "postcss": "8.4.26", "react": "18.2.0", "react-dom": "18.2.0", "tailwindcss": "3.3.3", "typescript": "5.1.6" }, "devDependencies": { "@tailwindcss/typography": "^0.5.9" } } `
sandrinjoy commented 1 year ago

it looks like you are using app-dir. Currently next-themes don't come out of the box with 'use client'. so Rather than importing directly from "next-themes", create a new Theme provider file with 'use client' and import that one instead. This is given in the next-themes/examples/app-dir example. ThemeProvider.js

"use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";

/**
 * Your app's theme provider component.
 * 'use client' is essential for next-themes to work with app-dir.
 */
export function ThemeProvider({ children, ...props }) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

and in the layout.js

....
import { ThemeProvider } from "./components/ThemeProvider";
....

This fixed my issue. Ideally 'next-themes' can export a file with 'use client' directive and it will be much easier.

viral-siddhapura commented 8 months ago

I guess by now, everything with Next.js 14 latest version (event with less compatible versions) with next-themes working fine. I implemented the below code using the Next.js 14 version and haven't faced any errors so far.

Create a new Theme provider file with 'use client' and then create ThemeToggle.tsx file:

Theme Provider Filer

'use client'

import * as React from 'react'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
type ThemeProviderProps = Parameters<typeof NextThemesProvider>[0]

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}

Theme Toggle File

'use client'

import { useTheme } from 'next-themes'

function ThemeToggle() {
  const { theme, setTheme } = useTheme()

  return (
    <button
      className="mt-16 px-4 py-2 text-white dark:text-black bg-black dark:bg-white font-semibold rounded-md"
      onClick={() => {
        setTheme(theme === 'light' ? 'dark' : 'light')
      }}
    >
      Change Theme
    </button>
  )
}

export default ThemeToggle

Now In Layout.tsx file - don't need to use any suppress warning

import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import { ThemeProvider } from './components/ThemeProvider'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Viral Siddhapura',
  description: 'Generated by Viral Siddhapura',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className='bg-white dark:bg-black min-h-[100dvh]'>
        <ThemeProvider attribute="class">{children}</ThemeProvider>
      </body>
    </html>
  )
}

This fixed my issue. My portfolio is also live based on this code. Hope this help you 😊🤔

pacocoursey commented 8 months ago

In next-themes@0.3.0, the ThemeProvider is a client component, so you shouldn't need a wrapper anymore.