error in _document.js when run build next js - reactjs

I'm getting two errors when I try to yarn run build my nextJS project:
3:1 Error: next/document should not be imported outside of pages/_document.js.
See https://nextjs.org/docs/messages/no-document-import-in-page. #next/next/no-document-import-in-page
13:38 Error: Component definition is missing display name react/display-name
the first error doesn't make sense to me, see the path of my _document.js:
the second, doesn'nt uderstand, my _document.js:
import Document, { Head, Main, NextScript } from "next/document";
// Import styled components ServerStyleSheet
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
// Step 1: Create an instance of ServerStyleSheet
const sheet = new ServerStyleSheet();
// Step 2: Retrieve styles from components in the page
const page = renderPage(
(App) => (props) => sheet.collectStyles(<App {...props} />)
);
// Step 3: Extract the styles as <style> tags
const styleTags = sheet.getStyleElement();
// Step 4: Pass styleTags as a prop
return { ...page, styleTags };
}
render() {
return (
<html>
<Head>
<title>My app</title>
{/* Step 5: Output the styles in the head */}
{this.props.styleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
I already tried to install the canary new version (npm install next#11.1.3-canary.15), (saw this solution in another post) but doesn't work.
any tip, please?

Related

document is not defined when creating new portal in Nextjs

in my project I want to separate section like menu in header tag, content in main tag and contact in footer tag _document.js file, for this I created a new portal but I get an error document is not defined in my Header.js file.
I trying to create new portal in nextjs like this:
import React, { Fragment } from "react";
import ReactDOM from "react-dom";
import NavigationBar from "./NavigationBar";
import classes from "./header.module.css";
const Header = (props) => {
return (
<Fragment>
{ReactDOM.createPortal(
<NavigationBar>{props.children}</NavigationBar>,
document.getElementById("header")
)}
</Fragment>
);
};
export default Header;
I created _document.js:
import Document, { Html, Head, Main, NextScript } from "next/document";
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
return (
<Html lang="en" dir="ltr">
<Head />
<body>
<header id="header"></header>
<Main />
<footer id="_footer"></footer>
<div id="_modal"></div>
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
The error is thrown because document is only available inside the browser and not on the server. Next js executes this code on the server side and that's why the error is thrown.
You can wrap our code inside an if statement. If you check on the console the type of window it returns object. The following code illustrates this:
if (typeof window === 'object') {
// Check if document is finally loaded
}
Use React portal maker:
import React from "react";
import reactDom from "react-dom";
const Header = (props) => {
const content = <NavigationBar>{props.children}</NavigationBar>;
if (typeof window === "object") {
return reactDom.createPortal(content, document.getElementById("__header"));
}
return null;
};
export default Header ;

Loading p5js of react-p5 npm package to NextJS app shows "ReferenceError: window is not defined"

This is my Code Which I got from react-p5 typescript Example and modified it a bit
import Sketch from "react-p5";
import p5Types from "p5";
type InputParameterType = {};
function P5JsComponent({}: InputParameterType) {
let x = 50;
const y = 50;
//See annotations in JS for more information
const setup = (p5: p5Types, canvasParentRef: Element) => {
p5.createCanvas(500, 500).parent(canvasParentRef);
};
const draw = (p5: p5Types) => {
p5.background(0);
p5.ellipse(x, y, 70, 70);
x++;
};
return <Sketch setup={setup} draw={draw} />;
}
export default P5JsComponent;
My Parent Component in My NextJs App is 'homepage.tsx' which is present in the pages directory.
import Head from "next/head";
import P5JsComponent from "#/components/P5JsComponent";
function homepage() {
return (
<div>
<Head>
<title>My App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<P5JsComponent />
</div>
);
}
export default homepage;
I am getting a ReferenceError: window is not defined error when I run this code.
In server-side-rendering, we haven't global variables from the browser, like the "window" variable.
P5JsComponent must be rendered on the client-side.
Import P5JsComponent with no SSR:
const P5JsComponent = dynamic(
() => import("#/components/P5JsComponent"),
{ ssr: false }
)
ref: https://nextjs.org/docs/advanced-features/dynamic-import

Error: "MyDocument.getInitialProps()" should resolve to an object with a "html" prop set with a valid html string

My project is in https://github.com/Talita1996/NLW4
I created a project with the command yarn create next-app project_name
I changed the extension of some files and added some code
I installed typescript with the command yarn add typescript #types/react #types/react-dom #types/node -D
On the first day everything worked fine, but today, when I call yarn dev I get the error:
in your page/_document you need to extend Document class
import Document, { Html, Head, Main, NextScript } from 'next/document';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght#400;500;600&family=Rajdhani:wght#600&display=swap" rel="stylesheet" />
</Head>
<body>
<Main/>
<NextScript/>
</body>
</Html>
);
}
}
Here's a solution using a function component, and fully typed with TypeScript.
import NextDocument, { Html, Head, Main, NextScript } from 'next/document'
import type { DocumentContext, DocumentInitialProps } from 'next/document'
const Document = () => {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
Document.getInitialProps = async (ctx: DocumentContext): Promise<DocumentInitialProps> => {
const initialProps = await NextDocument.getInitialProps(ctx)
return { ...initialProps }
}
export default Document
As pointed out in previous answers, you have to call await Document.getInitialProps(ctx) and spread the returned object in the getInitialProps's return statement.
Please check if you have missed 'await' and then ad it :
static async getInitialProps(ctx){
const initialProps = await Document.getInitialProps(ctx)
return {...initialProps, locale: ctx?.locale || "fr"}
}

Nextjs css flickering

I'm building a react app using material ui and nextjs. I'm using <Autocomplete /> component, provided by material UI and override some its styles with my own like this:
<Autocomplete
classes={{
root: `${styles[`search__autocomplete`]} ${
styles[`search--${variant}__autocomplete`]
}`,
inputRoot: `${styles[`search__autocomplete-input`]} ${
styles[`search--${variant}__autocomplete-input`]
}`
}}
/>
variant is a prop, which gets passed to the component and styles is a variable, which get imported from the css module: import styles from "Search.module.sass".
Now, when I'm working on this locally everything looks great:
But, after I deploy it to production via next build && next export I start experiencing "flickering" effect when for like 1/3 of a second my page looks like this:
My guess is that it might be related to the fact that nextjs export my css to several files on production:
<link
rel="preload"
href="/_next/static/css/4dcd7fa805fb41261f08.css"
as="style"
/>
<link
rel="stylesheet"
href="/_next/static/css/4dcd7fa805fb41261f08.css"
data-n-g=""
/>
<link
rel="preload"
href="/_next/static/css/a23cf79bceae4047fddb.css"
as="style"
/>
<link
rel="stylesheet"
href="/_next/static/css/a23cf79bceae4047fddb.css"
data-n-p=""
/>
How can I solve that?
The solution was to create a custom pages/_document.js page with:
import React from 'react';
// Modules
import Document, { Html, Head, Main, NextScript } from 'next/document';
// MUI Core
import { ServerStyleSheets } from '#material-ui/core/styles';
class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans:wght#300;400;600;700&display=swap" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side rendering (SSR).
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
// 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(),
],
};
};
export default MyDocument;
In my case it was caused by the <CacheProvider> component of #emotion/react removing it from _app.js file fixed the problem for me
Nextjs is now supporting SSR with emotion you can enable it this way in next.config.js file :
const nextConfig = {
//...
compiler: {
emotion: true,
},
};
Also if using <CssBaseline/> component of Material UI replace it with <ScopedCssBaseline>
However, you might be progressively migrating a website to MUI, using a global reset might not be an option. It's possible to apply the baseline only to the children by using the ScopedCssBaseline component.
import { ScopedCssBaseline } from "#mui/material";
//...
<ScopedCssBaseline>
<Component {...pageProps} />
</ScopedCssBaseline>
//...

