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

Hydrogen项目中基础MUI组件在TypeScript环境下无法运行

在Shopify Hydrogen项目中集成Material UI的解决方案

我在创建Shopify Hydrogen(React)项目时,引入Material UI库开发,使用以下基础代码:

import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: theme.palette.text.secondary,
}));

export default function Home() {
  return (
  <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2}>
        <Grid item xs={8}>
          <Item>xs=8</Item>
        </Grid>
        <Grid item xs={4}>
          <Item>xs=4</Item>
        </Grid>
        <Grid item xs={4}>
          <Item>xs=4</Item>
        </Grid>
        <Grid item xs={8}>
          <Item>xs=8</Item>
        </Grid>
      </Grid>
    </Box>

  )
}

运行后出现以下错误:

Warning: Only plain objects can be passed to client components from server components. Classes or other objects with methods are not supported. Remove sheet from these props: {key: "css", sheet: {_insertTag: function, isSpeedy: false, tags: [...], ctr: 0, nonce: undefined, key: "css", container: undefined, ...}, nonce: undefined, inserted: {...}, registered: {...}, insert: function}
Error processing route: http://localhost:3000/rx
Error: Functions cannot be passed directly to client components because they're not serializable. Remove _insertTag (function) from this object, or avoid the entire object: {_insertTag: function, isSpeedy: false, tags: [...], ctr: 0, nonce: undefined, key: "css", container: undefined, ...}
at resolveModelToJSON (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1515:13)
at StyleSheet.toJSON (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1029:14)
at stringify (<anonymous>)
at processModelChunk (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:164:14)
at retryTask (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1625:26)
at performWork (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1658:7)
at eval (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1755:12)
at scheduleWork (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:58:3)
at startWork (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1754:3)
at Object.start (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1866:7)
at setupReadableByteStreamController (node:internal/webstreams/readablestream:3110:23)
at setupReadableByteStreamControllerFromSource (node:internal/webstreams/readablestream:3147:3)
at new ReadableStream (node:internal/webstreams/readablestream:250:7)
at Module.renderToReadableStream (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite-writer.browser.server.js?v=fa4e9613:1863:16)
at runRSC (/node_modules/@shopify/hydrogen/dist/esnext/entry-server.js?v=fa4e9613:598:46)
at processRequest (/node_modules/@shopify/hydrogen/dist/esnext/entry-server.js?v=fa4e9613:200:15)
at handleRequest (/node_modules/@shopify/hydrogen/dist/esnext/entry-server.js?v=fa4e9613:163:26)
/.../node_modules/yoga-layout-prebuilt/yoga-layout/build/Release/nbind.js:53
throw ex;
^

TypeError: Cannot read properties of undefined (reading 'null')
at getOrCreateServerContext (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite.js?v=fa4e9613:116:23)
at resolveProvider (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite.js?v=fa4e9613:395:51)
at processFullRow (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite.js?v=fa4e9613:469:9)
at processBinaryChunk (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite.js?v=fa4e9613:513:5)
at progress (/node_modules/@shopify/hydrogen/vendor/react-server-dom-vite/esm/react-server-dom-vite.js?v=fa4e9613:566:5)

解决方案

1. 标记组件为客户端组件

Hydrogen默认使用React Server Components,而Material UI的styled、sx等样式方案依赖客户端环境的样式处理逻辑,无法在服务器端序列化传递。需在组件文件最顶部添加'use client'指令,强制组件在客户端渲染:

'use client'; // 必须放在文件第一行
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

// 其余代码保持不变

2. 拆分客户端与服务器组件(更规范的写法)

创建单独的客户端组件文件(可通过.client.jsx后缀让Hydrogen自动识别),将所有MUI相关代码放入其中:

// MuiGrid.client.jsx
'use client';
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Paper from '@mui/material/Paper';
import Grid from '@mui/material/Grid';

const Item = styled(Paper)(({ theme }) => ({
  backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
  ...theme.typography.body2,
  padding: theme.spacing(1),
  textAlign: 'center',
  color: theme.palette.text.secondary,
}));

export default function MuiGrid() {
  return (
    <Box sx={{ flexGrow: 1 }}>
      <Grid container spacing={2}>
        <Grid item xs={8}>
          <Item>xs=8</Item>
        </Grid>
        <Grid item xs={4}>
          <Item>xs=4</Item>
        </Grid>
        <Grid item xs={4}>
          <Item>xs=4</Item>
        </Grid>
        <Grid item xs={8}>
          <Item>xs=8</Item>
        </Grid>
      </Grid>
    </Box>
  );
}

然后在服务器组件中引入该客户端组件:

// Home.jsx(服务器组件)
import MuiGrid from './MuiGrid.client';

export default function Home() {
  return <MuiGrid />;
}

3. 优化SSR样式渲染(可选)

若要避免首屏样式闪烁,可在Hydrogen的服务器入口文件中收集MUI的服务器端样式:

// entry-server.jsx
import { renderToString } from 'react-dom/server';
import { ServerStyleSheets, ThemeProvider, createTheme } from '@mui/material/styles';
import App from './App';

export default function handleRequest(request, response) {
  const sheets = new ServerStyleSheets();
  const theme = createTheme();

  const html = renderToString(
    sheets.collect(
      <ThemeProvider theme={theme}>
        <App />
      </ThemeProvider>
    )
  );

  const css = sheets.toString();

  response.send(`
    <!DOCTYPE html>
    <html>
      <head>
        <style id="jss-server-side">${css}</style>
      </head>
      <body>
        <div id="root">${html}</div>
      </body>
    </html>
  `);
}

同时在客户端入口移除服务器注入的样式:

// entry-client.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import App from './App';

const theme = createTheme();

ReactDOM.hydrateRoot(
  document.getElementById('root'),
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>
);

// 清理服务器端样式
const serverStyle = document.getElementById('jss-server-side');
if (serverStyle) serverStyle.remove();

问题核心原因

React Server Components要求传递给客户端的props必须是可序列化的纯对象,而Material UI的styled生成的组件包含了_insertTag等样式处理函数,这类非纯对象无法被序列化传递,因此必须将使用MUI的组件强制在客户端环境运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 20:20:25