Why am I getting ReferenceError: self is not defined when I import a client-side library?
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
}
)