diff --git a/docs/advanced-features/dynamic-import.md b/docs/advanced-features/dynamic-import.md index 9bd60726971b592..fd92848067e9958 100644 --- a/docs/advanced-features/dynamic-import.md +++ b/docs/advanced-features/dynamic-import.md @@ -156,3 +156,25 @@ function Home() { export default Home ``` + +## With suspense + +Option `suspense` allows you to lazy-load a component, similar to `React.lazy` and `` with React 18. Note that it only works on client-side or server-side with `fallback`. Full SSR support in concurrent mode is still a work-in-progress. + +```jsx +import dynamic from 'next/dynamic' + +const DynamicLazyComponent = dynamic(() => import('../components/hello4'), { + suspense: true, +}) + +function Home() { + return ( +
+ + + +
+ ) +} +``` diff --git a/errors/invalid-dynamic-suspense.md b/errors/invalid-dynamic-suspense.md new file mode 100644 index 000000000000000..11e4d6134d732fa --- /dev/null +++ b/errors/invalid-dynamic-suspense.md @@ -0,0 +1,13 @@ +# Invalid Usage of `suspense` Option of `next/dynamic` + +#### Why This Error Occurred + +`` is not allowed under legacy render mode when using React older than v18. + +#### Possible Ways to Fix It + +Remove `suspense: true` option in `next/dynamic` usages. + +### Useful Links + +- [Dynamic Import Suspense Usage](https://nextjs.org/docs/advanced-features/dynamic-import#with-suspense) diff --git a/errors/manifest.json b/errors/manifest.json index fc6a3ebb010ebf7..5645b9cd13e89bc 100644 --- a/errors/manifest.json +++ b/errors/manifest.json @@ -151,6 +151,10 @@ "title": "invalid-assetprefix", "path": "/errors/invalid-assetprefix.md" }, + { + "title": "invalid-dynamic-suspense", + "path": "/errors/invalid-dynamic-suspense.md" + }, { "title": "invalid-external-rewrite", "path": "/errors/invalid-external-rewrite.md" diff --git a/packages/next/shared/lib/dynamic.tsx b/packages/next/shared/lib/dynamic.tsx index 771e4b5aaa375a3..8c1f5b3df916d50 100644 --- a/packages/next/shared/lib/dynamic.tsx +++ b/packages/next/shared/lib/dynamic.tsx @@ -119,7 +119,7 @@ export default function dynamic

( 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` + `Invalid suspense option usage in next/dynamic. Read more: https://nextjs.org/docs/messages/invalid-dynamic-suspense` ) } } diff --git a/test/integration/react-18/test/index.test.js b/test/integration/react-18/test/index.test.js index a63d78b92372c84..1b5fef5360a8683 100644 --- a/test/integration/react-18/test/index.test.js +++ b/test/integration/react-18/test/index.test.js @@ -87,7 +87,7 @@ describe('React 18 Support', () => { }) expect(code).toBe(1) expect(stderr).toContain( - 'Disallowed suspense option usage with next/dynamic' + 'Invalid suspense option usage in next/dynamic. Read more: https://nextjs.org/docs/messages/invalid-dynamic-suspense' ) }) }) @@ -130,7 +130,7 @@ describe('Basics', () => { const html = await renderViaHTTP(appPort, '/suspense/unwrapped') unwrappedPage.restore() await killApp(app) - // expect(html).toContain('Disallowed suspense option usage with next/dynamic') + expect(html).toContain( 'A React component suspended while rendering, but no fallback UI was specified' )