Skip to content

Commit 5f47a20

Browse files
committed
Add back in the module loading indirection to make it work across bundles (runtime + user bundle) on the server
1 parent e92e687 commit 5f47a20

File tree

17 files changed

+69
-36
lines changed

17 files changed

+69
-36
lines changed

packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { PassThrough } from 'node:stream'
1818
import entry from 'APP_ENTRY'
1919
import BOOTSTRAP from 'APP_BOOTSTRAP'
2020
import { createServerResponse } from '../internal/http'
21-
import { createManifests } from './app/manifest'
21+
import { createManifests, installRequireAndChunkLoad } from './app/manifest'
2222
import { join } from 'node:path'
2323
import { nodeFs } from 'next/dist/server/lib/node-fs-methods'
2424
import { IncrementalCache } from 'next/dist/server/lib/incremental-cache'
@@ -27,6 +27,8 @@ const {
2727
renderToHTMLOrFlight,
2828
} = require('next/dist/compiled/next-server/app-page.runtime.dev')
2929

30+
installRequireAndChunkLoad()
31+
3032
const MIME_TEXT_HTML_UTF8 = 'text/html; charset=utf-8'
3133

3234
startOperationStreamHandler(async (renderData: RenderData, respond) => {
@@ -90,6 +92,10 @@ async function runOperation(renderData: RenderData) {
9092
},
9193
ComponentMod: {
9294
...entry,
95+
__next_app__: {
96+
require: __next_require__,
97+
loadChunk: __next_chunk_load__,
98+
},
9399
pages: ['page.js'],
94100
},
95101
incrementalCache: new IncrementalCache({

packages/next-swc/crates/next-core/js/src/entry/app/edge-page-bootstrap.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import { renderToHTMLOrFlight } from 'next/dist/server/app-render/app-render'
55
;('TURBOPACK { chunking-type: isolatedParallel }')
66
import entry from 'APP_ENTRY'
77
import BOOTSTRAP from 'APP_BOOTSTRAP'
8-
import { createManifests } from './manifest'
8+
import { createManifests, installRequireAndChunkLoad } from './manifest'
99
import type { NextRequest, NextFetchEvent } from 'next/server'
1010
import type { RenderOpts } from 'next/dist/server/app-render/types'
1111
import type { ParsedUrlQuery } from 'querystring'
1212

13+
installRequireAndChunkLoad()
14+
1315
// avoid limiting stack traces to 10 lines
1416
Error.stackTraceLimit = 100
1517

@@ -41,6 +43,10 @@ async function render(request: NextRequest, event: NextFetchEvent) {
4143
},
4244
ComponentMod: {
4345
...entry,
46+
__next_app__: {
47+
require: __next_require__,
48+
loadChunk: __next_chunk_load__,
49+
},
4450
pages: ['page.js'],
4551
},
4652
clientReferenceManifest,

packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import ReactDOMClient from 'react-dom/client'
22
import React, { use } from 'react'
33
import type { ReactElement } from 'react'
44
import { version } from 'next/package.json'
5-
import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-turbopack/client'
5+
import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack/client'
66
import { callServer } from 'next/dist/client/app-call-server'
77
import { linkGc } from 'next/dist/client/app-link-gc'
88

@@ -19,6 +19,12 @@ window.next = {
1919
appDir: true,
2020
}
2121

22+
globalThis.__next_require__ = (data) => {
23+
const [client_id] = JSON.parse(data)
24+
return __turbopack_require__(client_id)
25+
}
26+
globalThis.__next_chunk_load__ = __turbopack_load__
27+
2228
const appElement = document
2329

2430
const getCacheKey = () => {

packages/next-swc/crates/next-core/js/src/entry/app/manifest.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,11 @@ export function createManifests() {
114114

115115
return { clientReferenceManifest }
116116
}
117+
118+
export function installRequireAndChunkLoad() {
119+
globalThis.__next_require__ = (data) => {
120+
const [, , ssr_id] = JSON.parse(data)
121+
return __turbopack_require__(ssr_id)
122+
}
123+
globalThis.__next_chunk_load__ = () => Promise.resolve()
124+
}

packages/next-swc/crates/next-core/js/types/globals.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ declare global {
88
var __webpack_public_path__: string | undefined
99
var __DEV_MIDDLEWARE_MATCHERS: any[]
1010

11+
var __next_require__: (id: string) => any
12+
var __next_chunk_load__: (id: string) => Promise
1113
var __next_f: (
1214
| [isBootStrap: 0]
1315
| [isNotBootstrap: 1, responsePartial: string]

packages/next/src/build/webpack-config.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,12 +1955,10 @@ export default async function getBaseWebpackConfig(
19551955
layer: WEBPACK_LAYERS.appMetadataRoute,
19561956
},
19571957
{
1958+
// Ensure that the app page module is in the client layers, this
1959+
// enables React to work correctly for RSC.
19581960
layer: WEBPACK_LAYERS.serverSideRendering,
1959-
test: [
1960-
// Ensure that the app page module is in the client layers, this
1961-
// enables React to work correctly for RSC.
1962-
/next[\\/]dist[\\/](esm[\\/])?server[\\/]future[\\/]route-modules[\\/]app-page[\\/]module/,
1963-
],
1961+
test: /next[\\/]dist[\\/](esm[\\/])?server[\\/]future[\\/]route-modules[\\/]app-page[\\/]module/,
19641962
},
19651963
{
19661964
// All app dir layers need to use this configured resolution logic

packages/next/src/client/app-next-dev.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ import { appBootstrap } from './app-bootstrap'
44

55
appBootstrap(() => {
66
require('./app-webpack')
7-
// It is import that the webpack patch above in ./app-webpack runs before any
8-
// react code is loaded. This order dependent loading will ensure that react controls
9-
// the filename resolution of flight loaded chunks and will not be intercepted
10-
// by the patch above.
117
const { hydrate } = require('./app-index')
128
hydrate()
139
})

packages/next/src/client/app-next.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@ import { appBootstrap } from './app-bootstrap'
22

33
appBootstrap(() => {
44
// Include app-router and layout-router in the main chunk
5-
require('./app-webpack')
6-
// It is import that the webpack patch above in ./app-webpack runs before any
7-
// react code is loaded. This order dependent loading will ensure that react controls
8-
// the filename resolution of flight loaded chunks and will not be intercepted
9-
// by the patch above.
105
require('next/dist/client/components/app-router')
116
require('next/dist/client/components/layout-router')
7+
require('./app-webpack')
128
const { hydrate } = require('./app-index')
139
hydrate()
1410
})
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @ts-expect-error
2+
process.env.__NEXT_NEW_LINK_BEHAVIOR = true
3+
4+
export {}

packages/next/src/server/app-render/action-handler.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,15 +360,13 @@ export async function handleAction({
360360
}
361361
}
362362
} else {
363-
// Use react-server-dom-webpack/server.node for decodeReplyFromBusboy and react-server-dom-webpack/server.edge
364-
// for decodeAction and decodeReply. We could actually use just server.node for all the action handling because
365-
// the but these packages don't actually have any direct platform primitives so either works in this context
363+
// Use react-server-dom-webpack/server.node which supports streaming
366364
const {
365+
decodeReply,
367366
decodeReplyFromBusboy,
368367
decodeAction,
369-
decodeReply,
370368
decodeFormState,
371-
} = ComponentMod
369+
} = require(`./react-server.node`)
372370

373371
if (isMultipartAction) {
374372
if (isFetchAction) {

packages/next/src/server/app-render/create-server-components-renderer.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ export function createServerComponentRenderer<Props>(
1313
ComponentToRender: (props: Props) => any,
1414
ComponentMod: {
1515
renderToReadableStream: any
16-
createFromReadableStream: any
16+
__next_app__?: {
17+
require: any
18+
loadChunk: any
19+
}
1720
},
1821
{
1922
transformStream,

packages/next/src/server/app-render/entry-base.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ const {
66
// eslint-disable-next-line import/no-extraneous-dependencies
77
} = require('react-server-dom-webpack/server.edge')
88

9-
let decodeReplyFromBusboy
10-
if (process.env.NEXT_RUNTIME !== 'edge') {
11-
decodeReplyFromBusboy =
12-
// eslint-disable-next-line import/no-extraneous-dependencies
13-
require('react-server-dom-webpack/server.node').decodeReplyFromBusboy
14-
}
15-
169
import AppRouter from '../../client/components/app-router'
1710
import LayoutRouter from '../../client/components/layout-router'
1811
import RenderFromTemplateContext from '../../client/components/render-from-template-context'
@@ -47,7 +40,6 @@ export {
4740
decodeReply,
4841
decodeAction,
4942
decodeFormState,
50-
decodeReplyFromBusboy,
5143
preloadStyle,
5244
preloadFont,
5345
preconnect,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// This file should be opted into the react-server layer
2+
3+
export {
4+
decodeReply,
5+
decodeReplyFromBusboy,
6+
decodeAction,
7+
decodeFormState,
8+
// eslint-disable-next-line import/no-extraneous-dependencies
9+
} from 'react-server-dom-webpack/server.node'

packages/next/src/server/app-render/use-flight-response.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,16 @@ export function useFlightResponse(
2626
return flightResponseRef.current
2727
}
2828
// react-server-dom-webpack/client.edge must not be hoisted for require cache clearing to work correctly
29-
const {
30-
createFromReadableStream,
31-
} = require(`react-server-dom-webpack/client.edge`)
29+
let createFromReadableStream
30+
if (process.env.TURBOPACK) {
31+
createFromReadableStream =
32+
// eslint-disable-next-line import/no-extraneous-dependencies
33+
require('react-server-dom-turbopack/client.edge').createFromReadableStream
34+
} else {
35+
createFromReadableStream =
36+
// eslint-disable-next-line import/no-extraneous-dependencies
37+
require('react-server-dom-webpack/client.edge').createFromReadableStream
38+
}
3239

3340
const [renderStream, forwardStream] = req.tee()
3441
const res = createFromReadableStream(renderStream, {

packages/next/webpack.config.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ module.exports = ({ dev, turbo, bundleType, experimental }) => {
193193
},
194194
module: {
195195
rules: [
196+
{
197+
include: /[\\/]react-server.node/,
198+
layer: 'react-server',
199+
},
196200
{
197201
include: /vendored[\\/]rsc[\\/]entrypoints/,
198202
resolve: {

test/e2e/app-dir/chunk-loading/app/account/ClientShared.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { SuperShared } from '../../components/SuperShared'
44
import { LazyShared } from '../../components/LazyShared'
5-
import 'client-only'
65

76
export function ClientShared() {
87
return <SuperShared from="fizz" />

test/e2e/app-dir/chunk-loading/app/account/page.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ClientShared, ClientDynamicShared } from './ClientShared'
2-
import 'server-only'
32

43
import styles from './styles.module.css'
54

0 commit comments

Comments
 (0)