Why am I getting ReferenceError: self is not defined when I import a client-side library?

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?


Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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`
}, [])

#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

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Notify of

Inline Feedbacks
View all comments
Would love your thoughts, please comment.x