This question already has answers here:
Window is not defined in Next.js React app
(23 answers)
Closed 6 months ago.
I have a Next.js app
This is one of my page/component looks like
import React from "react";
import { SomeLocalStorageComponent } from "some-external-lib";
const MyComponent = () => {
const isBrowser = typeof window !== "undefined"
{
if (isBrowser) {
<SomeLocalStorageComponent></SomeLocalStorageComponent>
}
}
};
export default MyComponent;
This is throwing the below run time error
Server Error
ReferenceError: localStorage is not defined
Here SomeLocalStorageComponent is an external library component which is dependant on a localStorage variable
When this SomeLocalStorageComponent is used in a React app, it functions as expected however when I'm consuming this into Next.js app it throws the error.
how to get rid of this error?
Please suggest. Thanks!
You can use next/dynamic:
import dynamic from 'next/dynamic'
const SomeLocalStorageComponent = dynamic(() => import('some-external-lib'), {
ssr: false,
})
It will disable ssr for imported component
If your external library exports multiple components you can do something like this:
const SomeLocalStorageComponent = dynamic(
async () => (await import('some-external-lib').SomeExportedComponent,
{
ssr: false,
}
)
You should do above for each component you want to disable ssr
And if you want to have ssr in imported component you can import it normally:
import { TestComponent } from "some-external-lib"
Also protip:
You can export component with no ssr to a new file:
//TestComponentNoSsr.js
const TestComponent = dynamic(
async () => (await import('some-external-lib').TestComponent,
{
ssr: false,
}
)
export default TestComponent
Related
Trying to create an xterm react component in Next.js I got stuck as I'm not able to get over an error message I've never got before.
I'm trying to import a npm client-side module called xterm, but if I add the import line the application crashes.
import { Terminal } from 'xterm'
The error reads Server Error... ReferenceError: self is not defined
and then shows this chunk of code as Source
module.exports = require("xterm");
According to some research I did, this has to do with Webpack and could be helped if something like this was done:
output: {
globalObject: 'this'
}
Would you know how to fix this?
The error occurs because the library requires Web APIs to work, which are not available when Next.js pre-renders the page on the server-side.
In your case, xterm tries to access the window object which is not present on the server. To fix it, you have to dynamically import xterm so it only gets loaded on the client-side.
There are a couple of ways to achieve this in Next.js.
#1 Using dynamic import()
Move the import to your component's useEffect, then dynamically import the library and add your logic there.
useEffect(() => {
const initTerminal = async () => {
const { Terminal } = await import('xterm')
const term = new Terminal()
// Add logic with `term`
}
initTerminal()
}, [])
#2 Using next/dynamic with ssr: false
Create a component where you add the xterm logic.
// components/terminal-component
import { Terminal } from 'xterm'
function TerminalComponent() {
const term = new Terminal()
// Add logic around `term`
return <></>
}
export default TerminalComponent
Then dynamically import that component when using it.
import dynamic from 'next/dynamic'
const TerminalComponent = dynamic(() => import('<path-to>/components/terminal-component'), {
ssr: false
})
As an alternative, you could add the logic directly when dynamically importing the library with next/dynamic to avoid having an extra file for it.
import dynamic from 'next/dynamic'
const Terminal = dynamic(
{
loader: () => import('xterm').then((mod) => mod.Terminal),
render: (props, Terminal) => {
const term = new Terminal()
// Add logic with `term`
return <></>
}
},
{
ssr: false
}
)
Trying to create an xterm react component in Next.js I got stuck as I'm not able to get over an error message I've never got before.
I'm trying to import a npm client-side module called xterm, but if I add the import line the application crashes.
import { Terminal } from 'xterm'
The error reads Server Error... ReferenceError: self is not defined
and then shows this chunk of code as Source
module.exports = require("xterm");
According to some research I did, this has to do with Webpack and could be helped if something like this was done:
output: {
globalObject: 'this'
}
Would you know how to fix this?
The error occurs because the library requires Web APIs to work, which are not available when Next.js pre-renders the page on the server-side.
In your case, xterm tries to access the window object which is not present on the server. To fix it, you have to dynamically import xterm so it only gets loaded on the client-side.
There are a couple of ways to achieve this in Next.js.
#1 Using dynamic import()
Move the import to your component's useEffect, then dynamically import the library and add your logic there.
useEffect(() => {
const initTerminal = async () => {
const { Terminal } = await import('xterm')
const term = new Terminal()
// Add logic with `term`
}
initTerminal()
}, [])
#2 Using next/dynamic with ssr: false
Create a component where you add the xterm logic.
// components/terminal-component
import { Terminal } from 'xterm'
function TerminalComponent() {
const term = new Terminal()
// Add logic around `term`
return <></>
}
export default TerminalComponent
Then dynamically import that component when using it.
import dynamic from 'next/dynamic'
const TerminalComponent = dynamic(() => import('<path-to>/components/terminal-component'), {
ssr: false
})
As an alternative, you could add the logic directly when dynamically importing the library with next/dynamic to avoid having an extra file for it.
import dynamic from 'next/dynamic'
const Terminal = dynamic(
{
loader: () => import('xterm').then((mod) => mod.Terminal),
render: (props, Terminal) => {
const term = new Terminal()
// Add logic with `term`
return <></>
}
},
{
ssr: false
}
)
Trying to create an xterm react component in Next.js I got stuck as I'm not able to get over an error message I've never got before.
I'm trying to import a npm client-side module called xterm, but if I add the import line the application crashes.
import { Terminal } from 'xterm'
The error reads Server Error... ReferenceError: self is not defined
and then shows this chunk of code as Source
module.exports = require("xterm");
According to some research I did, this has to do with Webpack and could be helped if something like this was done:
output: {
globalObject: 'this'
}
Would you know how to fix this?
The error occurs because the library requires Web APIs to work, which are not available when Next.js pre-renders the page on the server-side.
In your case, xterm tries to access the window object which is not present on the server. To fix it, you have to dynamically import xterm so it only gets loaded on the client-side.
There are a couple of ways to achieve this in Next.js.
#1 Using dynamic import()
Move the import to your component's useEffect, then dynamically import the library and add your logic there.
useEffect(() => {
const initTerminal = async () => {
const { Terminal } = await import('xterm')
const term = new Terminal()
// Add logic with `term`
}
initTerminal()
}, [])
#2 Using next/dynamic with ssr: false
Create a component where you add the xterm logic.
// components/terminal-component
import { Terminal } from 'xterm'
function TerminalComponent() {
const term = new Terminal()
// Add logic around `term`
return <></>
}
export default TerminalComponent
Then dynamically import that component when using it.
import dynamic from 'next/dynamic'
const TerminalComponent = dynamic(() => import('<path-to>/components/terminal-component'), {
ssr: false
})
As an alternative, you could add the logic directly when dynamically importing the library with next/dynamic to avoid having an extra file for it.
import dynamic from 'next/dynamic'
const Terminal = dynamic(
{
loader: () => import('xterm').then((mod) => mod.Terminal),
render: (props, Terminal) => {
const term = new Terminal()
// Add logic with `term`
return <></>
}
},
{
ssr: false
}
)
This question already has an answer here:
Why am I getting ReferenceError: self is not defined when I import a client-side library?
(1 answer)
Closed 11 months ago.
import Highlighter from "monaco-jsx-highlighter";
this import in next.js gives "document not found" error. So i tried to dynamically import
import dynamic from "next/dynamic";
const Highlighter = dynamic(import("monaco-jsx-highlighter"), { ssr: false });
However dynamic import returns Loadable Component. I checked the next-github and looks like dynamic import works only for components. But import Highlighter from "monaco-jsx-highlighter". Highlighter is actually a class and needs to be initialized as :
const highlighter = new Highlighter()
How can I use this module in next.js without dynamic import?
Seems like the problem is that highlighter has client side only code and cannot run on server with SSR. You could import it regularly into some other component, like HighlighterWrapper and then import HighlighterWrapper dynamically into your main component where you need it, then it should work.
import Highlighter from "monaco-jsx-highlighter";
export const HighligherWrapper = (props) => {
// Make instance here or outside
const highlighter = useMemo(() => new Highlighter(),[]);
// Do whatever you want here with highlighter instance
return <div>Something</div>;
}
export default HighligherWrapper;
import dynamic from "next/dynamic";
const HighligherWrapper = dynamic(()=> import("./HighligherWrapper"), { ssr: false });
const Page() {
// Now you can use it in your code and it won't break SSR
return (
<div>
<HighligherWrapper />
</div>
);
}
Try smt. like this:
/ClientSideComponent.js:
import Highlighter from "monaco-jsx-highlighter";
export default function ClientSideComponent(props){
// Write here the Highlighter logic.
return <Highlighter />;
}
/page.js:
import dynamic from "next/dynamic";
const ClientSideComponent = dynamic(()=> import("./ClientSideComponent.js"), { ssr: false });
function Page(props) {
return <ClientSideComponent />
}
I solved the issue with the vanilla dynamic import instead of next.js dynamic import.
let jsxHighlighter = null;
import("monaco-jsx-highlighter").then((allMonacoSyntaxHighlighter) => {
jsxHighlighter = allMonacoSyntaxHighlighter.default;
});
I do use recoil in my nextjs application.
But if I run next (in dev or production make no difference) I got this error-message:
Duplicate atom key "companyData". This is a FATAL ERROR in
production. But it is safe to ignore this warning if it occurred because of
hot module replacement.
This is the way I've implemented it:
/src/stores/CompanyStore.js:
import { useSetRecoilState, useRecoilValue , atom } from 'recoil';
import config from '../../content/config.yml';
const companyData = atom({
key: 'companyData',
default: {...config.company},
});
export const useSetCompanyData = () => useSetRecoilState(companyData);
export const useCompanyData = () => useRecoilValue(companyData);
export default {
useSetCompanyData,
useCompanyData,
};
I use it like this in some components:
MyComponent.js
import React from 'react';
...
...
import {useCompanyData} from '../stores/CompanyStore';
const MyComponent = () => {
const classes = useStyles();
const companyData = useCompanyData();
const { summary: headline, description } = companyData;
return (<div><h2>{headline}</h2><p>{description}</p>)
I don't see, why this error-message appears. Might it caused of a bug in nextjs, or did I implement recoil in a wrong way?
Looks like a problem with recoil in nextjs when you have state in a separate file:
https://github.com/facebookexperimental/Recoil/issues/733
As of Recoil 0.7.6, add RECOIL_DUPLICATE_ATOM_KEY_CHECKING_ENABLED=false to your environment to hide these warnings.
(roeland had the correct GitHub issue, which has since been closed)