You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Emotion开发的NPM包引入Next.js时触发TypeError报错

问题背景

目标是将blinq-image-editor仓库发布的npm包成功导入,在emotion-demo Next.js应用中使用。
当前Next.js应用可以正常编译,但运行时在页面生成阶段会抛出如下服务端错误,所有控制台日志会输出到终端窗口:

Server Error
TypeError: Cannot read property 'registered' of null

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Call Stack
<unknown>
file:///Users/shertu/shertu/apple/node_modules/.pnpm/blinq-image-editor@1.0.4_hbkw2sf35pylg2cvgnw53hddsi/node_modules/blinq-image-editor/dist/index.js (2:238027)
Styled(div)
file:///Users/shertu/shertu/apple/node_modules/.pnpm/blinq-image-editor@1.0.4_hbkw2sf35pylg2cvgnw53hddsi/node_modules/blinq-image-editor/dist/index.js (2:147434)
renderWithHooks
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (5658:16)
renderForwardRef
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (5842:18)
renderElement
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (6005:11)
renderNodeDestructiveImpl
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (6104:11)
renderNodeDestructive
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (6076:14)
renderElement
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (5971:9)
renderNodeDestructiveImpl
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (6104:11)
renderNodeDestructive
file:///Users/shertu/shertu/apple/node_modules/.pnpm/react-dom@18.2.0_react@18.2.0/node_modules/react-dom/cjs/react-dom-server.browser.development.js (6076:14)

两个仓库均由提问者自行维护,可任意调整两边配置。

根因定位

从调用栈的Styled(div)标识和registered字段报错判断,这是典型的Emotion CSS-in-JS库服务端渲染上下文缺失问题,触发原因通常是以下两种:

  • blinq-image-editor构建时将react、@emotion系列依赖打包进了产物,导致npm包和Next.js应用各自持有一份独立的Emotion实例,服务端渲染时组件读取不到应用侧注入的样式上下文,拿到null值报错
  • Next.js应用侧没有配置Emotion的服务端渲染逻辑,服务端执行渲染时没有初始化对应的样式上下文
解决步骤

1. 修复blinq-image-editor的构建配置

这是最核心的修复点,从根源解决多实例冲突问题:

  • 将react、react-dom、所有@emotion/*开头的依赖从package.json的dependencies字段移到peerDependencies,声明为宿主环境需要提供的公共依赖
  • 在构建工具配置中把上述依赖标记为external,不要打包进最终dist产物。如果是用Vite构建库,参考配置如下:
// vite.config.js
export default {
  build: {
    lib: {
      // 保留原有库构建配置
    },
    rollupOptions: {
      external: ['react', 'react-dom', '@emotion/react', '@emotion/styled', '@emotion/cache'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
          '@emotion/react': 'emotionReact',
          '@emotion/styled': 'emotionStyled'
        }
      }
    }
  }
}
  • 重新构建并发布新版本的npm包,确认产物中不包含上述公共依赖的代码。

2. 配置Next.js应用的Emotion SSR支持

  • 安装必要依赖:npm i @emotion/cache @emotion/server @emotion/react @emotion/styled
  • 在pages目录下新建_document.js,配置服务端样式提取逻辑,参考配置:
// pages/_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document'
import createCache from '@emotion/cache'
import createEmotionServer from '@emotion/server/create-instance'

const cache = createCache({ key: 'css' })
const { extractCriticalToChunks } = createEmotionServer(cache)

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="zh-CN">
        <Head>
          {this.props.styleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

MyDocument.getInitialProps = async (ctx) => {
  const originalRenderPage = ctx.renderPage
  ctx.renderPage = () => originalRenderPage({
    enhanceApp: (App) => (props) => <App emotionCache={cache} {...props} />
  })
  const initialProps = await Document.getInitialProps(ctx)
  const emotionStyles = extractCriticalToChunks(initialProps.html)
  const styleTags = emotionStyles.styles.map(style => (
    <style
      data-emotion={`${style.key} ${style.ids.join(' ')}`}
      key={style.key}
      dangerouslySetInnerHTML={{ __html: style.css }}
    />
  ))
  return {
    ...initialProps,
    styleTags: [...initialProps.styles, ...styleTags]
  }
}
  • 修改pages目录下的_app.js,全局注入Emotion缓存:
// pages/_app.js
import { CacheProvider } from '@emotion/react'
import createCache from '@emotion/cache'

const clientCache = createCache({ key: 'css' })

export default function MyApp({ Component, pageProps }) {
  return (
    <CacheProvider value={clientCache}>
      <Component {...pageProps} />
    </CacheProvider>
  )
}
  • 安装更新后的blinq-image-editor包,重启Next.js开发服务即可正常运行。

3. 临时调试兜底方案

如果需要快速验证组件功能,暂时不想调整两边配置,可以直接关闭该组件的服务端渲染,用Next.js动态导入实现:

import dynamic from 'next/dynamic'
// 导入时关闭ssr
const BlinqImageEditor = dynamic(() => import('blinq-image-editor'), { ssr: false })

// 页面中直接使用组件即可,绕开SSR阶段的上下文问题

该方案会损失组件的SSR渲染能力,仅适合临时调试使用,长期使用建议按前两个步骤完成正式修复。


内容的提问来源于stack exchange,提问作者shertu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:45:59