Skip to content

Commit

Permalink
Merge branch 'canary' into revert-48688-revert-48685-revert-48678-rev…
Browse files Browse the repository at this point in the history
…ert-48383-feedthejim/next-1011-implement-new-caching-heuristics
  • Loading branch information
huozhi committed Apr 22, 2023
2 parents afc1b39 + 485955b commit 174ede6
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function formatRSCErrorMessage(
formattedVerboseMessage =
'\n\nMaybe one of these should be marked as a client entry with "use client":\n'
} else if (NEXT_RSC_ERR_SERVER_IMPORT.test(message)) {
let shouldAddUseClient = true
const matches = message.match(NEXT_RSC_ERR_SERVER_IMPORT)
switch (matches && matches[1]) {
case 'react-dom/server':
Expand All @@ -49,15 +50,17 @@ function formatRSCErrorMessage(
case 'next/router':
// If importing "next/router", we should tell them to use "next/navigation".
formattedMessage = `\n\nYou have a Server Component that imports next/router. Use next/navigation instead.`
shouldAddUseClient = false
break
default:
formattedMessage = message.replace(
NEXT_RSC_ERR_SERVER_IMPORT,
`\n\nYou're importing a component that imports $1. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.\n\n`
)
}
formattedVerboseMessage =
'\n\nMaybe one of these should be marked as a client entry "use client":\n'
formattedVerboseMessage = shouldAddUseClient
? '\n\nMaybe one of these should be marked as a client entry "use client":\n'
: '\n\nImport trace:\n'
} else if (NEXT_RSC_ERR_CLIENT_IMPORT.test(message)) {
if (isPagesDir) {
formattedMessage = message.replace(
Expand Down
58 changes: 25 additions & 33 deletions packages/next/src/server/app-render/action-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,24 @@ export async function handleAction({
let bound = []

const workerName = 'app' + pathname
const { decodeReply } = ComponentMod
const serverModuleMap = new Proxy(
{},
{
get: (_, id: string) => {
return {
id: serverActionsManifest.node[id].workers[workerName],
name: id,
chunks: [],
}
},
}
)

try {
if (process.env.NEXT_RUNTIME === 'edge') {
// Use react-server-dom-webpack/server.edge
const { decodeReply } = ComponentMod

const webRequest = req as unknown as Request
if (!webRequest.body) {
throw new Error('invariant: Missing request body.')
Expand Down Expand Up @@ -72,44 +86,22 @@ export async function handleAction({
formData.delete('$$id')
bound = [formData]
} else {
bound = await decodeReply(actionData)
bound = await decodeReply(actionData, serverModuleMap)
}
}
} else {
if (isMultipartAction) {
const formFields = new FormData()
// Use react-server-dom-webpack/server.node which supports streaming
const {
decodeReply,
decodeReplyFromBusboy,
} = require('next/dist/compiled/react-server-dom-webpack/server.node')

if (isMultipartAction) {
const busboy = require('busboy')
const bb = busboy({ headers: req.headers })
let innerResolvor: () => void, innerRejector: (e: any) => void
const promise = new Promise<void>((resolve, reject) => {
innerResolvor = resolve
innerRejector = reject
})
bb.on('file', () =>
innerRejector(new Error('File upload is not supported.'))
)
bb.on('error', (err: any) => innerRejector(err))
bb.on('field', (id: any, val: any) => formFields.append(id, val))
bb.on('finish', () => innerResolvor())
req.pipe(bb)
await promise

bound = await decodeReply(
formFields,
new Proxy(
{},
{
get: (_, id: string) => {
return {
id: serverActionsManifest.node[id].workers[workerName],
name: id,
chunks: [],
}
},
}
)
)

bound = await decodeReplyFromBusboy(bb, serverModuleMap)
} else {
const { parseBody } =
require('../api-utils/node') as typeof import('../api-utils/node')
Expand All @@ -124,7 +116,7 @@ export async function handleAction({
formData.delete('$$id')
bound = [formData]
} else {
bound = await decodeReply(actionData)
bound = await decodeReply(actionData, serverModuleMap)
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions test/e2e/app-dir/rsc-basic/app/app-react/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react'

export default function Page() {
return <div>{'version=' + React.version}</div>
}
5 changes: 5 additions & 0 deletions test/e2e/app-dir/rsc-basic/pages/pages-react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react'

export default function Page() {
return <div>{'version=' + React.version}</div>
}
15 changes: 15 additions & 0 deletions test/e2e/app-dir/rsc-basic/rsc-basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,21 @@ describe('app dir - rsc basics', () => {
expect(await res.text()).toBe('Hello from import-test.js')
})

it('should use stable react for pages', async () => {
const resPages = await next.fetch('/pages-react')
const versionPages = (await resPages.text()).match(
/<div>version=([^<]+)<\/div>/
)?.[1]

const resApp = await next.fetch('/app-react')
const versionApp = (await resApp.text()).match(
/<div>version=([^<]+)<\/div>/
)?.[1]

expect(versionPages).not.toInclude('-next-')
expect(versionApp).toInclude('-next-')
})

// disable this flaky test
it.skip('should support partial hydration with inlined server data in browser', async () => {
// Should end up with "next_streaming_data".
Expand Down

0 comments on commit 174ede6

Please sign in to comment.