MUI (Material-UI) использует Emotion в качестве системы стилизации по умолчанию. Это позволяет создавать динамические стили с использованием JavaScript, что обеспечивает гибкость и модульность компонентов. При серверном рендеринге (SSR) важно корректно собирать и внедрять стили, чтобы избежать мигания некорректно стилизованного контента (FOUC – Flash of Unstyled Content).
Для работы с MUI и Emotion в SSR необходимы следующие зависимости:
npm install @mui/material @emotion/react @emotion/styled @emotion/server
@mui/material – библиотека компонентов MUI.@emotion/react – ядро Emotion для создания стилей.@emotion/styled – возможность создавать стилизованные
компоненты через шаблонные строки.@emotion/server – сборка и инлайнинг стилей на
сервере.Для корректного SSR требуется создать отдельный Emotion Cache, который будет использоваться как на клиенте, так и на сервере:
import createCache from '@emotion/cache';
export default function createEmotionCache() {
return createCache({ key: 'css', prepend: true });
}
key: 'css' – префикс для всех классов, генерируемых
Emotion.prepend: true – вставляет стили в начало
<head>, чтобы MUI переопределял стандартные стили
браузера.Для SSR важно собрать все стили с помощью Emotion и вставить их в HTML до отправки на клиент. Пример для Next.js:
import createEmotionServer from '@emotion/server/create-instance';
import createEmotionCache from './createEmotionCache';
import Document, { Html, Head, Main, NextScript } from 'next/document';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const cache = createEmotionCache();
const { extractCriticalToChunks } = createEmotionServer(cache);
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 emotionStyleTags = emotionStyles.styles.map((style) => (
<style
data-emotion={`${style.key} ${style.ids.join(' ')}`}
key={style.key}
dangerouslySetInnerHTML={{ __html: style.css }}
/>
));
return {
...initialProps,
styles: [
...React.Children.toArray(initialProps.styles),
...emotionStyleTags,
],
};
}
render() {
return (
<Html lang="ru">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
Ключевые моменты:
createEmotionServer(cache) создает экземпляр для
извлечения критических стилей.extractCriticalToChunks анализирует HTML и возвращает
минимальный набор стилей, необходимых для корректного отображения.data-emotion позволяет Emotion на клиенте
идентифицировать уже встроенные стили и избежать дублирования.На клиенте необходимо передать созданный кеш в
ThemeProvider:
import { CacheProvider } from '@emotion/react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import createEmotionCache from './createEmotionCache';
const clientSideEmotionCache = createEmotionCache();
const theme = createTheme();
export default function MyApp({ Component, pageProps, emotionCache = clientSideEmotionCache }) {
return (
<CacheProvider value={emotionCache}>
<ThemeProvider theme={theme}>
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>
);
}
CacheProvider обеспечивает
идентичность стилей на сервере и клиенте.createTheme() позволяет кастомизировать тему,
интегрированную с MUI.Emotion поддерживает динамические стили через
sx и styled API:
import { styled } from '@mui/material/styles';
import Button from '@mui/material/Button';
const CustomButton = styled(Button)(({ theme, color }) => ({
backgroundColor: color || theme.palette.primary.main,
'&:hover': {
backgroundColor: theme.palette.secondary.main,
},
}));
theme) доступны внутри функции.color) для
динамического изменения стилей.SSR корректно собирает эти стили благодаря переданному
emotionCache и extractCriticalToChunks.
Инлайнинг стилей на сервере снижает время первого отображения (TTFB) и предотвращает FOUC. Основные рекомендации:
Emotion Cache для всего
приложения.extractCriticalToChunks.<style data-emotion> в
<Head>.TypeScript поддерживает Emotion и MUI без сложностей:
import createCache, { EmotionCache } from '@emotion/cache';
export default function createEmotionCache(): EmotionCache {
return createCache({ key: 'css', prepend: true });
}
EmotionCache обеспечивает автодополнение и
контроль пропсов.ThemeProvider и
styled.extractCriticalToChunks пользователь может увидеть
неподготовленные стили.styled и sx для построения
адаптивных компонентов, полностью совместимых с темами и серверным
рендерингом.Корректная организация Emotion и MUI в SSR обеспечивает стабильную, производительную и предсказуемую визуализацию интерфейсов без лишних миганий стилей.