Material-ui: SheetsRegistry in SSR generates empty string

Created on 11 Nov 2017  路  8Comments  路  Source: mui-org/material-ui

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

The console.log(css) returns some CSS as string (?)

Current Behavior

The console.log(css) returns empty string "". Therefore my rendered material-ui components don't have styles.

Steps to Reproduce

I followed all steps in the official guide https://material-ui-next.com/guides/server-rendering/. And here is some sample of my code:

/* server.js */
...
import { SheetsRegistry, JssProvider } from 'react-jss';
import { create } from 'jss';
import preset from 'jss-preset-default';
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import createGenerateClassName from 'material-ui/styles/createGenerateClassName';
import { red } from 'material-ui/colors';
...
app.use((req, res) => {
...
  const sheetsRegistry = new SheetsRegistry();
  const theme = createMuiTheme({
    palette: {
      primary: red,
      type: 'dark',
    },
  });
  const jss = create(preset());
  jss.options.createGenerateClassName = createGenerateClassName;

  const component = (
    <Provider store={store} key="provider">
      <JssProvider registry={sheetsRegistry} jss={jss}>
        <MuiThemeProvider theme={theme} sheetsManager={new Map()}>
          <ReduxAsyncConnect {...renderProps} />
        </MuiThemeProvider>
      </JssProvider>
    </Provider>
  );

  const css = sheetsRegistry.toString();
  console.log(css); // returns empty string

  res.send(`<!doctype html>
    ${ReactDOM.renderToString(
      <Html assets={webpackIsomorphicTools.assets()} style={css} component={component} store={store} />
  )}`);
...
});

The response I got from initial render is correct, for example this AppBar component

<AppBar>
  <Toolbar>
    <IconButton color="contrast" aria-label="Menu" className={classes.menuButton}>
      <MenuIcon />
    </IconButton>
    <Typography type="title" color="inherit" className={classes.title}>
      Dashboard
    </Typography>
    <Button color="contrast">Login</Button>
  </Toolbar>
</AppBar>

Rendered to string as

<header class="c10 c16 c3 c4 c8 mui-fixed" data-reactid="4">
    <div class="c37 c38" data-reactid="5">
        <button tabindex="0" class="c48 c39 c41 c2" type="button" role="button" aria-label="Menu" data-reactid="6"><span class="c45" data-reactid="7"><svg class="c50 c46" focusable="false" viewBox="0 0 24 24" aria-hidden="true" data-reactid="8"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" data-reactid="9"></path></svg></span><span class="c51" data-reactid="10"></span>
        </button>
        <h2 class="c58 c64 c77 c1" data-reactid="11">Dashboard</h2>
        <button tabindex="0" class="c48 c82 c87" type="button" role="button" data-reactid="12"><span class="c84" data-reactid="13">Login</span><span class="c51" data-reactid="14"></span>
        </button>
    </div>
</header>

Context

Just trying to accomplish simple SSR by following official guide.

My Environment

| Tech | Version |
|--------------|---------|
| Material-UI |1.0.0-beta.20|
| React |15.5.4|
| JSS | 8.1.0 |
| react-jss | 7.2.0 |

question

Most helpful comment

What you are describing is the expected behavior.
You are calling ReactDOM.renderToString() after sheetsRegistry.toString().
You need to reverse the calls. It's ReactDOM.renderToString() how is adding the CSS to the sheet registry.

All 8 comments

What you are describing is the expected behavior.
You are calling ReactDOM.renderToString() after sheetsRegistry.toString().
You need to reverse the calls. It's ReactDOM.renderToString() how is adding the CSS to the sheet registry.

@oliviertassinari Hi bro, I have the empty string problem too, but not like this calling renderToString after sheetsRegistry.toString, my problem is sheetsRegistry.toString can generate stylesheet string correctly in the "first call", but after that, the sheetsRegistry.toString just return empty string, I'm not sure if it's related to this one, so I just put it here first.

import { renderToString } from "react-dom/server";
import React from "react";
import { createGenerateClassName } from "material-ui/styles";
import { SheetsRegistry } from "react-jss/lib/jss";
import JssProvider from "react-jss/lib/JssProvider";
import Button from "material-ui/Button";

function render() {
  const sheetsRegistry = new SheetsRegistry();
  const generateClassName = createGenerateClassName();

  const str = renderToString(
    <JssProvider
      registry={sheetsRegistry}
      generateClassName={generateClassName}
    >
      <Button>Default</Button>
    </JssProvider>
  );

  const css = sheetsRegistry.toString();

  console.log(css.length);
}

render();
render();

The second console.log will print 0, what did I do wrong in SSR?
In case that you might need to reproduce it ssr

@cyl19910101 Posting this issue on StackOverflow would be much more efficient. The stylesheets are generated only once per component type (for performance). We use a cache. You need to clear this cache between two requests. It's what the sheetsManager is for in the guide.

@oliviertassinari Thanks a lot! I was thinking that according to that guide if I don't need to override the default them then I don't need to wrap the application under MuiThemeProvider....

@oliviertassinari @cyl19910101 so how can i clear cache? Lose many time for this problem..(

@Fi1osof The cache is stored in the sheetsManager. It's a simple Map object. You can provide a new one to clear the cache.

@oliviertassinari It`s my mistake... mui@next do not requries MuiThemeProvider, and i have not this component in my code. yes, later i added this component and this solves my problem. Thanks for answer!

@oliviertassinari Hi bro, I have the empty string problem too, but not like this calling renderToString after sheetsRegistry.toString, my problem is sheetsRegistry.toString can generate stylesheet string correctly in the "first call", but after that, the sheetsRegistry.toString just return empty string, I'm not sure if it's related to this one, so I just put it here first.

import { renderToString } from "react-dom/server";
import React from "react";
import { createGenerateClassName } from "material-ui/styles";
import { SheetsRegistry } from "react-jss/lib/jss";
import JssProvider from "react-jss/lib/JssProvider";
import Button from "material-ui/Button";

function render() {
  const sheetsRegistry = new SheetsRegistry();
  const generateClassName = createGenerateClassName();

  const str = renderToString(
    <JssProvider
      registry={sheetsRegistry}
      generateClassName={generateClassName}
    >
      <Button>Default</Button>
    </JssProvider>
  );

  const css = sheetsRegistry.toString();

  console.log(css.length);
}

render();
render();

The second console.log will print 0, what did I do wrong in SSR?
In case that you might need to reproduce it ssr

I had this issue too. Then I found that if I add sheetsManager={new Map()} to MuiThemeProvider, the problem solved.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

reflog picture reflog  路  3Comments

ghost picture ghost  路  3Comments

sys13 picture sys13  路  3Comments

anthony-dandrea picture anthony-dandrea  路  3Comments

newoga picture newoga  路  3Comments