Skip to content

Commit 29010ff

Browse files
authored
Update cases for build complete with adapters (#84361)
This handles `i18n` cases, ensures `pathname` field is prefixed with `basePath` when configured, and fixes interop with `output: 'export'` configured.
1 parent 9c9e793 commit 29010ff

File tree

9 files changed

+1194
-1002
lines changed

9 files changed

+1194
-1002
lines changed

packages/next/src/build/adapter/build-complete.ts

Lines changed: 108 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import {
3535
JSON_CONTENT_TYPE_HEADER,
3636
NEXT_RESUME_HEADER,
3737
} from '../../lib/constants'
38+
import { normalizeLocalePath } from '../../shared/lib/i18n/normalize-locale-path'
39+
import { addPathPrefix } from '../../shared/lib/router/utils/add-path-prefix'
3840

3941
interface SharedRouteFields {
4042
/**
@@ -62,6 +64,12 @@ interface SharedRouteFields {
6264
*/
6365
assets: Record<string, string>
6466

67+
/**
68+
* wasmAssets are bundled wasm files with mapping of name
69+
* to filePath on disk
70+
*/
71+
wasmAssets?: Record<string, string>
72+
6573
/**
6674
* config related to the route
6775
*/
@@ -77,6 +85,12 @@ interface SharedRouteFields {
7785
* region preferences to the provider being used
7886
*/
7987
preferredRegion?: string | string[]
88+
89+
/**
90+
* env is the environment variables to expose, this is only
91+
* populated for edge runtime currently
92+
*/
93+
env?: Record<string, string>
8094
}
8195
}
8296

@@ -297,9 +311,30 @@ export interface NextAdapter {
297311
}) => Promise<void> | void
298312
}
299313

