NextJS Build Errors with SSR and Styled-Components - next.js

I'm deploying a NextJS app to Vercel and I use styled-components. This is my _document.tsx file:
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
import flush from 'styled-jsx/server'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
const styledJSXStyles = flush()
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
{styledJSXStyles}
</>
),
}
} finally {
sheet.seal()
}
}
}
The error I'm seeing from Vercel is that document is not defined at new StyleSheet:
02:22:23 > Build error occurred
02:22:23 ReferenceError: document is not defined
02:22:23 at new StyleSheet (/vercel/workpath0/node_modules/styled-jsx/dist/lib/stylesheet.js:40:35)
02:22:23 at new StyleSheetRegistry (/vercel/workpath0/node_modules/styled-jsx/dist/stylesheet-registry.js:26:33)
02:22:23 at Object.<anonymous> (/vercel/workpath0/node_modules/styled-jsx/dist/style.js:15:26)
02:22:23 at Module._compile (internal/modules/cjs/loader.js:1063:30)
02:22:23 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
02:22:23 at Module.load (internal/modules/cjs/loader.js:928:32)
02:22:23 at Function.Module._load (internal/modules/cjs/loader.js:769:14)
02:22:23 at Module.require (internal/modules/cjs/loader.js:952:19)
02:22:23 at require (internal/modules/cjs/helpers.js:88:18)
02:22:23 at Object.<anonymous> (/vercel/workpath0/node_modules/styled-jsx/dist/server.js:9:14)
02:22:23 at Module._compile (internal/modules/cjs/loader.js:1063:30)
02:22:23 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
02:22:23 at Module.load (internal/modules/cjs/loader.js:928:32)
02:22:23 at Function.Module._load (internal/modules/cjs/loader.js:769:14)
02:22:23 at Module.require (internal/modules/cjs/loader.js:952:19)
02:22:23 at require (internal/modules/cjs/helpers.js:88:18)
I was under the assumption that using SeverStyleSheet in my document file would have fixed this situation, but it does not seem to be the case.
Here are the things I've tried since:
Updating _document.tsx (shown above) to support styled-components and styled-jsx (I don't use the latter, this is a dependency part of NextJS and the source of the error)
Attempted to build locally (builds just fine with npm run build)
Check for presence of the window object in index.tsx and _app.tsx
Checking for the presence of window.fetch before calling fetch in any component
Commented out a rendered iFrame w/ dangerouslySetInnerHTML
What have I not yet considered?

You can test your _document.tsx with this example:
import React from 'react'
import Document, {
DocumentContext,
DocumentInitialProps,
Head,
Html,
Main,
NextScript
} from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />)
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
)
}
} finally {
sheet.seal()
}
}
render(): JSX.Element {
return (
<Html lang="en">
<Head>
<title>your app title</title>
<meta charSet="utf-8" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}

It turns out the issue was with an older version of NextJS, bumping my version from 10.0.6 to 10.0.9 resolved this.

Related

Cannot destructure property 'docComponentsRendered' of '(0 , _react).useContext(...)' as it is null

I'm trying to run a custom document as it says into nextjs docs,
but the app throws an error when I run it. The error is
TypeError: Cannot destructure property 'docComponentsRendered' of '(0 , _react).useContext(...)' as it is null.
enter image description here
Anyway, this is my custom document code:
import Document, {
Html,
Head,
Main,
NextScript,
DocumentContext,
DocumentInitialProps
} from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />)
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
)
}
} finally {
sheet.seal()
}
}
render() {
return (
<Html lang="pt-br">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
I'm running nextjs 13, and trying to configure the styled component.
Could some help me to solve this error?
I already tried to delete the _document, but now the error persists, and I have no idea what is the problem.

Testing NextJS and Jest ReferenceError: TextEncoder is not defined

I am getting this error message while trying to learn how to test next.js applications
I have tried import the Text Encoder from utils at the top of the config as well as test file with no success
ReferenceError: TextEncoder is not defined
at Object.<anonymous> (node_modules/whatwg-url/lib/encoding.js:2:21)
at Object.<anonymous> (node_modules/whatwg-url/lib/url-state-machine.js:5:34)
at Object.<anonymous> (node_modules/whatwg-url/lib/URL-impl.js:2:13)
at Object.<anonymous> (node_modules/whatwg-url/lib/URL.js:442:14)
at Object.<anonymous> (node_modules/whatwg-url/webidl2js-wrapper.js:3:13)
at Object.<anonymous> (node_modules/whatwg-url/index.js:3:34)
at Object.<anonymous> (node_modules/mongodb-connection-string-url/src/index.ts:1:1)
at Object.<anonymous> (node_modules/mongodb/src/connection_string.ts:3:1)
at Object.<anonymous> (node_modules/mongodb/src/mongo_client.ts:11:1)
at Object.<anonymous> (node_modules/mongodb/src/change_stream.ts:17:1)
at Object.<anonymous> (node_modules/mongodb/src/index.ts:3:1)
at Object.<anonymous> (node_modules/mongoose/lib/drivers/node-mongodb-native/binary.js:8:16)
at Object.<anonymous> (node_modules/mongoose/lib/drivers/node-mongodb-native/index.js:7:18)
at Object.<anonymous> (node_modules/mongoose/lib/index.js:7:25)
at Object.<anonymous> (node_modules/mongoose/index.js:8:18)
at Object.<anonymous> (library/mongoDB.js:15:56)
at Object.<anonymous> (library/players.js:15:18)
at Object.<anonymous> (pages/index.js:18:18)
at Object.<anonymous> (tests/index.test.js:6:53)
Jest Config File
const nextJest = require('next/jest')
const createJestConfig = nextJest({
dir: './',
})
const customJestConfig = {
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
}
module.exports = createJestConfig(customJestConfig)
Package.json
"devDependencies": {
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.4.0",
"eslint": "8.23.1",
"eslint-config-next": "12.3.0",
"jest": "^29.1.1",
"jest-environment-jsdom": "^29.1.1"
}
index.test.js
import Home from '../pages/index'
import '#testing-library/jest-dom'
import { fireEvent, render, screen } from '#testing-library/react'
describe('Home Page', () => {
it('renders home component',
() => {
render(<Home />)
expect(screen.getByTestId('home-page')).toBeInTheDocument()
})
})
I would do it by mocking TextEncoder on a dedicated file which will be placed as a setup file on jest config.
This way I think you should get rid of that error.
// text-encoder.mock.ts
import { TextEncoder } from 'util';
global.TextEncoder = TextEncoder;
// jest.config.ts
const nextJest = require('next/jest');
const createJestConfig = nextJest({
dir: './',
});
const customJestConfig = {
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
setupFiles: [
'<rootDir>/path/to/text-encoder.mock.ts',
],
};
module.exports = createJestConfig(customJestConfig)

Having difficulty setting up pinia stores in nuxt 3

I'm currently trying to setup a project using nuxt 3 with pinia for state management and I have bumped into the following error:
[h3] [unhandled] H3Error: defineStore is not defined
at createError (file:///home/johnr/Code/Personal/test/node_modules/h3/dist/index.mjs:191:15)
at Server.nodeHandler (file:///home/johnr/Code/Personal/test/node_modules/h3/dist/index.mjs:381:21) {
statusCode: 500,
fatal: false,
unhandled: true,
statusMessage: 'Internal Server Error'
}
I initialized the project with npx nuxi init and then ran npm i, followed by npm install #pinia/nuxt. I then added pinia to nuxt.config.ts:
// nuxt.config.js
export default {
// ... other options
modules: [
// ...
'#pinia/nuxt',
],
}
and created a basic store in store/counter.js:
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
function increment() {
count.value++;
}
return { count, increment };
});
and have tried to use the returned count in the app template:
<template>
<div>
<p>The count is {{ counterStore.count.value }}</p>
</div>
</template>
<script setup>
import { useCounterStore } from './store/counter.js';
const counterStore = useCounterStore();
</script>
It looks like you forgot to import defineStore in store/counter.js:
import { defineStore } from 'pinia'

Storybook gives error on hotreload in Nextjs with Material ui 5

When I refresh the page, I get correct component loaded up. If the component is Typography and i edit a text. It works fine. The error occurs when i change Typography to Button component. Tried storybook-addon-next-material-ui. Same error there
index.js:56 Unexpected error while loading ./pages/test.stories.tsx: Cannot read properties of undefined (reading 'call')
TypeError: Cannot read properties of undefined (reading 'call')
at __webpack_require__ (http://localhost:6006/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6006/runtime~main.iframe.bundle.js:339:21)
at ./components/test-component.tsx (http://localhost:6006/main.436c782e1c77c7940bf8.hot-update.js:14:71)
at __webpack_require__ (http://localhost:6006/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6006/runtime~main.iframe.bundle.js:339:21)
at ./stories/pages/test.stories.tsx (http://localhost:6006/main.iframe.bundle.js:44:84)
at __webpack_require__ (http://localhost:6006/runtime~main.iframe.bundle.js:28:33)
at fn (http://localhost:6006/runtime~main.iframe.bundle.js:339:21)
at webpackContext (http://localhost:6006/main.iframe.bundle.js:118:9)
at http://localhost:6006/vendors-node_modules_mui_material_Button_Button_js-node_modules_storybook_addon-actions_previ-68b32d.iframe.bundle.js:14244:29
.storybook/main.js
module.exports = {
stories: [
'../stories/**/*.stories.mdx',
'../stories/**/*.stories.#(js|jsx|ts|tsx)',
],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'storybook-addon-next',
],
framework: '#storybook/react',
core: {
builder: 'webpack5',
},
};
test.stories.tsx
import { TestComponent } from '../../components/test-component';
export default {
title: 'Pages',
component: TestComponent,
};
export const TestScreen = () => <TestComponent />;
test-component.tsx
import { Button, Typography } from '#mui/material';
import React from 'react';
export const TestComponent = () => {
return <Typography>TestComponent</Typography>;
};

Next.js and Styled Components go out of sync between the server and the client on refresh

I have a Next.js app using styled components. On first load of any page, there are no complaints, and everything looks properly styled. When I refresh a page however, everything still looks proper, but I get a console error reading:
Warning: Prop `className` did not match. Server: "sc-TXQaF bfnBGK" Client: "sc-bdnylx kKokSB"
I've tried simplifying the styles on the specific component, and the error persists. I've tried removing the component entirely from the DOM, and that results in the same error on the next element in the DOM. So it seems to be a global issue.
I've followed the guide for using Next.js and Styled Components found here: https://github.com/vercel/next.js/tree/master/examples/with-styled-components
I have the .babelrc file in the root:
{
"presets": ["next/babel"],
"plugins": [["styled-components", { "ssr": true }]]
}
I have the _document.js file in my pages directory:
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
Here is an example of one of my styled components:
import styled from 'styled-components';
export const Block = styled.div`
margin: ${props => props.small ? '2rem 0' : '4rem 0'};
margin-top: ${props => props.clearTop ? '0' : null};
`;
... although I've tried to dumb it down to something as simple as this with no change in the console error:
import styled from 'styled-components';
export const Block = styled.div`
position: relative;
`;
Finally, here's a dumbed down page that still produces the error:
import { useContext, useEffect } from 'react';
import { useRouter } from 'next/router';
import Layout from '../components/layout';
import { Block } from '../components/styled/Block';
import { userContext } from '../context/userContext';;
function Profile() {
const router = useRouter();
const { loggedIn } = useContext(userContext);
useEffect(() => {
if (!loggedIn) router.push('/login');
}, [loggedIn]);
return (
<Layout>
<Block>
<h1>Test</h1>
</Block>
</Layout>
)
}
export default Profile;
Kind of at my wits end here.
I believe I figured out an answer. I didn't have the dev dependency for babel styled components.
npm install babel-plugin-styled-components --save-dev
Your package.json file should have this:
"devDependencies": {
"babel-plugin-styled-components": "^1.11.1"
}
After this was installed, along with the _document.js and .babelrc files correctly placed in your app, you shouldn't have any problems.
I had this issue for the last 1 month and finally got a solution that worked for me!
So the solution here is to get the styling exclusively from the server.
from the docs:
Basically you need to add a custom pages/_document.js (if you don't
have one). Then copy the logic for styled-components to inject the
server side rendered styles into the <head>
To solve this issue is you need something like this in your Document component:
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
The final step (if the error persists) is to delete the cache: delete the .next folder and restart the server
The full example code from Next documentation is Here
with the Next Complier on the latest version of next, you should only update your next.config file and _document file, and you will be all set. Babel will cause conflict with the NextJS compiler.
Here you can check the files. If you don't use TS, just replace
ctx: DocumentContext
with only
ctx
Example app with styled-components

Resources