Skip to content

Commit

Permalink
Merge app internal chunk into main chunk for layouts (#41902)
Browse files Browse the repository at this point in the history
When emitting the client components entry from server compiler, merging
app internal entry into main-app to avoid duplicated chunks like react
are generated in both sides

Related: #41870
  • Loading branch information
huozhi committed Oct 27, 2022
1 parent c17e7cb commit 3618b90
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 22 deletions.
14 changes: 13 additions & 1 deletion packages/next/build/index.ts
Expand Up @@ -59,6 +59,8 @@ import {
FLIGHT_SERVER_CSS_MANIFEST,
RSC_MODULE_TYPES,
FONT_LOADER_MANIFEST,
CLIENT_STATIC_FILES_RUNTIME_MAIN_APP,
APP_CLIENT_INTERNALS,
} from '../shared/lib/constants'
import { getSortedRoutes, isDynamicRoute } from '../shared/lib/router/utils'
import { __ApiPreviewProps } from '../server/api-utils'
Expand Down Expand Up @@ -975,7 +977,17 @@ export default async function build(
// Only continue if there were no errors
if (!serverResult.errors.length && !edgeServerResult?.errors.length) {
injectedClientEntries.forEach((value, key) => {
;(clientConfig.entry as webpack.EntryObject)[key] = value
const clientEntry = clientConfig.entry as webpack.EntryObject
if (key === APP_CLIENT_INTERNALS) {
clientEntry[CLIENT_STATIC_FILES_RUNTIME_MAIN_APP] = [
// TODO-APP: cast clientEntry[CLIENT_STATIC_FILES_RUNTIME_MAIN_APP] to type EntryDescription once it's available from webpack
// @ts-expect-error clientEntry['main-app'] is type EntryDescription { import: ... }
...clientEntry[CLIENT_STATIC_FILES_RUNTIME_MAIN_APP].import,
value,
]
} else {
clientEntry[key] = value
}
})

clientResult = await runCompiler(clientConfig, {
Expand Down
19 changes: 12 additions & 7 deletions packages/next/build/webpack-config.ts
Expand Up @@ -795,13 +795,18 @@ export default async function getBaseWebpackConfig(
)
.replace(/\\/g, '/'),
]
: `./` +
path
.relative(
dir,
path.join(NEXT_PROJECT_ROOT_DIST_CLIENT, 'app-next.js')
)
.replace(/\\/g, '/'),
: [
`./` +
path
.relative(
dir,
path.join(
NEXT_PROJECT_ROOT_DIST_CLIENT,
'app-next.js'
)
)
.replace(/\\/g, '/'),
],
}
: {}),
} as ClientEntries)
Expand Down
19 changes: 9 additions & 10 deletions packages/next/build/webpack/plugins/flight-client-entry-plugin.ts
Expand Up @@ -13,6 +13,7 @@ import type {
} from '../loaders/next-flight-client-entry-loader'
import { APP_DIR_ALIAS, WEBPACK_LAYERS } from '../../../lib/constants'
import {
APP_CLIENT_INTERNALS,
COMPILER_NAMES,
EDGE_RUNTIME_WEBPACK,
FLIGHT_SERVER_CSS_MANIFEST,
Expand Down Expand Up @@ -219,7 +220,7 @@ export class FlightClientEntryPlugin {
compilation,
entryName: name,
clientComponentImports: [...internalClientComponentEntryImports],
bundlePath: 'app-internals',
bundlePath: APP_CLIENT_INTERNALS,
})
)
})
Expand Down Expand Up @@ -517,28 +518,26 @@ export class FlightClientEntryPlugin {
addEntry(
compilation: any,
context: string,
entry: any /* Dependency */,
options: {
name: string
layer: string | undefined
} /* EntryOptions */
dependency: any /* Dependency */,
options: any /* EntryOptions */
): Promise<any> /* Promise<module> */ {
return new Promise((resolve, reject) => {
compilation.entries.get(options.name).includeDependencies.push(entry)
const entry = compilation.entries.get(options.name)
entry.includeDependencies.push(dependency)
compilation.hooks.addEntry.call(entry, options)
compilation.addModuleTree(
{
context,
dependency: entry,
dependency,
contextInfo: { issuerLayer: options.layer },
},
(err: Error | undefined, module: any) => {
if (err) {
compilation.hooks.failedEntry.call(entry, options, err)
compilation.hooks.failedEntry.call(dependency, options, err)
return reject(err)
}

compilation.hooks.succeedEntry.call(entry, options, module)
compilation.hooks.succeedEntry.call(dependency, options, module)
return resolve(module)
}
)
Expand Down
5 changes: 2 additions & 3 deletions packages/next/client/app-next.js
Expand Up @@ -2,9 +2,8 @@ import { appBootstrap } from './app-bootstrap'

appBootstrap(() => {
// Include app-router and layout-router in the main chunk
import('next/dist/client/components/app-router.js')
import('next/dist/client/components/layout-router.js')

require('next/dist/client/components/app-router')
require('next/dist/client/components/layout-router')
const { hydrate } = require('./app-index')
hydrate()
})
2 changes: 2 additions & 0 deletions packages/next/shared/lib/constants.ts
Expand Up @@ -76,6 +76,8 @@ export const MIDDLEWARE_REACT_LOADABLE_MANIFEST =
// static/runtime/main.js
export const CLIENT_STATIC_FILES_RUNTIME_MAIN = `main`
export const CLIENT_STATIC_FILES_RUNTIME_MAIN_APP = `${CLIENT_STATIC_FILES_RUNTIME_MAIN}-app`
// next internal client components chunk for layouts
export const APP_CLIENT_INTERNALS = 'app-client-internals'
// static/runtime/react-refresh.js
export const CLIENT_STATIC_FILES_RUNTIME_REACT_REFRESH = `react-refresh`
// static/runtime/amp.js
Expand Down
2 changes: 1 addition & 1 deletion test/.stats-app/app/app-edge-ssr/page.js
@@ -1,5 +1,5 @@
export default function page() {
return 'edge-ssr'
return 'app-edge-ssr'
}

export const runtime = 'experimental-edge'
5 changes: 5 additions & 0 deletions test/.stats-app/app/app-ssr/page.js
@@ -0,0 +1,5 @@
export default function page() {
return 'app-ssr'
}

export const revalidate = 0

0 comments on commit 3618b90

Please sign in to comment.