为什么在导入客户端库时收到 ReferenceError: self is not defined?

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

提问人:Lord Reptilia 提问时间:2/8/2021 最后编辑:juliomalvesLord Reptilia 更新时间:6/20/2023 访问量:40153

问:

尝试在 Next.js 中创建 xterm react 组件时,我遇到了困难,因为我无法克服以前从未收到过的错误消息。

我正在尝试导入一个名为 的 npm 客户端模块,但是如果我添加导入行,应用程序就会崩溃。xterm

import { Terminal } from 'xterm'

该错误读取并显示此代码块Server Error... ReferenceError: self is not definedSource

module.exports = require("xterm");

根据我所做的一些研究,这与 Webpack 有关,如果完成这样的事情会有所帮助:

output: {
  globalObject: 'this'
}

你知道如何解决这个问题吗?

reactjs webpack next.js xtermjs

评论


答:

79赞 juliomalves 2/8/2021 #1

发生此错误的原因是库需要 Web API 才能工作,当 Next.js 在服务器端预呈现页面时,这些 API 不可用。

在本例中,尝试访问服务器上不存在的对象。解决方案是避免在服务器上加载并动态导入它,以便它只在客户端加载。xtermwindowxterm

在 Next.js 中,有几种方法可以实现这一点。


#1 在内部使用动态import()useEffect

将 移动到组件的 ,然后动态导入库并在其中添加逻辑。importuseEffect

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

#2 使用next/dynamicssr: false

创建一个组件,您可以在其中添加逻辑。xterm

// components/terminal-component
import { Terminal } from 'xterm'

function TerminalComponent() {
    const term = new Terminal()
    // Add logic around `term`
    return <></>
}

export default TerminalComponent

然后在使用该组件时动态导入该组件。

import dynamic from 'next/dynamic'

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

或者,您可以在动态导入库时直接添加逻辑,以避免有额外的文件。next/dynamic

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

评论

0赞 Lord Reptilia 2/9/2021
感谢您的回复!我已经尝试过这个,但它似乎没有导入构造函数。相反,我得到的是一个带有 a 和属性的。你知道为什么会这样吗?{ Terminal }someobject = {}$$typeof:render:
2赞 Lord Reptilia 2/9/2021
我已经通过在我的组件中执行一个,然后使用父页面中的函数导入它来解决它。如果你提到这个细节,我可以把你的答案标记为正确。import { Terminal } from 'xterm'<Component />dynamic()
1赞 juliomalves 2/9/2021
啊,对了,我假设是一个组件 - Next.js 必须返回一个组件。我会更新我的答案。Terminaldynamic
1赞 user10033434 4/4/2023
你不知道你的回答是如何拯救我的。谢谢。。。
1赞 juliomalves 9/8/2023
@crollywood 使用不会使组件仅在客户端呈现。这仅仅意味着除了服务器端渲染之外,组件还将在客户端渲染。与服务器组件(不使用 的组件)相反,其中呈现仅在服务器上进行。use clientuse client