Skip to content

Commit

Permalink
Add back in the module loading indirection to make it work across bun…
Browse files Browse the repository at this point in the history
…dles (runtime + user bundle) on the server
  • Loading branch information
gnoff committed Sep 26, 2023
1 parent e92e687 commit 5f47a20
Show file tree
Hide file tree
Showing 17 changed files with 69 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { PassThrough } from 'node:stream'
import entry from 'APP_ENTRY'
import BOOTSTRAP from 'APP_BOOTSTRAP'
import { createServerResponse } from '../internal/http'
import { createManifests } from './app/manifest'
import { createManifests, installRequireAndChunkLoad } from './app/manifest'
import { join } from 'node:path'
import { nodeFs } from 'next/dist/server/lib/node-fs-methods'
import { IncrementalCache } from 'next/dist/server/lib/incremental-cache'
Expand All @@ -27,6 +27,8 @@ const {
renderToHTMLOrFlight,
} = require('next/dist/compiled/next-server/app-page.runtime.dev')

installRequireAndChunkLoad()

const MIME_TEXT_HTML_UTF8 = 'text/html; charset=utf-8'

startOperationStreamHandler(async (renderData: RenderData, respond) => {
Expand Down Expand Up @@ -90,6 +92,10 @@ async function runOperation(renderData: RenderData) {
},
ComponentMod: {
...entry,
__next_app__: {
require: __next_require__,
loadChunk: __next_chunk_load__,
},
pages: ['page.js'],
},
incrementalCache: new IncrementalCache({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { renderToHTMLOrFlight } from 'next/dist/server/app-render/app-render'
;('TURBOPACK { chunking-type: isolatedParallel }')
import entry from 'APP_ENTRY'
import BOOTSTRAP from 'APP_BOOTSTRAP'
import { createManifests } from './manifest'
import { createManifests, installRequireAndChunkLoad } from './manifest'
import type { NextRequest, NextFetchEvent } from 'next/server'
import type { RenderOpts } from 'next/dist/server/app-render/types'
import type { ParsedUrlQuery } from 'querystring'

installRequireAndChunkLoad()

// avoid limiting stack traces to 10 lines
Error.stackTraceLimit = 100

Expand Down Expand Up @@ -41,6 +43,10 @@ async function render(request: NextRequest, event: NextFetchEvent) {
},
ComponentMod: {
...entry,
__next_app__: {
require: __next_require__,
loadChunk: __next_chunk_load__,
},
pages: ['page.js'],
},
clientReferenceManifest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import ReactDOMClient from 'react-dom/client'
import React, { use } from 'react'
import type { ReactElement } from 'react'
import { version } from 'next/package.json'
import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-turbopack/client'
import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack/client'
import { callServer } from 'next/dist/client/app-call-server'
import { linkGc } from 'next/dist/client/app-link-gc'

Expand All @@ -19,6 +19,12 @@ window.next = {
appDir: true,
}

globalThis.__next_require__ = (data) => {
const [client_id] = JSON.parse(data)
return __turbopack_require__(client_id)
}
globalThis.__next_chunk_load__ = __turbopack_load__

const appElement = document

const getCacheKey = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,11 @@ export function createManifests() {

return { clientReferenceManifest }
}

export function installRequireAndChunkLoad() {
globalThis.__next_require__ = (data) => {
const [, , ssr_id] = JSON.parse(data)
return __turbopack_require__(ssr_id)
}
globalThis.__next_chunk_load__ = () => Promise.resolve()
}
2 changes: 2 additions & 0 deletions packages/next-swc/crates/next-core/js/types/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ declare global {
var __webpack_public_path__: string | undefined
var __DEV_MIDDLEWARE_MATCHERS: any[]

var __next_require__: (id: string) => any
var __next_chunk_load__: (id: string) => Promise
var __next_f: (
| [isBootStrap: 0]
| [isNotBootstrap: 1, responsePartial: string]
Expand Down
8 changes: 3 additions & 5 deletions packages/next/src/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1955,12 +1955,10 @@ export default async function getBaseWebpackConfig(
layer: WEBPACK_LAYERS.appMetadataRoute,
},
{
// Ensure that the app page module is in the client layers, this
// enables React to work correctly for RSC.
layer: WEBPACK_LAYERS.serverSideRendering,
test: [
// Ensure that the app page module is in the client layers, this
// enables React to work correctly for RSC.
/next[\\/]dist[\\/](esm[\\/])?server[\\/]future[\\/]route-modules[\\/]app-page[\\/]module/,
],
test: /next[\\/]dist[\\/](esm[\\/])?server[\\/]future[\\/]route-modules[\\/]app-page[\\/]module/,
},
{
// All app dir layers need to use this configured resolution logic
Expand Down
4 changes: 0 additions & 4 deletions packages/next/src/client/app-next-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ import { appBootstrap } from './app-bootstrap'

appBootstrap(() => {
require('./app-webpack')
// It is import that the webpack patch above in ./app-webpack runs before any
// react code is loaded. This order dependent loading will ensure that react controls
// the filename resolution of flight loaded chunks and will not be intercepted
// by the patch above.
const { hydrate } = require('./app-index')
hydrate()
})
Expand Down
6 changes: 1 addition & 5 deletions packages/next/src/client/app-next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,9 @@ import { appBootstrap } from './app-bootstrap'

appBootstrap(() => {
// Include app-router and layout-router in the main chunk
require('./app-webpack')
// It is import that the webpack patch above in ./app-webpack runs before any
// react code is loaded. This order dependent loading will ensure that react controls
// the filename resolution of flight loaded chunks and will not be intercepted
// by the patch above.
require('next/dist/client/components/app-router')
require('next/dist/client/components/layout-router')
require('./app-webpack')
const { hydrate } = require('./app-index')
hydrate()
})
4 changes: 4 additions & 0 deletions packages/next/src/client/app-turbopack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @ts-expect-error
process.env.__NEXT_NEW_LINK_BEHAVIOR = true

export {}
8 changes: 3 additions & 5 deletions packages/next/src/server/app-render/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,15 +360,13 @@ export async function handleAction({
}
}
} else {
// Use react-server-dom-webpack/server.node for decodeReplyFromBusboy and react-server-dom-webpack/server.edge
// for decodeAction and decodeReply. We could actually use just server.node for all the action handling because
// the but these packages don't actually have any direct platform primitives so either works in this context
// Use react-server-dom-webpack/server.node which supports streaming
const {
decodeReply,
decodeReplyFromBusboy,
decodeAction,
decodeReply,
decodeFormState,
} = ComponentMod
} = require(`./react-server.node`)

if (isMultipartAction) {
if (isFetchAction) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export function createServerComponentRenderer<Props>(
ComponentToRender: (props: Props) => any,
ComponentMod: {
renderToReadableStream: any
createFromReadableStream: any
__next_app__?: {
require: any
loadChunk: any
}
},
{
transformStream,
Expand Down
8 changes: 0 additions & 8 deletions packages/next/src/server/app-render/entry-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@ const {
// eslint-disable-next-line import/no-extraneous-dependencies
} = require('react-server-dom-webpack/server.edge')

let decodeReplyFromBusboy
if (process.env.NEXT_RUNTIME !== 'edge') {
decodeReplyFromBusboy =
// eslint-disable-next-line import/no-extraneous-dependencies
require('react-server-dom-webpack/server.node').decodeReplyFromBusboy
}

import AppRouter from '../../client/components/app-router'
import LayoutRouter from '../../client/components/layout-router'
import RenderFromTemplateContext from '../../client/components/render-from-template-context'
Expand Down Expand Up @@ -47,7 +40,6 @@ export {
decodeReply,
decodeAction,
decodeFormState,
decodeReplyFromBusboy,
preloadStyle,
preloadFont,
preconnect,
Expand Down
9 changes: 9 additions & 0 deletions packages/next/src/server/app-render/react-server.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This file should be opted into the react-server layer

export {
decodeReply,
decodeReplyFromBusboy,
decodeAction,
decodeFormState,
// eslint-disable-next-line import/no-extraneous-dependencies
} from 'react-server-dom-webpack/server.node'
13 changes: 10 additions & 3 deletions packages/next/src/server/app-render/use-flight-response.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,16 @@ export function useFlightResponse(
return flightResponseRef.current
}
// react-server-dom-webpack/client.edge must not be hoisted for require cache clearing to work correctly
const {
createFromReadableStream,
} = require(`react-server-dom-webpack/client.edge`)
let createFromReadableStream
if (process.env.TURBOPACK) {
createFromReadableStream =
// eslint-disable-next-line import/no-extraneous-dependencies
require('react-server-dom-turbopack/client.edge').createFromReadableStream
} else {
createFromReadableStream =
// eslint-disable-next-line import/no-extraneous-dependencies
require('react-server-dom-webpack/client.edge').createFromReadableStream
}

const [renderStream, forwardStream] = req.tee()
const res = createFromReadableStream(renderStream, {
Expand Down
4 changes: 4 additions & 0 deletions packages/next/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ module.exports = ({ dev, turbo, bundleType, experimental }) => {
},
module: {
rules: [
{
include: /[\\/]react-server.node/,
layer: 'react-server',
},
{
include: /vendored[\\/]rsc[\\/]entrypoints/,
resolve: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { SuperShared } from '../../components/SuperShared'
import { LazyShared } from '../../components/LazyShared'
import 'client-only'

export function ClientShared() {
return <SuperShared from="fizz" />
Expand Down
1 change: 0 additions & 1 deletion test/e2e/app-dir/chunk-loading/app/account/page.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ClientShared, ClientDynamicShared } from './ClientShared'
import 'server-only'

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

Expand Down

0 comments on commit 5f47a20

Please sign in to comment.