Apply react-server condition for pages api (#57459)
Apply react-server condition and related API checks for pages API. if you're doing react SSR with renderToString in middleware it should be disallowed. Imaging it could send the rendered html code to client and you display it in browser. But it might require hydration so it can be broken. Follow up for #57448 , same reason explained in #57448 Closes NEXT-1653
This commit is contained in:
parent
b27aa57908
commit
6b18f397cb
4 changed files with 45 additions and 59 deletions
|
@ -454,13 +454,12 @@ export default async function getBaseWebpackConfig(
|
|||
].filter(Boolean)
|
||||
: []
|
||||
|
||||
const swcLoaderForMiddlewareLayer = useSWCLoader
|
||||
? swcServerLayerLoader
|
||||
: // When using Babel, we will have to use SWC to do the optimization
|
||||
// for middleware to tree shake the unused default optimized imports like "next/server".
|
||||
// This will cause some performance overhead but
|
||||
// acceptable as Babel will not be recommended.
|
||||
[swcServerLayerLoader, babelLoader]
|
||||
const swcLoaderForMiddlewareLayer =
|
||||
// When using Babel, we will have to use SWC to do the optimization
|
||||
// for middleware to tree shake the unused default optimized imports like "next/server".
|
||||
// This will cause some performance overhead but
|
||||
// acceptable as Babel will not be recommended.
|
||||
[swcServerLayerLoader, babelLoader].filter(Boolean)
|
||||
|
||||
// client components layers: SSR + browser
|
||||
const swcLoaderForClientLayer = [
|
||||
|
@ -488,16 +487,9 @@ export default async function getBaseWebpackConfig(
|
|||
: []),
|
||||
]
|
||||
|
||||
// Loader for API routes needs to be differently configured as it shouldn't
|
||||
// have RSC transpiler enabled, so syntax checks such as invalid imports won't
|
||||
// be performed.
|
||||
const loaderForAPIRoutes =
|
||||
hasAppDir && useSWCLoader
|
||||
? getSwcLoader({
|
||||
serverComponents: false,
|
||||
isReactServerLayer: false,
|
||||
})
|
||||
: defaultLoaders.babel
|
||||
// Loader for API routes will also apply react-server export condition for bundling,
|
||||
// and the API checks for server side only APIs.
|
||||
const loaderForAPIRoutes = [swcServerLayerLoader, babelLoader].filter(Boolean)
|
||||
|
||||
const pageExtensions = config.pageExtensions
|
||||
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
// You can still import React and Next's client component APIs from the server
|
||||
// they won't be poisoned by the environment.
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { useState } from 'react'
|
||||
import 'next/headers'
|
||||
|
||||
export default function (_, res) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createNextDescribe } from 'e2e-utils'
|
||||
import { getRedboxSource, hasRedbox } from 'next-test-utils'
|
||||
import { check, getRedboxSource, hasRedbox } from 'next-test-utils'
|
||||
|
||||
createNextDescribe(
|
||||
'module layer',
|
||||
|
@ -68,51 +68,49 @@ createNextDescribe(
|
|||
// Should error for using mixed (with client-only) in server targets
|
||||
if (isNextDev) {
|
||||
describe('no server-only in server targets', () => {
|
||||
const middlewareFile = 'middleware.js'
|
||||
// const pagesApiFile = 'pages/api/hello.js'
|
||||
let middlewareContent = ''
|
||||
// let pagesApiContent = ''
|
||||
|
||||
beforeAll(async () => {
|
||||
await next.stop()
|
||||
|
||||
middlewareContent = await next.readFile(middlewareFile)
|
||||
// pagesApiContent = await next.readFile(pagesApiFile)
|
||||
|
||||
it('should error when import client-only in middleware', async () => {
|
||||
const middlewareFile = 'middleware.js'
|
||||
const middlewareContent = await next.readFile(middlewareFile)
|
||||
await next.patchFile(
|
||||
middlewareFile,
|
||||
middlewareContent
|
||||
// .replace("import 'server-only'", "// import 'server-only'")
|
||||
.replace(
|
||||
"// import './lib/mixed-lib'",
|
||||
"import './lib/mixed-lib'"
|
||||
)
|
||||
middlewareContent.replace(
|
||||
"// import './lib/mixed-lib'",
|
||||
"import './lib/mixed-lib'"
|
||||
)
|
||||
)
|
||||
|
||||
// await next.patchFile(
|
||||
// pagesApiFile,
|
||||
// pagesApiContent
|
||||
// .replace("import 'server-only'", "// import 'server-only'")
|
||||
// .replace(
|
||||
// "// import '../../lib/mixed-lib'",
|
||||
// "import '../../lib/mixed-lib'"
|
||||
// )
|
||||
// )
|
||||
|
||||
await next.start()
|
||||
})
|
||||
afterAll(async () => {
|
||||
await next.patchFile(middlewareFile, middlewareContent)
|
||||
// await next.patchFile(pagesApiFile, pagesApiContent)
|
||||
})
|
||||
|
||||
it('should error when import client-only in middleware', async () => {
|
||||
const browser = await next.browser('/')
|
||||
|
||||
expect(await hasRedbox(browser, true)).toBe(true)
|
||||
expect(await getRedboxSource(browser)).toContain(
|
||||
`You're importing a component that imports client-only. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.`
|
||||
)
|
||||
|
||||
await next.patchFile(middlewareFile, middlewareContent)
|
||||
})
|
||||
|
||||
it('should error when import client-only in pages/api', async () => {
|
||||
const pagesApiFile = 'pages/api/mixed.js'
|
||||
const pagesApiContent = await next.readFile(pagesApiFile)
|
||||
await next.patchFile(
|
||||
pagesApiFile,
|
||||
pagesApiContent.replace(
|
||||
"// import 'client-only'",
|
||||
"import 'client-only'"
|
||||
)
|
||||
)
|
||||
|
||||
const existingCliOutputLength = next.cliOutput.length
|
||||
await check(async () => {
|
||||
await next.fetch('/api/mixed')
|
||||
const newCliOutput = next.cliOutput.slice(existingCliOutputLength)
|
||||
expect(newCliOutput).toContain('./pages/api/mixed.js')
|
||||
expect(newCliOutput).toContain(
|
||||
`You're importing a component that imports client-only. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.`
|
||||
)
|
||||
return 'success'
|
||||
}, 'success')
|
||||
|
||||
await next.patchFile(pagesApiFile, pagesApiContent)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import '../../lib/mixed-lib'
|
||||
// import 'client-only'
|
||||
|
||||
export default function handler(req, res) {
|
||||
return res.send('pages/api/mixed.js:')
|
||||
|
|
Loading…
Reference in a new issue