first commit
Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled

This commit is contained in:
Arian Tron
2026-03-10 19:37:31 +03:30
commit 61f56f997c
27684 changed files with 2784175 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
import { DynamicComponent } from '../client-reference'
export async function GET() {
return new Response('Hello ' + typeof DynamicComponent)
}

View File

@@ -0,0 +1,5 @@
'use client'
export default function () {
return <h1>hello</h1>
}

View File

@@ -0,0 +1,13 @@
// This file is needed for the test, to ensure that the "comp.js" module is
// created as a dynamic import chunk.
'use client'
function noop() {}
export default function Page() {
import('./comp').then((m) => {
noop(m)
})
return null
}

View File

@@ -0,0 +1,5 @@
import Comp from '../comp'
export default function Page() {
return <Comp />
}

View File

@@ -0,0 +1,5 @@
'use client'
import dynamic from 'next/dynamic'
export const DynamicComponent = dynamic(() => import('./dynamic-component'))

View File

@@ -0,0 +1,12 @@
const isDevTest = false
const DynamicImportComponent = () => {
if (isDevTest && typeof window === 'undefined') {
throw new Error('This component should only be rendered on the client side')
}
return (
<div id="dynamic-component">This is a dynamically imported component</div>
)
}
export default DynamicImportComponent

View File

@@ -0,0 +1,26 @@
'use client'
import dynamic from 'next/dynamic'
const DynamicHeader = dynamic(
() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(import('./dynamic-component'))
}, 1000)
})
},
{
loading: () => <p>Loading...</p>,
}
)
const Page = () => {
return (
<div>
<DynamicHeader />
</div>
)
}
export default Page

View File

@@ -0,0 +1,7 @@
const DynamicImportComponent = () => {
return (
<div id="dynamic-component">This is a dynamically imported component</div>
)
}
export default DynamicImportComponent

View File

@@ -0,0 +1,21 @@
'use client'
import dynamic from 'next/dynamic'
const DynamicHeader = dynamic(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(import('./dynamic-component'))
}, 1000)
})
})
const Page = () => {
return (
<div>
<DynamicHeader />
</div>
)
}
export default Page

View File

@@ -0,0 +1,7 @@
const DynamicImportComponent = () => {
return (
<div id="dynamic-component">This is a dynamically imported component</div>
)
}
export default DynamicImportComponent

View File

@@ -0,0 +1,5 @@
'use client'
export { default } from '../dynamic-import'
export const runtime = 'edge'

View File

@@ -0,0 +1,3 @@
'use client'
export { default } from '../dynamic-import'

View File

@@ -0,0 +1,14 @@
import dynamic from 'next/dynamic'
const DynamicSSRFalse = dynamic(() => import('./ssr-false-module'), {
ssr: false,
})
export default function page() {
return (
<div>
<DynamicSSRFalse />
<p id="content">dynamic-mixed-ssr-false</p>
</div>
)
}

View File

@@ -0,0 +1,11 @@
import Client from './ssr-false-client'
// import Server from './ssr-false-server'
export default function Comp() {
return (
<>
<Client />
{/* <Server /> */}
</>
)
}

View File

@@ -0,0 +1,5 @@
'use client'
export default function Comp() {
return <p id="ssr-false-client-module">ssr-false-client-module-text</p>
}

View File

@@ -0,0 +1,3 @@
export default function Comp() {
return <p id="ssr-false-server-module">ssr-false-server-module-text</p>
}

View File

@@ -0,0 +1,7 @@
'use client'
let name = await Promise.resolve('async')
export default (props) => {
return <button {...props}>this is an {name} client button</button>
}

View File

@@ -0,0 +1,7 @@
'use client'
let name = await Promise.resolve('async')
export default (props) => {
return <button {...props}>this is an {name} client button with SSR</button>
}

View File

@@ -0,0 +1,15 @@
'use client'
import dynamic from 'next/dynamic'
const Client1 = dynamic(() => import('./client'))
const Client2 = dynamic(() => import('./client-no-ssr'), { ssr: false })
export default function Page() {
return (
<>
<Client1 id="client-button" />
<Client2 id="client-button-no-ssr" />
</>
)
}

View File

@@ -0,0 +1,17 @@
'use client'
import dynamic from 'next/dynamic'
const Dynamic = dynamic(() => import('../text-dynamic-client'))
const DynamicNoSSR = dynamic(() => import('../text-dynamic-no-ssr-client'), {
ssr: false,
})
export function NextDynamicClientComponent() {
return (
<>
<Dynamic />
<DynamicNoSSR name=":suffix" />
</>
)
}

View File

@@ -0,0 +1,14 @@
import dynamic from 'next/dynamic'
export const NextDynamicServerComponent = dynamic(
() => import('../text-dynamic-server')
)
// export const NextDynamicNoSSRServerComponent = dynamic(
// () => import('../text-dynamic-no-ssr-server'),
// {
// ssr: false,
// }
// )
export const NextDynamicServerImportClientComponent = dynamic(
() => import('../text-dynamic-server-import-client')
)

