forked from vercel/next.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Alias next/dynamic to lazy impl for appDir (vercel#41216)
Since `next/dynamic` has client hooks that not compatible with server components, and app renderer doesn't provide context (such as `LoadableContext`) for it to use. Previously we provided a simple replacement using `React.lazy` for `next/dynamic` if you want to use it in appDir. This PR always alias it to the `React.lazy ` implementation for appDir so that user won't need to worry about the dynamic options. They can only use `dynamic()` without 2nd options arg ```js import dynamic from 'next/dynamic' const Dynamic = dynamic(() => import('./dynamic-component')) ```
- Loading branch information
Showing
40 changed files
with
164 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
'client' | ||
|
||
import React from 'react' | ||
import Loadable from './loadable' | ||
|
||
|
2 changes: 1 addition & 1 deletion
2
test/e2e/app-dir/app/app/dashboard/index/dynamic-imports/dynamic-client.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
test/e2e/app-dir/app/app/dashboard/index/dynamic-imports/dynamic-server.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
7 changes: 0 additions & 7 deletions
7
test/e2e/app-dir/rsc-basic/components/random-module-instance.js
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import path from 'path' | ||
import { renderViaHTTP, fetchViaHTTP } from 'next-test-utils' | ||
import { createNext, FileRef } from 'e2e-utils' | ||
import { NextInstance } from 'test/lib/next-modes/base' | ||
|
||
async function resolveStreamResponse(response: any, onData?: any) { | ||
let result = '' | ||
onData = onData || (() => {}) | ||
await new Promise((resolve) => { | ||
response.body.on('data', (chunk) => { | ||
result += chunk.toString() | ||
onData(chunk.toString(), result) | ||
}) | ||
|
||
response.body.on('end', resolve) | ||
}) | ||
return result | ||
} | ||
|
||
describe('app dir - rsc external dependency', () => { | ||
let next: NextInstance | ||
|
||
if ((global as any).isNextDeploy) { | ||
it('should skip for deploy mode for now', () => {}) | ||
return | ||
} | ||
|
||
beforeAll(async () => { | ||
next = await createNext({ | ||
files: new FileRef(path.join(__dirname, './rsc-external')), | ||
dependencies: { | ||
react: 'experimental', | ||
'react-dom': 'experimental', | ||
}, | ||
packageJson: { | ||
scripts: { | ||
setup: `cp -r ./node_modules_bak/* ./node_modules`, | ||
build: 'yarn setup && next build', | ||
dev: 'yarn setup && next dev', | ||
start: 'next start', | ||
}, | ||
}, | ||
installCommand: 'yarn', | ||
startCommand: (global as any).isNextDev ? 'yarn dev' : 'yarn start', | ||
buildCommand: 'yarn build', | ||
}) | ||
}) | ||
afterAll(() => next.destroy()) | ||
|
||
const { isNextDeploy } = global as any | ||
const isReact17 = process.env.NEXT_TEST_REACT_VERSION === '^17' | ||
if (isNextDeploy || isReact17) { | ||
it('should skip tests for next-deploy and react 17', () => {}) | ||
return | ||
} | ||
|
||
it('should be able to opt-out 3rd party packages being bundled in server components', async () => { | ||
await fetchViaHTTP(next.url, '/react-server/optout').then( | ||
async (response) => { | ||
const result = await resolveStreamResponse(response) | ||
expect(result).toContain('Server: index.default') | ||
expect(result).toContain('Server subpath: subpath.default') | ||
expect(result).toContain('Client: index.default') | ||
expect(result).toContain('Client subpath: subpath.default') | ||
} | ||
) | ||
}) | ||
|
||
it('should handle external async module libraries correctly', async () => { | ||
const clientHtml = await renderViaHTTP(next.url, '/external-imports/client') | ||
const serverHtml = await renderViaHTTP(next.url, '/external-imports/server') | ||
const sharedHtml = await renderViaHTTP(next.url, '/shared-esm-dep') | ||
|
||
expect(clientHtml).toContain('module type:esm-export') | ||
expect(clientHtml).toContain('export named:named') | ||
expect(clientHtml).toContain('export value:123') | ||
expect(clientHtml).toContain('export array:4,5,6') | ||
expect(clientHtml).toContain('export object:{x:1}') | ||
|
||
// support esm module imports on server side, and indirect imports from shared components | ||
expect(serverHtml).toContain('random-module-instance') | ||
expect(sharedHtml).toContain( | ||
'node_modules instance from client module random-module-instance' | ||
) | ||
}) | ||
|
||
it('should resolve the subset react in server components based on the react-server condition', async () => { | ||
await fetchViaHTTP(next.url, '/react-server').then(async (response) => { | ||
const result = await resolveStreamResponse(response) | ||
expect(result).toContain('Server: <!-- -->subset') | ||
expect(result).toContain('Client: <!-- -->full') | ||
}) | ||
}) | ||
|
||
it('should resolve 3rd party package exports based on the react-server condition', async () => { | ||
await fetchViaHTTP(next.url, '/react-server/3rd-party-package').then( | ||
async (response) => { | ||
const result = await resolveStreamResponse(response) | ||
|
||
// Package should be resolved based on the react-server condition, | ||
// as well as package's internal & external dependencies. | ||
expect(result).toContain( | ||
'Server: index.react-server:react.subset:dep.server' | ||
) | ||
expect(result).toContain('Client: index.default:react.full:dep.default') | ||
|
||
// Subpath exports should be resolved based on the condition too. | ||
expect(result).toContain('Server subpath: subpath.react-server') | ||
expect(result).toContain('Client subpath: subpath.default') | ||
} | ||
) | ||
}) | ||
}) |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export default function AppLayout({ children }) { | ||
return ( | ||
<html> | ||
<head></head> | ||
<body>{children}</body> | ||
</html> | ||
) | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import Random from '../../components/random-module-instance' | ||
|
||
export default function Page() { | ||
return <Random /> | ||
} |
7 changes: 7 additions & 0 deletions
7
test/e2e/app-dir/rsc-external/components/random-module-instance.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'client' | ||
|
||
import { name } from 'random-module-instance' | ||
|
||
export default function () { | ||
return `node_modules instance from client module ${name}` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module.exports = { | ||
reactStrictMode: true, | ||
experimental: { | ||
appDir: true, | ||
serverComponentsExternalPackages: ['conditional-exports-optout'], | ||
}, | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.