Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Material UI breaks NextJS app in production

I created a NextJS app which uses server-side rendering and Material UI. It works fine in development.

The app compiles and builds without errors when I run "next build". When I run it with NODE_ENV=production, the webpage renders just fine but many features no longer work. For example:

  1. The "Hidden" component for Material UI never shows any of its sub-components nested within even when it should (in my development app, it hides and shows certain divs depending on screen size).

  2. None of the buttons on the webpage work. All these buttons have "onClick" events whose callback functions modify the React state object in some way when clicked. However, nothing happens when these are clicked. The state remains the same, so I'm assuming these functions never get called when these click events occur. This is true for Material UI's Button components as well as plain old HTML buttons (as JSX).

Everything works completely fine when I run this in dev mode on my laptop. However, when I build the NextJS app and deploy it to the server in production mode, I encounter the problems listed above. So far, my research has only turned up the possibility of class name conflicts during builds (this was said on Material UI's FAQ page). Has anyone had the same problem as I'm having?

EDIT: I just started a barebones NextJS app containing only one index page and minimal dependencies with one state parameter and one button to modify the parameter via an onClick event. I'm having the same problem. The button works in development but not in production. So this would be a NextJS issue rather than a Material UI problem. But that still doesn't explain why the "Hidden" component for Material UI always remains hidden regardless of screen size. Maybe it's both a Next JS and Material UI problem.

like image 274
ron136 Avatar asked Aug 09 '20 09:08

ron136


1 Answers

I think this can help you. in _document.js

import React from 'react';
import Document, {
  Html, Main, NextScript,
} from 'next/document';
import { ServerStyleSheets } from '@material-ui/core/styles';

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang="en">
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {

  // Render app and page and get the context of the page with collected side effects.
  const sheets = new ServerStyleSheets();
  const originalRenderPage = ctx.renderPage;

  ctx.renderPage = () => originalRenderPage({
    enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
  });

  const initialProps = await Document.getInitialProps(ctx);

  return {
    ...initialProps,
    // Styles fragment is rendered after the app and page rendering finish.
    styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
  };
};

and in add in _app.js

React.useEffect(() => {
  // Remove the server-side injected CSS.
  const jssStyles = document.querySelector('#jss-server-side');
  if (jssStyles) {
    jssStyles.parentElement.removeChild(jssStyles);
  }
}, []);

Hope it work !

like image 189
Bao Duong Avatar answered Sep 29 '22 13:09

Bao Duong