314+
function normalizePathnames(
315+
config: NextConfigComplete,
316+
outputs: AdapterOutputs
317+
) {
318+
// normalize pathname field with basePath
319+
if (config.basePath) {
320+
for (const output of [
321+
...outputs.pages,
322+
...outputs.pagesApi,
323+
...outputs.appPages,
324+
...outputs.appRoutes,
325+
...outputs.prerenders,
326+
...outputs.staticFiles,
327+
...(outputs.middleware ? [outputs.middleware] : []),
328+
]) {
329+
output.pathname = addPathPrefix(output.pathname, config.basePath)
330+
}
331+
}
332+
}
333+
300334
export async function handleBuildComplete({
301335
dir,
302336
config,
337+
configOutDir,
303338
distDir,
304339
pageKeys,
305340
tracingRoot,
@@ -318,6 +353,7 @@ export async function handleBuildComplete({
318353
}: {
319354
dir: string
320355
distDir: string
356+
configOutDir: string
321357
adapterPath: string
322358
tracingRoot: string
323359
nextVersion: string
@@ -341,16 +377,34 @@ export async function handleBuildComplete({
341377
if (typeof adapterMod.onBuildComplete === 'function') {
342378
Log.info(`Running onBuildComplete from ${adapterMod.name}`)
343379

344-
try {
345-
const outputs: AdapterOutputs = {
346-
pages: [],
347-
pagesApi: [],
348-
appPages: [],
349-
appRoutes: [],
350-
prerenders: [],
351-
staticFiles: [],
352-
}
380+
const outputs: AdapterOutputs = {
381+
pages: [],
382+
pagesApi: [],
383+
appPages: [],
384+
appRoutes: [],
385+
prerenders: [],
386+
staticFiles: [],
387+
}
388+
389+
if (config.output === 'export') {
390+
// collect export assets and provide as static files
391+
const exportFiles = await recursiveReadDir(configOutDir)
392+
393+
for (const file of exportFiles) {
394+
let pathname = (
395+
file.endsWith('.html') ? file.replace(/\.html$/, '') : file
396+
).replace(/\\/g, '/')
353397

398+
pathname = pathname.startsWith('/') ? pathname : `/${pathname}`
399+
400+
outputs.staticFiles.push({
401+
id: file,
402+
pathname,
403+
filePath: path.join(configOutDir, file),
404+
type: AdapterOutputType.STATIC_FILE,
405+
} satisfies AdapterOutput['STATIC_FILE'])
406+
}
407+
} else {
354408
const staticFiles = await recursiveReadDir(path.join(distDir, 'static'))
355409

356410
for (const file of staticFiles) {
@@ -460,12 +514,15 @@ export async function handleBuildComplete({
460514
''
461515
),
462516
assets: {},
463-
config:
464-
type === AdapterOutputType.MIDDLEWARE
517+
wasmAssets: {},
518+
config: {
519+
...(type === AdapterOutputType.MIDDLEWARE
465520
? {
466521
matchers: page.matchers,
467522
}
468-
: {},
523+
: {}),
524+
env: page.env,
525+
},
469526
}
470527

471528
function handleFile(file: string) {
@@ -482,9 +539,15 @@ export async function handleBuildComplete({
482539
for (const file of page.files) {
483540
handleFile(file)
484541
}
485-
for (const item of [...(page.wasm || []), ...(page.assets || [])]) {
542+
for (const item of [...(page.assets || [])]) {
486543
handleFile(item.filePath)
487544
}
545+
for (const item of page.wasm || []) {
546+
if (!output.wasmAssets) {
547+
output.wasmAssets = {}
548+
}
549+
output.wasmAssets[item.name] = item.filePath
550+
}
488551

489552
if (type === AdapterOutputType.MIDDLEWARE) {
490553
outputs.middleware = output
@@ -528,12 +591,28 @@ export async function handleBuildComplete({
528591
// if it's an auto static optimized page it's just
529592
// a static file
530593
if (staticPages.has(page)) {
531-
outputs.staticFiles.push({
532-
id: page,
533-
pathname: route,
534-
type: AdapterOutputType.STATIC_FILE,
535-
filePath: pageFile.replace(/\.js$/, '.html'),
536-
} satisfies AdapterOutput['STATIC_FILE'])
594+
if (config.i18n) {
595+
for (const locale of config.i18n.locales || []) {
596+
const localePage =
597+
page === '/' ? `/${locale}` : addPathPrefix(page, `/${locale}`)
598+
outputs.staticFiles.push({
599+
id: localePage,
600+
pathname: localePage,
601+
type: AdapterOutputType.STATIC_FILE,
602+
filePath: path.join(
603+
pagesDistDir,
604+
`${normalizePagePath(localePage)}.html`
605+
),
606+
} satisfies AdapterOutput['STATIC_FILE'])
607+
}
608+
} else {
609+
outputs.staticFiles.push({
610+
id: page,
611+
pathname: route,
612+
type: AdapterOutputType.STATIC_FILE,
613+
filePath: pageFile.replace(/\.js$/, '.html'),
614+
} satisfies AdapterOutput['STATIC_FILE'])
615+
}
537616
continue
538617
}
539618

@@ -639,7 +718,12 @@ export async function handleBuildComplete({
639718
childRoute: string,
640719
allowMissing?: boolean
641720
) => {
642-
const parentOutput = pageOutputMap[srcRoute] || appOutputMap[srcRoute]
721+
const normalizedSrcRoute = normalizeLocalePath(
722+
srcRoute,
723+
config.i18n?.locales || []
724+
).pathname
725+
const parentOutput =
726+
pageOutputMap[normalizedSrcRoute] || appOutputMap[normalizedSrcRoute]
643727

644728
if (!parentOutput && !allowMissing) {
645729
console.error({
@@ -966,7 +1050,11 @@ export async function handleBuildComplete({
9661050
}
9671051
prerenderGroupId += 1
9681052
}
1053+
}
1054+
1055+
normalizePathnames(config, outputs)
9691056

1057+
try {
9701058
await adapterMod.onBuildComplete({
9711059
routes: {
9721060
dynamicRoutes: routesManifest.dynamicRoutes,

packages/next/src/build/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3796,7 +3796,7 @@ export default async function build(
37963796
dataRoute: path.posix.join(
37973797
'/_next/data',
37983798
buildId,
3799-
`${file}.json`
3799+
`${localePage}.json`
38003800
),
38013801
prefetchDataRoute: undefined,
38023802
allowHeader: ALLOWED_HEADERS,
@@ -4085,6 +4085,9 @@ export default async function build(
40854085
})
40864086
}
40874087

4088+
// This should come after output: export handling but before
4089+
// output: standalone, in the future output: standalone might
4090+
// not be allowed if an adapter with onBuildComplete is configured
40884091
const adapterPath = config.experimental.adapterPath
40894092
if (adapterPath) {
40904093
await nextBuildSpan
@@ -4094,6 +4097,7 @@ export default async function build(
40944097
dir,
40954098
distDir,
40964099
config,
4100+
configOutDir: path.join(dir, configOutDir),
40974101
staticPages,
40984102
nextVersion: process.env.__NEXT_VERSION as string,
40994103
tracingRoot: outputFileTracingRoot,

0 commit comments

Comments
 (0)