Intense FOUC when using Next.js 8 and styled-jsx

I have recently upgraded to Next.js 8.0.3 from 6.1.1 and I am now encountering a very intense flash of un-styled content (FOUC) for my header content which is using styled-jsx. It loaded just fine before updating Next.js.
The header code that is flashing is a custom built npm module that uses styled-jsx (but not next) and is being imported and placed into a layout page that is rendered with every next page.
This was the implementation in the _document.js file before updating next and it was working:
import Document, { Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet, injectGlobal } from 'styled-components'
import styledNormalize from 'styled-normalize'
import flush from 'styled-jsx/server'
injectGlobal`
${styledNormalize}
`
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const sheet = new ServerStyleSheet()
const page = renderPage(App => props =>
sheet.collectStyles(<App {...props} />)
)
const styleTags = sheet.getStyleElement()
const styles = flush()
return { ...page, styleTags, styles }
}
render() {
return (
<html>
<Head>
{this.props.styleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
)
}
}
Based on the docs I have also tried this (where I wait for the initial props):
import Document, { Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet, injectGlobal } from 'styled-components'
import styledNormalize from 'styled-normalize'
import flush from 'styled-jsx/server'
injectGlobal`
${styledNormalize}
`
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const page = ctx.renderPage(App => props =>
sheet.collectStyles(<App {...props} />)
)
const initialProps = await Document.getInitialProps(ctx)
const styleTags = sheet.getStyleElement()
const styles = flush()
return { ...initialProps, ...page, styles, styleTags }
}
render() {
return (
<html>
<Head>
{this.props.styleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</html>
)
}
}
The flash might be a result of where I am implementing the module but not sure.
It seems like the code coming in from the module is not being properly bundled with the rest of the pages and thus giving the page flash. Any thoughts or feedback would be appreciated.
I ended up fixing the issue by refactoring the custom npm module to not use styled-jsx but instead use styled-components. Not really a fix but more of a work around

Resources