Material UI is breaking in production with NEXT js

Viewed 210

Someone help me, I built an application with NEXT and Material UI and now for some reason even though the dev server works perfectly fine the productio build is breaking. I tried to alter my _document.ts as shown below:

import Document, { Html, Head, Main, NextScript } from 'next/document';
import React from 'react';
import { ServerStyleSheets } from '@mui/styles';

export default class MyDocument extends Document {
  render() {
    return (
      <Html lang='en'>
        <Head>
          <link rel='preconnect' href='https://fonts.googleapis.com' />
          <link rel='preconnect' href='https://fonts.gstatic.com' />
          <link
            href='https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400&display=swap'
            rel='stylesheet'
          />
        </Head>
        <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 this is _app.tsx:

import '../styles/root.scss';
import '../styles/global/_page.scss';

import { Provider } from 'react-redux';
import type { AppProps } from 'next/app';
import Notification from '../components/Common/Notifications/Notification';
import store from '../redux/app/store';
import React from 'react';
import MIUIHeader from '../components/Common/MUIComponents/MUI-Header/MUIHead';

export default function MyApp({ Component, pageProps }: AppProps) {
  React.useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles) {
      //@ts-ignore
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);
  return (
    <Provider store={store}>
      <React.Fragment>
        <MIUIHeader />
        <Component {...pageProps} />
        <Notification />
      </React.Fragment>
    </Provider>
  );
}

And here's my Material UI Component:

import React, { ReactElement } from 'react';
import TextField from '@mui/material/TextField';
import LocalPhoneIcon from '@mui/icons-material/LocalPhone';
import MuiPhoneNumber from 'material-ui-phone-number';
import Autocomplete from '@mui/material/Autocomplete';
import Button from '@mui/material/Button';

import MailIcon from '@mui/icons-material/Mail';
import PersonIcon from '@mui/icons-material/Person';
import LocationOnIcon from '@mui/icons-material/LocationOn';
import LocationCityIcon from '@mui/icons-material/LocationCity';
import BusinessCenterIcon from '@mui/icons-material/BusinessCenter';
import ShareIcon from '@mui/icons-material/Share';

import classes from './VibeForms.module.scss';
import CorporateFareIcon from '@mui/icons-material/CorporateFare';

import ImageCarasoul from '../../../ImageCarasoul/ImageCarasoul';
interface Props {}

const imagePaths = [
  '/screen-graphics/signup/individual/graphic-1.svg',
  '/screen-graphics/signup/individual/graphic-2.svg',
  '/screen-graphics/signup/individual/graphic-3.svg',
];
const maxMultilineRows = 3;
export default function LoginForm({}: Props): ReactElement {
  return (
    <React.Fragment>
      <div className={classes.LoginColumnGrid}>
        <ImageCarasoul imagePaths={imagePaths} />
        <div className={classes.LoginColumn}>
          <div className={classes.LoginRowGrid}>
            <PersonIcon />
            <TextField
              required
              className={classes.FormInputField}
              label='Full Name'
              size='small'
              type='text'
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <MailIcon />
            <TextField
              required
              className={classes.FormInputField}
              label='Email Address'
              size='small'
              type='email'
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <LocalPhoneIcon />
            <MuiPhoneNumber
              variant='outlined'
              name='phone'
              data-cy='user-phone'
              required
              className={classes.FormInputField}
              label='Phone Number'
              size='small'
              defaultCountry={'in'}
              onChange={(e) => console.log(e)}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <ShareIcon />
            <TextField
              required
              className={classes.FormInputField}
              label='Social Media Links'
              size='small'
              type='text'
              multiline
              maxRows={maxMultilineRows}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <CorporateFareIcon />
            <Autocomplete
              disablePortal
              options={[
                'Workshop/Training',
                'Social Media Promotion',
                'Our Tie Ups',
                'Networking',
              ]}
              renderInput={(params) => (
                <TextField
                  {...params}
                  label='Services you are looking for'
                  required
                  className={classes.FormInputField}
                  size='small'
                />
              )}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <CorporateFareIcon />
            <TextField
              required
              className={classes.FormInputField}
              label='Any Other Specific Requests?'
              size='small'
              type='text'
              multiline
              maxRows={maxMultilineRows}
            />
          </div>
        </div>
        <div className={classes.LoginColumn}>
          <div className={classes.LoginRowGrid}>
            <CorporateFareIcon />
            <Autocomplete
              disablePortal
              options={['Beginer', 'Intermediate', 'Expert']}
              renderInput={(params) => (
                <TextField
                  {...params}
                  label='Enter your Profession'
                  required
                  className={classes.FormInputField}
                  size='small'
                />
              )}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <LocationOnIcon />
            <Autocomplete
              disablePortal
              options={['Bangalore', 'Chennai', 'Hyderabad', 'Mumbai']}
              renderInput={(params) => (
                <TextField
                  {...params}
                  label='State'
                  required
                  className={classes.FormInputField}
                  size='small'
                />
              )}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <LocationCityIcon />
            <Autocomplete
              disablePortal
              options={['Bangalore', 'Chennai', 'Hyderabad']}
              renderInput={(params) => (
                <TextField
                  {...params}
                  label='City'
                  required
                  className={classes.FormInputField}
                  size='small'
                />
              )}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <CorporateFareIcon />
            <Autocomplete
              disablePortal
              options={['Beginer', 'Intermediate', 'Expert']}
              renderInput={(params) => (
                <TextField
                  {...params}
                  label='Profession Level'
                  required
                  className={classes.FormInputField}
                  size='small'
                />
              )}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <BusinessCenterIcon />
            <TextField
              required
              className={classes.FormInputField}
              label='Work Experience'
              size='small'
              type={'number'}
              InputProps={{
                endAdornment: <label>Years</label>,
              }}
            />
          </div>

          <div className={classes.LoginRowGrid}>
            <CorporateFareIcon />
            <TextField
              required
              className={classes.FormInputField}
              label='Your Achievements'
              size='small'
              type='text'
              multiline
              maxRows={maxMultilineRows}
            />
          </div>
        </div>
      </div>
      <Button
        variant='contained'
        style={{ alignSelf: 'end', margin: '1rem', width: '10rem' }}>
        Next
      </Button>
    </React.Fragment>
  );
}

I am using sass modules along with Material UI in NEXT. I tried all the solutions out there mentioned in github and stack overflow but nothing seems to work ;(.

1 Answers

Since most of the documents were outdated to an older version of Material UI, I found the solution in their github repo. They have updated it 20 days back and it works fine. In case someone may want to reference this in future, kindly keep checking this repo.

Here you will find the exact configuration you need to do for _app.tsx and _document.tsx. Additionally you need to also create two files for themes and createEmotionCache as well. The location doesn't matter though.

Related