diff --git a/.eslintrc.js b/.eslintrc.js
index df426d33c7..bbae2e5de0 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -26,6 +26,9 @@ module.exports = {
{
files: ['src/frontend/next/**/*.ts', 'src/frontend/next/**/*.tsx'],
plugins: ['@typescript-eslint'],
+ env: {
+ browser: true,
+ },
rules: {
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
diff --git a/src/frontend/next/src/pages/_app.tsx b/src/frontend/next/src/pages/_app.tsx
index 3f6dbc4c92..f0e6982cdc 100644
--- a/src/frontend/next/src/pages/_app.tsx
+++ b/src/frontend/next/src/pages/_app.tsx
@@ -1,8 +1,18 @@
+import { useEffect } from 'react';
import { AppProps } from 'next/app';
import '../styles/globals.css';
-const App = ({ Component, pageProps }: AppProps) => {
+// Reference: https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_app.js
+const AppComponent = ({ Component, pageProps }: AppProps) => {
+ // This hook is for ensuring the styling is sync between client and server
+ useEffect(() => {
+ // Remove the server-side injected CSS.
+ const jssStyles = document.querySelector('#jss-server-side');
+ if (jssStyles) {
+ jssStyles.parentElement?.removeChild(jssStyles);
+ }
+ }, []);
return ;
};
-export default App;
+export default AppComponent;
diff --git a/src/frontend/next/src/pages/_document.tsx b/src/frontend/next/src/pages/_document.tsx
new file mode 100644
index 0000000000..d8dcb14a7f
--- /dev/null
+++ b/src/frontend/next/src/pages/_document.tsx
@@ -0,0 +1,50 @@
+import { Children } from 'react';
+import Document, { Html, Head, Main, NextScript, DocumentContext } from 'next/document';
+import { ServerStyleSheets } from '@material-ui/core/styles';
+
+// Reference: https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_document.js
+class MyDocument extends Document {
+ static async getInitialProps(ctx: DocumentContext) {
+ const initialProps = await Document.getInitialProps(ctx);
+ return { ...initialProps };
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+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(),
+ });
+
+ const initialProps = await Document.getInitialProps(ctx);
+
+ return {
+ ...initialProps,
+ // Styles fragment is rendered after the app and page rendering finish.
+ styles: [...Children.toArray(initialProps.styles), sheets.getStyleElement()],
+ };
+};
+
+export default MyDocument;