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

使用React+Emotion+Vite构建的UI组件包在Next.js应用中调用时出现服务器错误的解决方案求助

解决Next.js调用Emotion UI组件包的服务器端缓存错误

我帮你拆解下这个问题——你碰到的TypeError: Cannot read properties of null (reading 'registered'),本质是Emotion的缓存对象在Next.js服务器端渲染(SSR)时没被正确初始化,哪怕加了<CacheProvider>也没起效。这通常是因为组件包的Emotion配置和Next.js的SSR上下文没匹配上,下面是针对性的解决方法:

1. 在Next.js端配置SSR兼容的CacheProvider

针对Next.js 13+ App Router

在根layout.tsx里,要给每个服务器请求单独创建Emotion缓存(避免跨请求污染),并确保CacheProvider包裹整个应用:

import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import type { Metadata } from 'next';

// 每个请求创建独立缓存
function createEmotionCache() {
  return createCache({ 
    key: 'next-ui-emotion',
    prepend: true, // 保证样式优先级正确
  });
}

export const metadata: Metadata = {
  title: '你的应用',
  description: '使用Emotion UI组件包的应用',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const cache = createEmotionCache();
  // 开启SSR兼容模式,这一步很关键
  cache.compat = true;

  return (
    <html lang="zh-CN">
      <body>
        <CacheProvider value={cache}>{children}</CacheProvider>
      </body>
    </html>
  );
}

针对Next.js Pages Router

在_app.tsx中做类似配置:

import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import type { AppProps } from 'next/app';

// 创建全局缓存(Pages Router下可复用)
const cache = createCache({ key: 'css', prepend: true });

export default function App({ Component, pageProps }: AppProps) {
  return (
    <CacheProvider value={cache}>
      <Component {...pageProps} />
    </CacheProvider>
  );
}

2. 检查UI组件包的依赖与Vite配置

从你给出的vite.config.js来看,核心配置没问题,但要确认两点:

  • 组件包的package.json必须包含正确的peerDependencies:
    确保这些依赖被标记为peer依赖,让Next.js应用来提供,避免组件包打包时把它们塞进产物里导致缓存冲突:

    "peerDependencies": {
      "@emotion/react": "^11.10.0",
      "@emotion/styled": "^11.10.0",
      "react": "^17.0.0 || ^18.0.0",
      "react-dom": "^17.0.0 || ^18.0.0"
    }
    

    你的Vite配置里已经用Object.keys(packageJson.peerDependencies)作为external,只要peerDependencies配置正确,这一步就没问题。

  • 组件包内的组件必须正确使用Emotion API:
    所有样式都要通过@emotion/styled或者@emotion/react的css prop创建,不能直接操作Emotion的全局缓存对象——这会导致脱离上下文,在SSR时找不到缓存。

3. 可选:服务器端样式提取(推荐)

为了确保SSR时样式正确注入到HTML中,避免页面闪烁,可以结合@emotion/server的extractCritical函数提取关键样式:

App Router示例(需用服务器组件)

import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import { extractCritical } from '@emotion/server';
import { renderToString } from 'react-dom/server';

function createEmotionCache() {
  return createCache({ key: 'css', prepend: true });
}

export default function RootLayout({ children }) {
  const cache = createEmotionCache();
  cache.compat = true;

  // 服务器端渲染并提取关键样式
  const html = renderToString(<CacheProvider value={cache}>{children}</CacheProvider>);
  const { css, ids } = extractCritical(html);

  return (
    <html lang="zh-CN">
      <head>
        {/* 将提取的样式注入到页面头部 */}
        <style
          data-emotion={`css ${ids.join(' ')}`}
          dangerouslySetInnerHTML={{ __html: css }}
        />
      </head>
      <body>
        <CacheProvider value={cache}>{children}</CacheProvider>
      </body>
    </html>
  );
}

4. 验证组件包的打包产物

构建组件包后,检查lib目录下的产物代码,确保@emotion/react、@emotion/styled这些依赖的导入还是原样,没有被打包进组件包——只有让Next.js应用来解析这些依赖,缓存上下文才能正确传递。

做完这些步骤后,服务器端的Emotion缓存应该就能正确初始化,不会再出现null访问的错误了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:27:43