Skip to content

Commit

Permalink
Avoid direct React client API imports in the server graph (#40686)
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
shuding authored Sep 19, 2022
1 parent aed2dc0 commit 6279dba
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 6 deletions.
16 changes: 12 additions & 4 deletions packages/next/pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Component, ReactElement, ReactNode, useContext } from 'react'
import React, { ReactElement, ReactNode, useContext } from 'react'
import {
OPTIMIZED_FONT_PROVIDERS,
NEXT_BUILTIN_DOCUMENT,
Expand Down Expand Up @@ -353,7 +353,13 @@ function getAmpPath(ampPath: string, asPath: string): string {
return ampPath || `${asPath}${asPath.includes('?') ? '&' : '?'}amp=1`
}

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

context!: React.ContextType<typeof HtmlContext>
Expand Down Expand Up @@ -899,7 +905,7 @@ function handleDocumentScriptLoaderItems(
__NEXT_DATA__.scriptLoader = scriptLoaderItems
}

export class NextScript extends Component<OriginProps> {
export class NextScript extends React.Component<OriginProps> {
static contextType = HtmlContext

context!: React.ContextType<typeof HtmlContext>
Expand Down Expand Up @@ -1104,7 +1110,9 @@ export function Main() {
* `Document` component handles the initial `document` markup and renders only on the server side.
* Commonly used for implementing server side rendering for `css-in-js` libraries.
*/
export default class Document<P = {}> extends Component<DocumentProps & P> {
export default class Document<P = {}> extends React.Component<
DocumentProps & P
> {
/**
* `getInitialProps` hook returns the context object with the addition of `renderPage`.
* `renderPage` callback executes `React` rendering logic synchronously to support server-rendering wrappers
Expand Down
10 changes: 8 additions & 2 deletions packages/next/shared/lib/flush-effects.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import React, { createContext, useContext } from 'react'
import React, { useContext } from 'react'

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

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

Expand Down

0 comments on commit 6279dba

Please sign in to comment.