Introduction
Next.js is a JavaScript open-source framework built on top of Node.js that enables you to build superfast and extremely user-friendly static websites, as well as web applications using React. React documentation mentions Next.js among "Recommended Toolchains" advising it to developers as a solution when "building a server-rendered website with Node.js.
Material UI is an open-source, front-end framework for React components that has 60,500 plus stars on Github. It is built using Less. Less (stands for Leaner Style Sheets), is a backward-compatible language extension for CSS. Material UI is based on Google’s Material Design to provide a high-quality, digital experience while developing front-end graphics. Material Design focuses on providing bold and crisp designs – it builds textures by focusing on how the components cast shadows and reflect light.
TypeScript adds additional syntax to JavaScript to support a tighter integration with your editor. Catch errors early in your editor. TypeScript code converts to JavaScript, which runs anywhere JavaScript runs: In a browser, on Node.js or Deno, and in your apps.
Installation
Before we get started, let’s confirm that we have Nodejs installed on our machine by running the following command on our terminal:
node --version
and also run the following command to check if NPM installed on our computer
npm --version
If this returns an error, click here to download and install Nodejs on your local machine. Nodejs installation comes with NPM by default, which we’ll be using to install the packages need for this tutorial.
step 1
With Nodejs and NPM installed, let’s begin by installing Nextjs and Typescript by running the following command on our terminal:
npx create-next-app@latest --ts
You will be asked, "What is your project named?" Type in the name you want to give the project and click enter
Step 2
cd into the directory, and type the following command to open the project in VScode:
code .
we don't need to worry about the Typescript setup because the project has come with Typescript setup. let move on to the next step.
step 3
let install Material UI by typing the following command on our terminal
npm install @mui/material @emotion/react @emotion/styled
we need to configure Nextjs to work with Material UI
step 4
let create createEmotionCache.ts to configure emotion to work with material by typing the following command on your terminal
touch createEmotionCache.ts`
copy the following code into the createEmotionCache.ts
import createCache from '@emotion/cache';
const createEmotionCache = () => {
return createCache({ key: 'css' });
};
export default createEmotionCache;
step 5
create a file for Material UI theme, for this tutorial, name the file theme.ts
and copy the following code to the file. to learn more about the Material UI theme click here
import { createTheme } from '@mui/material/styles';
import { red } from '@mui/material/colors';
const theme = createTheme({
palette: {
primary: {
main: '#556cd6',
},
secondary: {
main: '#19857b',
},
error: {
main: red.A400,
},
},
});
export default theme;
step 6
We will be extending the document and injecting the server-side rendered styles into the head. To override that default behavior, you must create a file at ./pages/_document.tsx where you can extend the Document class. copy the following code to the file
import * as React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
import createEmotionServer from '@emotion/server/create-instance';
import theme from '../styles/theme';
import createEmotionCache from '../lib/createEmotionCache';
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
{/* PWA primary color */}
<meta name="theme-color" content={theme.palette.primary.main} />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with static-site generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
const { renderPage: originalRenderPage } = ctx;
// You can consider sharing the same emotion cache between all the SSR requests to speed up performance.
// However, be aware that it can have global side effects.
const cache = createEmotionCache();
const { extractCriticalToChunks } = createEmotionServer(cache);
ctx.renderPage = () =>
originalRenderPage({
// eslint-disable-next-line react/display-name
enhanceApp: (App: any) => (props) =>
<App emotionCache={cache} {...props} />,
});
const initialProps = await Document.getInitialProps(ctx);
// This is important. It prevents emotion to render invalid HTML.
// See https://github.com/mui-org/material-ui/issues/26561#issuecomment-855286153
const emotionStyles = extractCriticalToChunks(initialProps.html);
const emotionStyleTags = emotionStyles.styles.map((style) => (
<style
data-emotion={`${style.key} ${style.ids.join(' ')}`}
key={style.key}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: style.css }}
/>
));
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),
...emotionStyleTags,
],
};
};
step 7
we also need to wrap material UI with the app component, let copy the following lines of code to _app.ts file inside the page folder.
import * as React from 'react';
import Head from 'next/head';
import { AppProps } from 'next/app';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import { CacheProvider, EmotionCache } from '@emotion/react';
import theme from '../styles/theme';
import createEmotionCache from '../../src/lib/createEmotionCache';
// Client-side cache, shared for the whole session of the user in the browser.
const clientSideEmotionCache = createEmotionCache();
interface MyAppProps extends AppProps {
emotionCache?: EmotionCache;
}
const App = (props: MyAppProps) => {
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
return (
<CacheProvider value={emotionCache}>
<Head>
<title>My page</title>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</Head>
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>
);
};
export default App;
Top comments (0)