Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on suspense in blocking rendering mode #28117

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 5 additions & 9 deletions packages/next/shared/lib/dynamic.tsx
Expand Up @@ -114,15 +114,11 @@ export default function dynamic<P = {}>(
loadableOptions = { ...loadableOptions, ...options }

const suspenseOptions = loadableOptions as LoadableSuspenseOptions<P>
if (!process.env.__NEXT_CONCURRENT_FEATURES) {
// Error if react root is not enabled and `suspense` option is set to true
if (!process.env.__NEXT_REACT_ROOT && suspenseOptions.suspense) {
// TODO: add error doc when this feature is stable
throw new Error(
`Disallowed suspense option usage with next/dynamic in blocking mode`
)
}
suspenseOptions.suspense = false
if (!process.env.__NEXT_CONCURRENT_FEATURES && suspenseOptions.suspense) {
// TODO: add error doc when this feature is stable
throw new Error(
`Disallowed suspense option usage with next/dynamic in blocking mode`
)
}
if (suspenseOptions.suspense) {
return loadableFn(suspenseOptions)
Expand Down
21 changes: 11 additions & 10 deletions packages/next/shared/lib/loadable.js
Expand Up @@ -71,8 +71,14 @@ function createLoadableComponent(loadFn, options) {
options
)

let lazyComponent
if (opts.suspense) {
opts.lazy = React.lazy(opts.loader)
lazyComponent = React.lazy(opts.loader)
return LazyImpl
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feel like we don't really need this option in next/dynamic if it only supports concurrent mode? dynamic(loader, {suspense: true}) equals React.lazy(loader). thoughts? @shuding @devknoll

}

function LazyImpl(props) {
return React.createElement(lazyComponent, props)
}

let subscription = null
Expand All @@ -90,7 +96,7 @@ function createLoadableComponent(loadFn, options) {
}

// Server only
if (typeof window === 'undefined' && !opts.suspense) {
if (typeof window === 'undefined') {
ALL_INITIALIZERS.push(init)
}

Expand All @@ -99,8 +105,7 @@ function createLoadableComponent(loadFn, options) {
!initialized &&
typeof window !== 'undefined' &&
typeof opts.webpack === 'function' &&
typeof require.resolveWeak === 'function' &&
!opts.suspense
typeof require.resolveWeak === 'function'
) {
const moduleIds = opts.webpack()
READY_INITIALIZERS.push((ids) => {
Expand Down Expand Up @@ -148,12 +153,8 @@ function createLoadableComponent(loadFn, options) {
}, [props, state])
}

function LazyImpl(props, ref) {
return React.createElement(opts.lazy, { ...props, ref })
}

const LoadableComponent = opts.suspense ? LazyImpl : LoadableImpl
LoadableComponent.preload = () => !opts.suspense && init()
const LoadableComponent = LoadableImpl
LoadableComponent.preload = () => init()
LoadableComponent.displayName = 'LoadableComponent'

return React.forwardRef(LoadableComponent)
Expand Down
10 changes: 0 additions & 10 deletions test/integration/react-18/app/pages/suspense/unwrapped.js

This file was deleted.

31 changes: 0 additions & 31 deletions test/integration/react-18/test/basics.js

This file was deleted.

27 changes: 0 additions & 27 deletions test/integration/react-18/test/blocking.js

This file was deleted.

28 changes: 4 additions & 24 deletions test/integration/react-18/test/index.test.js
Expand Up @@ -12,9 +12,7 @@ import {
nextStart,
renderViaHTTP,
} from 'next-test-utils'
import blocking from './blocking'
import concurrent from './concurrent'
import basics from './basics'

jest.setTimeout(1000 * 60 * 5)

Expand Down Expand Up @@ -80,14 +78,6 @@ describe('React 18 Support', () => {
expect(output).not.toMatch(USING_CREATE_ROOT)
expect(output).not.toMatch(UNSUPPORTED_PRERELEASE)
})

it('suspense is not allowed in blocking rendering mode', async () => {
const appPort = await findPort()
const app = await launchApp(appDir, appPort)
const html = await renderViaHTTP(appPort, '/suspense/unwrapped')
await killApp(app)
expect(html).toContain(SUSPENSE_ERROR_MESSAGE)
})
})

describe('warns with stable supported version of react-dom', () => {
Expand Down Expand Up @@ -117,13 +107,6 @@ describe('React 18 Support', () => {
})
})

describe('Basics', () => {
runTests('default setting with react 18', 'dev', (context) => basics(context))
runTests('default setting with react 18', 'prod', (context) =>
basics(context)
)
})

describe('Blocking mode', () => {
beforeAll(() => {
dynamicHello.replace('suspense = false', `suspense = true`)
Expand All @@ -132,13 +115,10 @@ describe('Blocking mode', () => {
dynamicHello.restore()
})

runTests('concurrentFeatures is disabled', 'dev', (context) =>
blocking(context, (p, q) => renderViaHTTP(context.appPort, p, q))
)

runTests('concurrentFeatures is disabled', 'prod', (context) =>
blocking(context, (p, q) => renderViaHTTP(context.appPort, p, q))
)
it('suspense is not allowed in blocking rendering mode (prod)', async () => {
const output = await getBuildOutput(appDir)
expect(output).toContain(SUSPENSE_ERROR_MESSAGE)
})
})

describe('Concurrent mode', () => {
Expand Down