Skip to content

Commit dd7b85b

Browse files
committed
ignore preload when suspense is set to true
1 parent c10ac7b commit dd7b85b

File tree

9 files changed

+74
-18
lines changed

9 files changed

+74
-18
lines changed

docs/advanced-features/dynamic-import.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,5 +180,5 @@ function Home() {
180180
export default Home
181181
```
182182

183-
If you're using `suspense: true`, `ssr` option will set to `true` to delegate rendering to React `<Suspense />`.
184-
It's similar to using `React.lazy`, but `next/dynamic` will support mode like SSG.
183+
If you set option `suspense` to true, both option `ssr` and `loading` will be omitted, delegating rendering control to React `<Suspense />`.
184+
It's similar to using `React.lazy` directly, but `next/dynamic` will support mode like CSR and SSG.

packages/next/shared/lib/dynamic.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@ export default function dynamic<P = {}>(
124124
}
125125
loadableOptions.suspense = false
126126
}
127+
128+
const { suspense, loader } = loadableOptions
127129
// If suspense is enabled, delegate rendering to suspense
128-
if (loadableOptions.suspense) {
129-
loadableOptions.ssr = true
130+
if (suspense) {
131+
delete loadableOptions.loadableGenerated
132+
delete loadableOptions.loading
133+
delete loadableOptions.ssr
130134
}
131135

132-
const { suspense, ssr, loader, loadableGenerated } = loadableOptions
133-
delete loadableOptions.ssr
134-
delete loadableOptions.loadableGenerated
135-
136136
if (typeof loadableOptions.loader === 'function' && suspense) {
137137
loadableOptions.loader = React.lazy(
138138
loader as () => Promise<{
@@ -142,15 +142,15 @@ export default function dynamic<P = {}>(
142142
}
143143

144144
// coming from build/babel/plugins/react-loadable-plugin.js
145-
if (loadableGenerated) {
145+
if (loadableOptions.loadableGenerated) {
146146
loadableOptions = {
147147
...loadableOptions,
148-
...loadableGenerated,
148+
...loadableOptions.loadableGenerated,
149149
}
150150
}
151151

152152
// support for disabling server side rendering, eg: dynamic(import('../hello-world'), {ssr: false})
153-
if (ssr === false && !suspense) {
153+
if (loadableOptions.ssr === false && !suspense) {
154154
return noSSR(loadableFn, loadableOptions)
155155
}
156156

packages/next/shared/lib/loadable.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ function createLoadableComponent(loadFn, options) {
7272
)
7373

7474
let subscription = null
75-
7675
function init() {
7776
if (opts.suspense) {
7877
return Promise.resolve()
@@ -152,7 +151,6 @@ function createLoadableComponent(loadFn, options) {
152151
}
153152

154153
function LazyImpl(props, ref) {
155-
useDynamicModules(opts.modules)
156154
return React.createElement(opts.loader, { ...props, ref })
157155
}
158156

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Suspense } from 'react'
2+
import dynamic from 'next/dynamic'
3+
4+
const Foo = dynamic(() => import('./foo'), {
5+
suspense: true,
6+
loadableGenerated: {
7+
modules: ['./foo'],
8+
webpack: [require.resolveWeak('./foo')],
9+
},
10+
})
11+
12+
export default function Bar() {
13+
return (
14+
<div>
15+
bar
16+
<Suspense fallback={'oof'}>
17+
<Foo />
18+
</Suspense>
19+
</div>
20+
)
21+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Foo() {
2+
return 'foo'
3+
}

test/integration/react-18/prerelease/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"scripts": {
3+
"next": "node -r ../test/require-hook.js ../../../../packages/next/dist/bin/next",
4+
"dev": "yarn next dev",
5+
"build": "yarn next build",
6+
"start": "yarn next start"
7+
},
28
"dependencies": {
39
"react": "*",
410
"react-dom": "*"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Suspense } from 'react'
2+
import dynamic from 'next/dynamic'
3+
4+
const Bar = dynamic(() => import('../../components/bar'), {
5+
suspense: true,
6+
loadableGenerated: {
7+
modules: ['../../components/bar'],
8+
webpack: [require.resolveWeak('../../components/bar')],
9+
},
10+
})
11+
12+
export default function NoPreload() {
13+
return (
14+
<Suspense fallback={'rab'}>
15+
<Bar />
16+
</Suspense>
17+
)
18+
}

test/integration/react-18/test/dynamic.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { File } from 'next-test-utils'
88
const appDir = join(__dirname, '../prerelease')
99
const page = new File(join(appDir, 'components/dynamic-suspense.js'))
1010

11-
function writeComponent({ ssr = false, suspense = false }) {
11+
function writeDynamicTestComponent({ ssr = false, suspense = false }) {
1212
const content = `import { Suspense } from 'react'
1313
import dynamic from 'next/dynamic'
1414
@@ -36,7 +36,7 @@ export default (context, render) => {
3636
describe('suspense:true option', () => {
3737
describe('promise is thrown on server side', () => {
3838
// let `ssr` option be auto overridden
39-
beforeAll(() => writeComponent({ suspense: true }))
39+
beforeAll(() => writeDynamicTestComponent({ suspense: true }))
4040
afterAll(() => page.restore())
4141

4242
it('should render the fallback on server side', async () => {
@@ -62,7 +62,6 @@ export default (context, render) => {
6262
})
6363

6464
describe('promise is not thrown on server side', () => {
65-
afterAll(() => page.restore())
6665
it('should render fallback on server side', async () => {
6766
const $ = await get$('/suspense/no-thrown')
6867
const text = $('#__next').text()
@@ -84,7 +83,7 @@ export default (context, render) => {
8483
})
8584

8685
describe('suspense:false option', () => {
87-
beforeAll(() => writeComponent({ suspense: false, ssr: false }))
86+
beforeAll(() => writeDynamicTestComponent({ suspense: false, ssr: false }))
8887
afterAll(() => page.restore())
8988

9089
it('should render nothing on server side', async () => {

test/integration/react-18/test/index.test.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { join } from 'path'
44
import fs from 'fs-extra'
55
import webdriver from 'next-webdriver'
6+
import cheerio from 'cheerio'
67
import {
78
File,
89
findPort,
@@ -124,13 +125,23 @@ describe('React 18 basics', () => {
124125
expect(await browser.elementById('react-dom-version').text()).toMatch(/18/)
125126
})
126127

127-
it('SSG works for suspense', async () => {
128+
it('should works with suspense in ssg', async () => {
128129
const res1 = await fetchViaHTTP(context.appPort, '/suspense/thrown')
129130
const res2 = await fetchViaHTTP(context.appPort, '/suspense/no-thrown')
130131

131132
expect(res1.status).toBe(200)
132133
expect(res2.status).toBe(200)
133134
})
135+
136+
it('should not preload modules on server side', async () => {
137+
const html = await renderViaHTTP(context.appPort, '/suspense/no-preload')
138+
const $ = cheerio.load(html)
139+
const nextData = JSON.parse($('#__NEXT_DATA__').text())
140+
const content = $('#__next').text()
141+
// <Bar> is suspended
142+
expect(content).toBe('rab')
143+
expect(nextData.dynamicIds).toBeUndefined()
144+
})
134145
})
135146

136147
describe('Dynamic import', () => {

0 commit comments

Comments
 (0)