View File

@@ -0,0 +1,15 @@
'use client'
import { useState, lazy } from 'react'
const Lazy = lazy(() => import('../text-lazy-client'))
export function LazyClientComponent() {
let [state] = useState('use client')
return (
<>
<Lazy />
<p className="hi">next-dynamic {state}</p>
</>
)
}

View File

@@ -0,0 +1,3 @@
.dynamic {
color: blue;
}

View File

@@ -0,0 +1,3 @@
.lazy {
color: purple;
}

View File

@@ -0,0 +1,5 @@
'use client'
export function Button(props) {
return <button {...props} />
}

View File

@@ -0,0 +1,11 @@
import dynamic from 'next/dynamic'
const Button = dynamic(() =>
import('./client').then((mod) => {
return mod.Button
})
)
export default function Page() {
return <Button id="client-button">this is a client button</Button>
}

View File

@@ -0,0 +1,19 @@
import { LazyClientComponent } from './dynamic-imports/react-lazy-client'
import { NextDynamicClientComponent } from './dynamic-imports/dynamic-client'
import {
NextDynamicServerComponent,
NextDynamicServerImportClientComponent,
// NextDynamicNoSSRServerComponent,
} from './dynamic-imports/dynamic-server'
export default function page() {
return (
<div id="content">
<LazyClientComponent />
<NextDynamicServerComponent />
<NextDynamicClientComponent />
<NextDynamicServerImportClientComponent />
{/* <NextDynamicNoSSRServerComponent /> */}
</div>
)
}

View File

@@ -0,0 +1,5 @@
'use client'
export default function TextClient() {
return <p>client component under sever no ssr</p>
}

View File

@@ -0,0 +1,13 @@
'use client'
import { useState } from 'react'
import styles from './dynamic.module.css'
export default function Dynamic() {
let [state] = useState('dynamic on client')
return (
<p id="css-text-dynamic-client" className={styles.dynamic}>
{`next-dynamic ${state}`}
</p>
)
}

View File

@@ -0,0 +1,13 @@
'use client'
import { useState } from 'react'
import styles from './dynamic.module.css'
export default function Dynamic({ name }) {
let [state] = useState('dynamic no ssr on client' + name)
return (
<p id="css-text-dynamic-no-ssr-client" className={styles.dynamic}>
{`next-dynamic ${state}`}
</p>
)
}

View File

@@ -0,0 +1,12 @@
// import TextClient from './text-client'
// export default function Dynamic() {
// return (
// <>
// <p id="css-text-dynamic-no-ssr-server">
// next-dynamic dynamic no ssr on server
// </p>
// <TextClient />
// </>
// )
// }

View File

@@ -0,0 +1,9 @@
'use client'
export default function ClientImportedByServer() {
return (
<p id="text-dynamic-server-import-client">
next-dynamic server import client
</p>
)
}

View File

@@ -0,0 +1,9 @@
import styles from './dynamic.module.css'
export default function Dynamic() {
return (
<p id="css-text-dynamic-server" className={styles.dynamic}>
next-dynamic dynamic on server
</p>
)
}

View File

@@ -0,0 +1,13 @@
'use client'
import styles from './lazy.module.css'
export default function LazyComponent() {
return (
<>
<p id="css-text-lazy" className={styles.lazy}>
next-dynamic lazy
</p>
</>
)
}

View File

@@ -0,0 +1,10 @@
export default function Root({ children }) {
return (
<html>
<body>
<header>top bar</header>
{children}
</body>
</html>
)
}

View File

@@ -0,0 +1,14 @@
import { DynamicComponent } from './client-reference'
globalThis.foo = DynamicComponent
export default function sitemap() {
return [
{
url: 'https://acme.com',
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
},
]
}

View File

