Gatsby: [Plugin] Add server-side rendering capability for Material-UI v1

Created on 14 Sep 2017  路  26Comments  路  Source: gatsbyjs/gatsby

Considering that Material-UI is a fairly large React UI framework with almost 30,000 stars on GitHub, I think it would be reasonable to support server-side rendering of their upcoming components.

Most helpful comment

For anyone wondering about how to make the integration possible:

  1. Install gatsby-plugin-jss and add it to the project's gatsby-config.js file
  2. Use The MuiThemeProvider component of Material-UI with the sheetsManager={new Map()} attribute specified

All 26 comments

Why does Material-UI need special support? Isn't everything in Gatsby pre-rendered by default?

Oh, I see that Material-UI uses JSS, so server-side rendering won't work out of the box. gatsby-plugin-jss should do the job.

Yup, looks like we're covered already!

Sweet :)

For anyone wondering about how to make the integration possible:

  1. Install gatsby-plugin-jss and add it to the project's gatsby-config.js file
  2. Use The MuiThemeProvider component of Material-UI with the sheetsManager={new Map()} attribute specified

Material-UI now hosts an official integration with Gatsby in material-ui/examples/gatsby.

@kripod Hi, I've followed those two steps you mentioned, but my ui is still flickering in terms of MU components, are these two the only steps needed with current gatsbyjs and MU v1?

After all, adding SSR support for Material-UI v1 is not even nearly as straightforward as utilizing gatsby-plugin-jss.

I think we should consider opening this issue again and make an official plugin based on the example at material-ui/examples/gatsby.

Anyone trying to use @oliviertassinari's example with Gatsby v2: Note that it uses pageContext (which Gatsby v1's pathContext was renamed to in v2)

Further, since material-ui uses MuiThemeProvider rather than standard jss's ThemeProvider, I don't think that gatsby-plugin-jss is a straight drop-in.

One more thing: the example uses a export default from getPageContext...

Perhaps due to the v2 changes regarding ES6 & CommonJS separation, you'll need to use require() syntax (rather than import) and getPageContext.default() in gatsby-ssr.

Perhaps similar changes need to be made to gatsby-plugin-jss since it currently usesimport statements.

@cpboyd When building the Material-UI example integration with Gatsby, I have started using gatsby-plugin-jss. But It doesn't work, I ended up with a custom solution. The logic can always be abstracted away into a plugin, but it's fairly simple. I'm not 馃挴 % convinced people need it.

I didn't know Gatsby was working on a v2. It would be good to update our example once it's released.
https://github.com/mui-org/material-ui/tree/master/examples/gatsby

Hi @cpboyd,

I have not yet tested @oliviertassinari's example with gatsby@v2, but according to their latest example it should be possible as package.json says "gatsby": "latest", doesn't it?

Perhaps due to the v2 changes regarding ES6 & CommonJS separation, you'll need to use require() syntax (rather than import) and getPageContext.default() in gatsby-ssr.

Have you tested it?

I have also issues to ssr my material-ui page. as soon as people start clicking it (the design, ...) works...

@oliviertassinari Your example was great! And even follows the new v2 layout suggestions by utilizing the withRoot() wrapper. I'd seen some other examples that had placed the MuiThemeProvider within the old layout component.

The only real changes needed are renaming pageContext (I just used muiContext) and then using the require() syntax within the gatsby-ssr.js

@natterstefan I'm not completely familiar with how NPM & yarn handle versioning, but I think "latest" still corresponds to v1, as v2 has only had beta releases thus far.

I'm not entirely sure why the import statements didn't work for me, but I know that changing them to require() resulted in it working as expected. I'm just making note of what changes I had to make, in case anyone else winds up here having trouble with v2.

Hi @cpboyd,

I'm not entirely sure why the import statements didn't work for me, but I know that changing them to require() resulted in it working as expected.

I think this is because of this part here of the migration guide: Convert to either pure CommonJS or pure ES6. Because moving to require in gatsby-ssr.js solved the issue on my side as well.

As well is relative, as the styling provided by the ssr on the inital load was still not matching the client side styling, once I started navigating/interacting with the MaterialUi.

