Skip to content

Commit d25e246

Browse files
authored
Keep custom app as non server component (#37044)
We added custom _app as server component support in #33149, but we found it's pretty confusing on usage like support it both server component pages and regular pages at the same time for having similar layout purpose. When using the _app.server and _app at the same time, applying them into proper places become more confusing. In that case, we decide to make _app.js can't be a server component, and you can still keep all the existing thing there. And also you don't need to think of the corresponding APIs of custom _app in RSC - [ ] Related issues linked using `fixes #number` - [x] Integration tests added - [x] Docs updated
1 parent 5af2fbb commit d25e246

File tree

19 files changed

+36
-200
lines changed

19 files changed

+36
-200
lines changed

docs/advanced-features/react-18/server-components.md

+1-9
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,7 @@ export default function Document() {
9494

9595
### `next/app`
9696

97-
If you're using `_app.js`, the usage is the same as [Custom App](/docs/advanced-features/custom-app).
98-
If you're using `_app.server.js` as a server component, see the example below where it only receives the `children` prop as React elements. You can wrap any other client or server components around `children` to customize the layout of your app.
99-
100-
```js
101-
// pages/_app.server.js
102-
export default function App({ children }) {
103-
return children
104-
}
105-
```
97+
The usage of `_app.js` is the same as [Custom App](/docs/advanced-features/custom-app). Using custom app as server component such as `_app.server.js` is not recommended, to keep align with non server components apps for client specific things like global CSS imports.
10698

10799
### Routing
108100

packages/next/build/entries.ts

+3-13
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,20 @@ import {
2828
import { __ApiPreviewProps } from '../server/api-utils'
2929
import { isTargetLikeServerless } from '../server/utils'
3030
import { warn } from './output/log'
31+
import { isServerComponentPage } from './utils'
3132
import { getPageStaticInfo } from './analysis/get-page-static-info'
32-
import { isServerComponentPage, withoutRSCExtensions } from './utils'
3333
import { normalizePathSep } from '../shared/lib/page-path/normalize-path-sep'
3434
import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path'
3535
import { serverComponentRegex } from './webpack/loaders/utils'
3636

3737
type ObjectValue<T> = T extends { [key: string]: infer V } ? V : never
3838

3939
/**
40-
* For a given page path removes the provided extensions. `/_app.server` is a
41-
* special case because it is the only page where we want to preserve the RSC
42-
* server extension.
40+
* For a given page path removes the provided extensions.
4341
*/
4442
export function getPageFromPath(pagePath: string, pageExtensions: string[]) {
45-
const extensions = pagePath.includes('/_app.server.')
46-
? withoutRSCExtensions(pageExtensions)
47-
: pageExtensions
48-
4943
let page = normalizePathSep(
50-
pagePath.replace(new RegExp(`\\.+(${extensions.join('|')})$`), '')
44+
pagePath.replace(new RegExp(`\\.+(${pageExtensions.join('|')})$`), '')
5145
)
5246

5347
page = page.replace(/\/index$/, '')
@@ -118,7 +112,6 @@ export function createPagesMapping({
118112

119113
if (isDev) {
120114
delete pages['/_app']
121-
delete pages['/_app.server']
122115
delete pages['/_error']
123116
delete pages['/_document']
124117
}
@@ -132,7 +125,6 @@ export function createPagesMapping({
132125
'/_app': `${root}/_app`,
133126
'/_error': `${root}/_error`,
134127
'/_document': `${root}/_document`,
135-
...(hasServerComponents ? { '/_app.server': `${root}/_app.server` } : {}),
136128
...pages,
137129
}
138130
}
@@ -175,7 +167,6 @@ export function getEdgeServerEntry(opts: {
175167
const loaderParams: MiddlewareSSRLoaderQuery = {
176168
absolute500Path: opts.pages['/500'] || '',
177169
absoluteAppPath: opts.pages['/_app'],
178-
absoluteAppServerPath: opts.pages['/_app.server'],
179170
absoluteDocumentPath: opts.pages['/_document'],
180171
absoluteErrorPath: opts.pages['/_error'],
181172
absolutePagePath: opts.absolutePagePath,
@@ -219,7 +210,6 @@ export function getServerlessEntry(opts: {
219210
const loaderParams: ServerlessLoaderQuery = {
220211
absolute404Path: opts.pages['/404'] || '',
221212
absoluteAppPath: opts.pages['/_app'],
222-
absoluteAppServerPath: opts.pages['/_app.server'],
223213
absoluteDocumentPath: opts.pages['/_document'],
224214
absoluteErrorPath: opts.pages['/_error'],
225215
absolutePagePath: opts.absolutePagePath,

packages/next/build/utils.ts

+1-8
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,6 @@ export async function printTreeView(
141141
]
142142

143143
const hasCustomApp = await findPageFile(pagesDir, '/_app', pageExtensions)
144-
const hasCustomAppServer = await findPageFile(
145-
pagesDir,
146-
'/_app.server',
147-
pageExtensions
148-
)
149-
150144
pageInfos.set('/404', {
151145
...(pageInfos.get('/404') || pageInfos.get('/_error')),
152146
static: useStatic404,
@@ -172,8 +166,7 @@ export async function printTreeView(
172166
!(
173167
e === '/_document' ||
174168
e === '/_error' ||
175-
(!hasCustomApp && e === '/_app') ||
176-
(!hasCustomAppServer && e === '/_app.server')
169+
(!hasCustomApp && e === '/_app')
177170
)
178171
)
179172
.sort((a, b) => a.localeCompare(b))

packages/next/build/webpack-config.ts

+1-8
Original file line numberDiff line numberDiff line change
@@ -606,19 +606,12 @@ export default async function getBaseWebpackConfig(
606606

607607
if (dev) {
608608
customAppAliases[`${PAGES_DIR_ALIAS}/_app`] = [
609-
...rawPageExtensions.reduce((prev, ext) => {
609+
...config.pageExtensions.reduce((prev, ext) => {
610610
prev.push(path.join(pagesDir, `_app.${ext}`))
611611
return prev
612612
}, [] as string[]),
613613
'next/dist/pages/_app.js',
614614
]
615-
customAppAliases[`${PAGES_DIR_ALIAS}/_app.server`] = [
616-
...rawPageExtensions.reduce((prev, ext) => {
617-
prev.push(path.join(pagesDir, `_app.server.${ext}`))
618-
return prev
619-
}, [] as string[]),
620-
'next/dist/pages/_app.server.js',
621-
]
622615
customAppAliases[`${PAGES_DIR_ALIAS}/_error`] = [
623616
...config.pageExtensions.reduce((prev, ext) => {
624617
prev.push(path.join(pagesDir, `_error.${ext}`))

packages/next/build/webpack/loaders/next-middleware-ssr-loader/index.ts

-10
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { stringifyRequest } from '../../stringify-request'
44
export type MiddlewareSSRLoaderQuery = {
55
absolute500Path: string
66
absoluteAppPath: string
7-
absoluteAppServerPath: string
87
absoluteDocumentPath: string
98
absoluteErrorPath: string
109
absolutePagePath: string
@@ -22,7 +21,6 @@ export default async function middlewareSSRLoader(this: any) {
2221
buildId,
2322
absolutePagePath,
2423
absoluteAppPath,
25-
absoluteAppServerPath,
2624
absoluteDocumentPath,
2725
absolute500Path,
2826
absoluteErrorPath,
@@ -42,10 +40,6 @@ export default async function middlewareSSRLoader(this: any) {
4240

4341
const stringifiedPagePath = stringifyRequest(this, absolutePagePath)
4442
const stringifiedAppPath = stringifyRequest(this, absoluteAppPath)
45-
const stringifiedAppServerPath = absoluteAppServerPath
46-
? stringifyRequest(this, absoluteAppServerPath)
47-
: null
48-
4943
const stringifiedErrorPath = stringifyRequest(this, absoluteErrorPath)
5044
const stringifiedDocumentPath = stringifyRequest(this, absoluteDocumentPath)
5145
const stringified500Path = absolute500Path
@@ -61,9 +55,6 @@ export default async function middlewareSSRLoader(this: any) {
6155
import Document from ${stringifiedDocumentPath}
6256
6357
const appMod = require(${stringifiedAppPath})
64-
const appServerMod = ${
65-
stringifiedAppServerPath ? `require(${stringifiedAppServerPath})` : 'null'
66-
}
6758
const pageMod = require(${stringifiedPagePath})
6859
const errorMod = require(${stringifiedErrorPath})
6960
const error500Mod = ${
@@ -85,7 +76,6 @@ export default async function middlewareSSRLoader(this: any) {
8576
buildManifest,
8677
reactLoadableManifest,
8778
serverComponentManifest: ${isServerComponent} ? rscManifest : null,
88-
appServerMod,
8979
config: ${stringifiedConfig},
9080
buildId: ${JSON.stringify(buildId)},
9181
})

packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts

-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ export function getRender({
2727
serverComponentManifest,
2828
config,
2929
buildId,
30-
appServerMod,
3130
}: {
3231
dev: boolean
3332
page: string
@@ -49,8 +48,6 @@ export function getRender({
4948
reactLoadableManifest,
5049
Document,
5150
App: appMod.default as AppType,
52-
AppMod: appMod,
53-
AppServerMod: appServerMod,
5451
}
5552

5653
const server = new WebServer({

packages/next/build/webpack/loaders/next-serverless-loader/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export type ServerlessLoaderQuery = {
1818
distDir: string
1919
absolutePagePath: string
2020
absoluteAppPath: string
21-
absoluteAppServerPath: string
2221
absoluteDocumentPath: string
2322
absoluteErrorPath: string
2423
absolute404Path: string

packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
6565
_params?: any
6666
) {
6767
let Component
68-
let AppMod
68+
let App
6969
let config
7070
let Document
7171
let Error
@@ -78,7 +78,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
7878
getServerSideProps,
7979
getStaticPaths,
8080
Component,
81-
AppMod,
81+
App,
8282
config,
8383
{ default: Document },
8484
{ default: Error },
@@ -103,7 +103,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
103103
setLazyProp({ req: req as any }, 'cookies', getCookieParser(req.headers))
104104

105105
const options = {
106-
AppMod,
106+
App,
107107
Document,
108108
ComponentMod: { default: Component },
109109
buildManifest,

packages/next/build/webpack/plugins/flight-manifest-plugin.ts

-2
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ export class FlightManifestPlugin {
9696
// For each SC server compilation entry, we need to create its corresponding
9797
// client component entry.
9898
for (const [name, entry] of compilation.entries.entries()) {
99-
if (name === 'pages/_app.server') continue
100-
10199
// Check if the page entry is a server component or not.
102100
const entryDependency = entry.dependencies?.[0]
103101
const request = entryDependency?.request

packages/next/build/webpack/plugins/pages-manifest-plugin.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export default class PagesManifestPlugin implements webpack.Plugin {
6060
file.endsWith('.js')
6161
)
6262

63-
// Skip _app.server entry which is empty
63+
// Skip entries which are empty
6464
if (!files.length) {
6565
continue
6666
}

packages/next/client/index.tsx

+1-8
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ let webpackHMR: any
8686

8787
let CachedApp: AppComponent, onPerfEntry: (metric: any) => void
8888
let CachedComponent: React.ComponentType
89-
let isRSCPage: boolean
9089

9190
class Container extends React.Component<{
9291
fn: (err: Error, info?: any) => void
@@ -331,7 +330,6 @@ export async function hydrate(opts?: { beforeRender?: () => Promise<void> }) {
331330
throw pageEntrypoint.error
332331
}
333332
CachedComponent = pageEntrypoint.component
334-
isRSCPage = !!pageEntrypoint.exports.__next_rsc__
335333

336334
if (process.env.NODE_ENV !== 'production') {
337335
const { isValidElementType } = require('next/dist/compiled/react-is')
@@ -647,12 +645,7 @@ function AppContainer({
647645
}
648646

649647
function renderApp(App: AppComponent, appProps: AppProps) {
650-
if (process.env.__NEXT_RSC && isRSCPage) {
651-
const { Component, err: _, router: __, ...props } = appProps
652-
return <Component {...props} />
653-
} else {
654-
return <App {...appProps} />
655-
}
648+
return <App {...appProps} />
656649
}
657650

658651
const wrapApp =

packages/next/export/index.ts

+1-6
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,7 @@ export default async function exportApp(
237237
continue
238238
}
239239

240-
if (
241-
page === '/_document' ||
242-
page === '/_app.server' ||
243-
page === '/_app' ||
244-
page === '/_error'
245-
) {
240+
if (page === '/_document' || page === '/_app' || page === '/_error') {
246241
continue
247242
}
248243

packages/next/pages/_app.server.tsx

-3
This file was deleted.

packages/next/server/load-components.ts

+1-13
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ export type LoadComponentsReturnType = {
4040
getStaticPaths?: GetStaticPaths
4141
getServerSideProps?: GetServerSideProps
4242
ComponentMod: any
43-
AppMod: any
44-
AppServerMod: any
4543
isViewPath?: boolean
4644
}
4745

@@ -60,9 +58,6 @@ export async function loadDefaultErrorComponents(distDir: string) {
6058
buildManifest: require(join(distDir, `fallback-${BUILD_MANIFEST}`)),
6159
reactLoadableManifest: {},
6260
ComponentMod,
63-
AppMod,
64-
// Use App for fallback
65-
AppServerMod: AppMod,
6661
}
6762
}
6863

@@ -106,7 +101,7 @@ export async function loadComponents(
106101
} as LoadComponentsReturnType
107102
}
108103

109-
const [DocumentMod, AppMod, ComponentMod, AppServerMod] = await Promise.all([
104+
const [DocumentMod, AppMod, ComponentMod] = await Promise.all([
110105
Promise.resolve().then(() =>
111106
requirePage('/_document', distDir, serverless, rootEnabled)
112107
),
@@ -116,11 +111,6 @@ export async function loadComponents(
116111
Promise.resolve().then(() =>
117112
requirePage(pathname, distDir, serverless, rootEnabled)
118113
),
119-
hasServerComponents
120-
? Promise.resolve().then(() =>
121-
requirePage('/_app.server', distDir, serverless, rootEnabled)
122-
)
123-
: null,
124114
])
125115

126116
const [buildManifest, reactLoadableManifest, serverComponentManifest] =
@@ -175,8 +165,6 @@ export async function loadComponents(
175165
reactLoadableManifest,
176166
pageConfig: ComponentMod.config || {},
177167
ComponentMod,
178-
AppMod,
179-
AppServerMod,
180168
getServerSideProps,
181169
getStaticProps,
182170
getStaticPaths,

0 commit comments

Comments
 (0)