Home  >  Q&A  >  body text

Why do I get ReferenceError: self is not Defined when I import the client library?

I'm stuck while trying to create an xterm React component in Next.js because I can't get over an error message I've never received before.

I'm trying to import an npm client module called xterm, but if I add the import line, the application crashes.

import { Terminal } from 'xterm'

Error reading Server error... ReferenceError: self is not Defined Then display this code as Source

module.exports = require("xterm");

From some research I've done, this has to do with Webpack and it might be helpful if something like this is done:

output: {
  globalObject: 'this'
}

Do you know how to solve this problem?

P粉214089349P粉214089349364 days ago689

reply all(1)I'll reply

  • P粉958986070

    P粉9589860702023-10-22 10:48:55

    This error occurs because the library requires Web API to work, and when Next.js prerenders the page on the server side.

    In your case, xterm is trying to access a window object that does not exist on the server. The solution is to avoid loading xterm on the server and import it dynamically so that it is only loaded on the client.

    In Next.js, there are multiple ways to achieve this.


    #1 Use dynamic import() inside useEffect

    Move import to the component's useEffect, then dynamically import the library and add logic there.

    useEffect(() => {
        const initTerminal = async () => {
            const { Terminal } = await import('xterm')
            const term = new Terminal()
            // Add logic with `term`
        }
        initTerminal()
    }, [])
    

    #2 Use next/dynamic with ssr: false

    Create a component and add xterm logic to it.

    // components/terminal-component
    import { Terminal } from 'xterm'
    
    function TerminalComponent() {
        const term = new Terminal()
        // Add logic around `term`
        return <></>
    }
    
    export default TerminalComponent
    

    Then dynamically import the component when used.

    import dynamic from 'next/dynamic'
    
    const TerminalComponent = dynamic(() => import('<path-to>/components/terminal-component'), {
        ssr: false
    })
    

    As an alternative, you can add logic directly when using next/dynamic to dynamically import the library to avoid generating extra files.

    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
        }
    )
    

    reply
    0
  • Cancelreply