Skip to content

Commit 6279dba

Browse files
authored
Avoid direct React client API imports in the server graph (#40686)
We have heuristic checks in the SWC transform to make sure you are not using client-only APIs such as `useState` inside the Server Components graph. However inside our server graph compilation we also have to import the framework and renderer itself (not just the component), and some utility files import these client APIs (because they can be shared by the SSR or client code). Hence we have errors like https://github.com/vercel/next.js/actions/runs/3083270196/jobs/4984135491. To manually opt-out these errors, you can do `import React from 'react'` and use these APIs via `React.useState`. cc @feedthejim ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
1 parent aed2dc0 commit 6279dba

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

packages/next/pages/_document.tsx

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { Component, ReactElement, ReactNode, useContext } from 'react'
1+
import React, { ReactElement, ReactNode, useContext } from 'react'
22
import {
33
OPTIMIZED_FONT_PROVIDERS,
44
NEXT_BUILTIN_DOCUMENT,
@@ -353,7 +353,13 @@ function getAmpPath(ampPath: string, asPath: string): string {
353353
return ampPath || `${asPath}${asPath.includes('?') ? '&' : '?'}amp=1`
354354
}
355355

356-
export class Head extends Component<HeadProps> {
356+
// Use `React.Component` to avoid errors from the RSC checks because
357+
// it can't be imported directly in Server Components:
358+
//
359+
// import { Component } from 'react'
360+
//
361+
// More info: https://github.com/vercel/next.js/pull/40686
362+
export class Head extends React.Component<HeadProps> {
357363
static contextType = HtmlContext
358364

359365
context!: React.ContextType<typeof HtmlContext>
@@ -899,7 +905,7 @@ function handleDocumentScriptLoaderItems(
899905
__NEXT_DATA__.scriptLoader = scriptLoaderItems
900906
}
901907

902-
export class NextScript extends Component<OriginProps> {
908+
export class NextScript extends React.Component<OriginProps> {
903909
static contextType = HtmlContext
904910

905911
context!: React.ContextType<typeof HtmlContext>
@@ -1104,7 +1110,9 @@ export function Main() {
11041110
* `Document` component handles the initial `document` markup and renders only on the server side.
11051111
* Commonly used for implementing server side rendering for `css-in-js` libraries.
11061112
*/
1107-
export default class Document<P = {}> extends Component<DocumentProps & P> {
1113+
export default class Document<P = {}> extends React.Component<
1114+
DocumentProps & P
1115+
> {
11081116
/**
11091117
* `getInitialProps` hook returns the context object with the addition of `renderPage`.
11101118
* `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers

packages/next/shared/lib/flush-effects.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import React, { createContext, useContext } from 'react'
1+
import React, { useContext } from 'react'
22

33
export type FlushEffectsHook = (callbacks: () => React.ReactNode) => void
44

5-
export const FlushEffectsContext = createContext<FlushEffectsHook | null>(
5+
// Use `React.createContext` to avoid errors from the RSC checks because
6+
// it can't be imported directly in Server Components:
7+
//
8+
// import { createContext } from 'react'
9+
//
10+
// More info: https://github.com/vercel/next.js/pull/40686
11+
export const FlushEffectsContext = React.createContext<FlushEffectsHook | null>(
612
null as any
713
)
814

0 commit comments

Comments
 (0)