@@ -0,0 +1,168 @@
import { nextTestSetup } from 'e2e-utils'
import { retry } from 'next-test-utils'
import path from 'path'
describe('app dir - next/dynamic', () => {
const { next, isNextStart, isNextDev, skipped } = nextTestSetup({
files: __dirname,
skipDeployment: true,
})
if (skipped) {
return
}
it('should handle ssr: false in pages when appDir is enabled', async () => {
const $ = await next.render$('/legacy/no-ssr')
expect($.html()).not.toContain('navigator')
const browser = await next.browser('/legacy/no-ssr')
expect(await browser.waitForElementByCss('#pure-client').text()).toContain(
'navigator'
)
})
it('should handle next/dynamic in SSR correctly', async () => {
const $ = await next.render$('/dynamic')
// filter out the script
const selector = 'body div'
const serverContent = $(selector).text()
// should load chunks generated via async import correctly with React.lazy
expect(serverContent).toContain('next-dynamic lazy')
// should support `dynamic` in both server and client components
expect(serverContent).toContain('next-dynamic dynamic on server')
expect(serverContent).toContain('next-dynamic dynamic on client')
expect(serverContent).toContain('next-dynamic server import client')
expect(serverContent).not.toContain('next-dynamic dynamic no ssr on client')
})
it('should handle next/dynamic in hydration correctly', async () => {
const browser = await next.browser('/dynamic')
await browser.waitForElementByCss('#css-text-dynamic-no-ssr-client')
expect(
await browser.elementByCss('#css-text-dynamic-no-ssr-client').text()
).toBe('next-dynamic dynamic no ssr on client:suffix')
})
it('should generate correct client manifest for dynamic chunks', async () => {
const $ = await next.render$('/chunk-loading/server')
expect($('h1').text()).toBe('hello')
})
it('should render loading by default if loading is specified and loader is slow', async () => {
const $ = await next.render$('/default-loading')
// First render in dev should show loading, production build will resolve the content.
expect($('body').text()).toContain(
isNextDev ? 'Loading...' : 'This is a dynamically imported component'
)
})
it('should not render loading by default', async () => {
const $ = await next.render$('/default')
expect($('#dynamic-component').text()).not.toContain('loading')
})
it('should ignore next/dynamic in routes', async () => {
const response = await next.fetch('/api')
expect(await response.text()).toEqual('Hello function')
})
it('should ignore next/dynamic in sitemap', async () => {
const response = await next.fetch('/sitemap.xml')
expect(await response.text()).toInclude('<changefreq>yearly</changefreq>')
})
if (isNextDev) {
it('should directly raise error when dynamic component error on server', async () => {
const pagePath = 'app/default-loading/dynamic-component.js'
const page = await next.readFile(pagePath)
await next.patchFile(
pagePath,
page.replace('const isDevTest = false', 'const isDevTest = true')
)
await retry(async () => {
const { status } = await next.fetch('/default-loading')
expect(status).toBe(200)
})
})
}
describe('no SSR', () => {
it('should not render client component imported through ssr: false in client components in edge runtime', async () => {
// noSSR should not show up in html
const $ = await next.render$('/dynamic-mixed-ssr-false/client-edge')
expect($('#server-false-client-module')).not.toContain(
'ssr-false-client-module-text'
)
// noSSR should not show up in browser
const browser = await next.browser('/dynamic-mixed-ssr-false/client-edge')
expect(
await browser.elementByCss('#ssr-false-client-module').text()
).toBe('ssr-false-client-module-text')
// in the server bundle should not contain client component imported through ssr: false
if (isNextStart) {
const middlewareManifest = JSON.parse(
await next.readFile('.next/server/middleware-manifest.json')
)
const uniquePageFiles = [
...new Set<string>(
middlewareManifest.functions[
'/dynamic-mixed-ssr-false/client-edge/page'
].files
),
]
for (const file of uniquePageFiles) {
const contents = await next.readFile(path.join('.next', file))
expect(contents).not.toContain('ssr-false-client-module-text')
}
}
})
it('should not render client component imported through ssr: false in client components', async () => {
// noSSR should not show up in html
const $ = await next.render$('/dynamic-mixed-ssr-false/client')
expect($('#client-false-client-module')).not.toContain(
'ssr-false-client-module-text'
)
// noSSR should not show up in browser
const browser = await next.browser('/dynamic-mixed-ssr-false/client')
expect(
await browser.elementByCss('#ssr-false-client-module').text()
).toBe('ssr-false-client-module-text')
// in the server bundle should not contain both server and client component imported through ssr: false
if (isNextStart) {
const pageServerChunk = await next.readFile(
'.next/server/app/dynamic-mixed-ssr-false/client/page.js'
)
expect(pageServerChunk).not.toContain('ssr-false-client-module-text')
}
})
it('should support dynamic import with accessing named exports from client component', async () => {
const $ = await next.render$('/dynamic/named-export')
expect($('#client-button').text()).toBe('this is a client button')
})
it('should support dynamic import with TLA in client components', async () => {
const $ = await next.render$('/dynamic/async-client')
expect($('#client-button').text()).toBe(
'this is an async client button with SSR'
)
expect($('#client-button-no-ssr').text()).toBe('')
const browser = await next.browser('/dynamic/async-client')
expect(await browser.elementByCss('#client-button').text()).toBe(
'this is an async client button with SSR'
)
expect(await browser.elementByCss('#client-button-no-ssr').text()).toBe(
'this is an async client button'
)
})
})
})

View File

@@ -0,0 +1,3 @@
module.exports = {
reactStrictMode: true,
}

View File

@@ -0,0 +1,5 @@
import dynamic from 'next/dynamic'
const PureClient = dynamic(() => import('../../ui/pure-client'), { ssr: false })
export default PureClient

View File

@@ -0,0 +1,5 @@
window.ua = navigator.userAgent
export default function PureClient() {
return <p id="pure-client">navigator</p>
}