Only when I did not remove the SSR css styles, which is contrary to what the MaterialUI documentation says. But then it works. This requires further investigation, but right now I am happy with this workaround.

@natterstefan I'd seen the CommonJS/ES6 stuff in the migration guide but couldn't find it when making my prior posts.

I hadn't noticed any issues with my layout leaving everything in componentDidMount(), but it'd probably be safest to move it to onInitialClientRender in gatsby-browser.js like gatsby-plugin-jss so that it doesn't accidentally remove the styles from the server version.

Thanks @cpboyd for the hint, I will definitely check it out and let you know if it works.

Edit: so you are still using gatsby-plugin-jss? Or how do I get the theme into gatsby-browser.js when not using the plugin?

I tried the Material UI Gatsby example with gatsby@next, but it throws the following error:

Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /Users/narbhati/projects/material-ui/examples/gatsby/.cache/develop-static-entry.js:
Support for the experimental syntax 'objectRestSpread' isn't currently enabled (72:5):

  70 |
  71 |   const htmlElement = React.createElement(Html, {
> 72 |     ...bodyProps,
     |     ^
  73 |     body: ``,
  74 |     headComponents: headComponents.concat([
  75 |       <script key={`io`} src="/socket.io/socket.io.js" />,

Add @babel/plugin-proposal-object-rest-spread (https://git.io/vb4Ss) to the 'plugins' section
of your Babel config to enable transformation.

Adding plugin-proposal-object-rest-spread to that example's .babelrc does not help. Don't know where to go from here.

FWIW i am having several problems with the material-ui integration as well, only for me it happens on build and not on develop.
Details here https://github.com/mui-org/material-ui/issues/12649

Hi @oorestisime, I had similar issues as you. I kinda solved it (with some workarounds, mentioned earlier in this issue) here in this repo. Maybe this helps you, at least a little.

@natterstefan Have you had any issues with the recent v2 RC?

My project now renders fine in develop mode, and the SSR builds the HTML successfully...
But once the Javascript rendering takes over in the production build, the styles get messed up.

@cpboyd have you checked out the example we host on Material-UI?

@cpboyd i fixed my issue by removing the withRoot call on all but root component (like index.jsx or another page just not in the components). It was causing everything to be re-rendered multiple times otherwise. now everything works good for me in develop and build. I am willing to PR a documentation warning or notice on that if anyone could confirm on their side that this is the case for them as well (or if someone for material-ui can pitch in and say that this actually makes sense :) )

@natterstefan thanks, i had a look at your repo before and saw the hack you did with not removing server side injected CSS but didn't fix the issue for my case unfortunately so i continued to debug

I created a starter template for Material-UI using Gatsby v2 and Material-UI v3. This is based on the example hosted on the Material-UI site. I have not run into the issue with withRoot() even though I am using it in root components as well as layout components - in develop and in build. You can see the live site here. While @oorestisime's comments make sense, I wonder why I am not running into this issue!!

@oorestisime

(...) not removing server side injected CSS but didn't fix the issue for my case unfortunately so i continued to debug

interesting behavior, as well as it seems to work with withRoot in @nareshbhatia's case compared to your setup.

thx @nareshbhatia for the template.

FYI: If you want to use wrapPageElement and wrapRootLayout, I now have a working example:
https://github.com/cpboyd/gatsby-layout-mui-bug

The gatsby-plugin-jss used a const sheets across all pages, but I found that this causes problems after a certain number of custom styles or pages.

Note: wrapPageElement (rather than using a withRoot per page) is necessary to take full advantage of page transitions. I also noticed a JS size reduction as it moves the layout from page JS files to a singular app JS file.

You can also checkout gatsby-plugin-layout for more info on this.

I confirmed that withRoot should only be used in a high-level component (e.g. a page). This provides the Material-UI theme to all the nested components. I have changed my starter template to reflect this - I am now only wrapping my Layout component with withRoot - it is the root component used by all the pages in the template.

Thanks to @oorestisime for the insight.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

theduke picture theduke  路  3Comments

jimfilippou picture jimfilippou  路  3Comments

brandonmp picture brandonmp  路  3Comments

Oppenheimer1 picture Oppenheimer1  路  3Comments

mikestopcontinues picture mikestopcontinues  路  3Comments