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

CRA迁移至Vite遇样式组件未定义错误,求SSR适配方案

迁移CRA到Vite+SSR时Emotion样式报错:Error: You are trying to create a styled element with an undefined component

问题背景

正在将Create React App(CRA)项目迁移到Vite以实现服务端渲染(SSR),但遇到以下错误:

Error: You are trying to create a styled element with an undefined component. You may have forgotten to import it.

以下是当前的配置文件:

vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import svgrPlugin from 'vite-plugin-svgr';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react({
      jsxImportSource: '@emotion/react',
      babel: {
        plugins: ['@emotion/babel-plugin'],
      },
    }),
    tsconfigPaths(),
    svgrPlugin(),
  ],
});

tsconfig.json

{
 "compilerOptions": {
   "target": "ES2020",
   "useDefineForClassFields": true,
   "lib": ["ES2020", "DOM", "DOM.Iterable"],
   "module": "ESNext",
   "skipLibCheck": true,
   "jsxImportSource": "@emotion/react",

   /* Bundler mode */
   "moduleResolution": "bundler",
   "allowImportingTsExtensions": true,
   "resolveJsonModule": true,
   "isolatedModules": true,
   "noEmit": true,
   "jsx": "react-jsx",

   /* Linting */
   "strict": true,
   "noUnusedLocals": true,
   "noUnusedParameters": true,
   "noFallthroughCasesInSwitch": true,
   "baseUrl": "./src"
 },
 "include": ["src"],

 "references": [{ "path": "./tsconfig.node.json" }]
}

tsconfig.node.json

{
 "compilerOptions": {
   "composite": true,
   "skipLibCheck": true,
   "module": "ESNext",
   "moduleResolution": "bundler",
   "allowSyntheticDefaultImports": true,
   "jsx": "preserve"
 },
 "include": ["vite.config.ts", "src/entry-server.tsx", "src/vite-env.d.ts"]
}

预期配置能正常运行,但实际触发上述错误,需要解决该问题。

解决方案

1. 检查Styled组件的导入方式

确保所有使用styled创建的组件都正确导入了基础组件。比如:

  • 错误示例:
    import styled from '@emotion/styled';
    
    const Button = styled(ButtonBase)`/* 样式 */`;
    // ButtonBase未导入导致undefined
    
  • 正确做法:
    import styled from '@emotion/styled';
    import ButtonBase from '@mui/material/ButtonBase'; // 或对应基础组件
    
    const Button = styled(ButtonBase)`/* 样式 */`;
    

2. 补全Emotion的SSR环境配置

Vite SSR需要额外处理Emotion的服务端渲染:

  • 安装依赖:
    npm install @emotion/server
    # 或 yarn add @emotion/server
    
  • 在entry-server.tsx中包裹CacheProvider并提取样式:
    import { renderToString } from 'react-dom/server';
    import { CacheProvider } from '@emotion/react';
    import createCache from '@emotion/cache';
    import createEmotionServer from '@emotion/server/create-instance';
    import App from './App';
    
    export async function render(url: string) {
      const cache = createCache({ key: 'ssr' });
      const { extractCriticalToChunks, constructStyleTagsFromChunks } = createEmotionServer(cache);
    
      const html = renderToString(
        <CacheProvider value={cache}>
          <App />
        </CacheProvider>
      );
    
      const chunks = extractCriticalToChunks(html);
      const styles = constructStyleTagsFromChunks(chunks);
    
      return { html, styles };
    }
    

3. 调整Vite插件的Emotion配置

完善@vitejs/plugin-react的babel插件参数,确保SSR场景下的兼容性:

// vite.config.ts
react({
  jsxImportSource: '@emotion/react',
  babel: {
    plugins: [
      ['@emotion/babel-plugin', { sourceMap: true, autoLabel: 'dev-only' }]
    ],
  },
})

4. 修正服务端入口的TS配置

将tsconfig.node.json中的"jsx": "preserve"改为"jsx": "react-jsx",因为服务端入口需要编译JSX代码:

{
 "compilerOptions": {
   "composite": true,
   "skipLibCheck": true,
   "module": "ESNext",
   "moduleResolution": "bundler",
   "allowSyntheticDefaultImports": true,
   "jsx": "react-jsx"
 },
 "include": ["vite.config.ts", "src/entry-server.tsx", "src/vite-env.d.ts"]
}

5. 排查第三方库的样式冲突

如果项目依赖第三方UI库(如Material UI),确认是否正确集成Emotion,避免混用不同样式库的styled方法,确保统一使用@emotion/styled。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 22:59:58