Skip to content

Commit 4e84f69

Browse files
authored
Add experimental trace file field (#65071)
This adds a new field to our `.nft.json` trace files when enabled behind a feature flag to output the hashes for the traced files. Closes NEXT-3232
1 parent 3438b39 commit 4e84f69

File tree

9 files changed

+330
-98
lines changed

9 files changed

+330
-98
lines changed

packages/next/src/build/collect-build-traces.ts

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
TRACE_IGNORES,
66
type BuildTraceContext,
77
getFilesMapFromReasons,
8+
getHash,
89
} from './webpack/plugins/next-trace-entrypoints-plugin'
910

1011
import {
@@ -29,6 +30,8 @@ import type { RoutesUsingEdgeRuntime } from './utils'
2930

3031
const debug = debugOriginal('next:build:build-traces')
3132

33+
const hashCache: Record<string, string> = {}
34+
3235
function shouldIgnore(
3336
file: string,
3437
serverIgnoreFn: (file: string) => boolean,
@@ -88,11 +91,13 @@ export async function collectBuildTraces({
8891
hasSsrAmpPages,
8992
buildTraceContext,
9093
outputFileTracingRoot,
94+
isFlyingShuttle,
9195
}: {
9296
dir: string
9397
distDir: string
9498
staticPages: string[]
9599
hasSsrAmpPages: boolean
100+
isFlyingShuttle?: boolean
96101
outputFileTracingRoot: string
97102
// pageInfos is serialized when this function runs in a worker.
98103
edgeRuntimeRoutes: RoutesUsingEdgeRuntime
@@ -496,9 +501,11 @@ export async function collectBuildTraces({
496501
[minimalServerEntries, minimalServerTracedFiles],
497502
] as Array<[string[], Set<string>]>) {
498503
for (const file of entries) {
499-
const curFiles = parentFilesMap.get(
500-
path.relative(outputFileTracingRoot, file)
501-
)
504+
const curFiles = [
505+
...(parentFilesMap
506+
.get(path.relative(outputFileTracingRoot, file))
507+
?.keys() || []),
508+
]
502509
tracedFiles.add(path.relative(distDir, file).replace(/\\/g, '/'))
503510

504511
for (const curFile of curFiles || []) {
@@ -545,8 +552,10 @@ export async function collectBuildTraces({
545552
}
546553

547554
// we don't need to trace for automatically statically optimized
548-
// pages as they don't have server bundles
549-
if (staticPages.includes(route)) {
555+
// pages as they don't have server bundles, note there is
556+
// the caveat with flying shuttle mode as it needs this for
557+
// detecting changed entries
558+
if (staticPages.includes(route) && !isFlyingShuttle) {
550559
return
551560
}
552561
const entryOutputPath = path.join(
@@ -557,14 +566,22 @@ export async function collectBuildTraces({
557566
const traceOutputPath = `${entryOutputPath}.nft.json`
558567
const existingTrace = JSON.parse(
559568
await fs.readFile(traceOutputPath, 'utf8')
560-
)
569+
) as {
570+
version: number
571+
files: string[]
572+
fileHashes: Record<string, string>
573+
}
561574
const traceOutputDir = path.dirname(traceOutputPath)
562575
const curTracedFiles = new Set<string>()
576+
const curFileHashes: Record<string, string> =
577+
existingTrace.fileHashes
563578

564579
for (const file of [...entryNameFiles, entryOutputPath]) {
565-
const curFiles = parentFilesMap.get(
566-
path.relative(outputFileTracingRoot, file)
567-
)
580+
const curFiles = [
581+
...(parentFilesMap
582+
.get(path.relative(outputFileTracingRoot, file))
583+
?.keys() || []),
584+
]
568585
for (const curFile of curFiles || []) {
569586
if (
570587
!shouldIgnore(
@@ -579,6 +596,19 @@ export async function collectBuildTraces({
579596
.relative(traceOutputDir, filePath)
580597
.replace(/\\/g, '/')
581598
curTracedFiles.add(outputFile)
599+
600+
if (isFlyingShuttle) {
601+
try {
602+
let hash = hashCache[filePath]
603+
604+
if (!hash) {
605+
hash = getHash(await fs.readFile(filePath))
606+
}
607+
curFileHashes[outputFile] = hash
608+
} catch (err: any) {
609+
// handle symlink errors or similar
610+
}
611+
}
582612
}
583613
}
584614
}
@@ -592,6 +622,11 @@ export async function collectBuildTraces({
592622
JSON.stringify({
593623
...existingTrace,
594624
files: [...curTracedFiles].sort(),
625+
...(isFlyingShuttle
626+
? {
627+
fileHashes: curFileHashes,
628+
}
629+
: {}),
595630
})
596631
)
597632
})

packages/next/src/build/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,7 @@ export default async function build(
16581658
hasSsrAmpPages: false,
16591659
buildTraceContext,
16601660
outputFileTracingRoot,
1661+
isFlyingShuttle: !!config.experimental.flyingShuttle,
16611662
})
16621663
.catch((err) => {
16631664
console.error(err)
@@ -2396,6 +2397,7 @@ export default async function build(
23962397
hasSsrAmpPages,
23972398
buildTraceContext,
23982399
outputFileTracingRoot,
2400+
isFlyingShuttle: !!config.experimental.flyingShuttle,
23992401
}).catch((err) => {
24002402
console.error(err)
24012403
process.exit(1)

packages/next/src/build/webpack-config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,8 @@ export default async function getBaseWebpackConfig(
17621762
turbotrace: config.experimental.turbotrace,
17631763
optOutBundlingPackages,
17641764
traceIgnores: config.experimental.outputFileTracingIgnores || [],
1765+
flyingShuttle: !!config.experimental.flyingShuttle,
1766+
compilerType,
17651767
}
17661768
),
17671769
// Moment.js is an extremely popular library that bundles large locale files

0 commit comments

Comments
 (0)