Skip to content

Commit 3a22e97

Browse files
authored
Track page counts during builds (#42766)
Ensures we keep track of page counts during builds. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm build && pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
1 parent 028b8d0 commit 3a22e97

File tree

5 files changed

+184
-21
lines changed

5 files changed

+184
-21
lines changed

packages/next/build/index.ts

+38-6
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ export default async function build(
597597
appPageKeys.push(normalizedAppPageKey)
598598
}
599599
}
600+
const totalAppPagesCount = appPageKeys.length
600601

601602
const pageKeys = {
602603
pages: pagesPageKeys,
@@ -1097,6 +1098,7 @@ export default async function build(
10971098
telemetry.record(
10981099
eventBuildCompleted(pagesPaths, {
10991100
durationInSeconds: webpackBuildEnd[0],
1101+
totalAppPagesCount,
11001102
})
11011103
)
11021104

@@ -1121,6 +1123,10 @@ export default async function build(
11211123
const buildManifestPath = path.join(distDir, BUILD_MANIFEST)
11221124
const appBuildManifestPath = path.join(distDir, APP_BUILD_MANIFEST)
11231125

1126+
let staticAppPagesCount = 0
1127+
let serverAppPagesCount = 0
1128+
let edgeRuntimeAppCount = 0
1129+
let edgeRuntimePagesCount = 0
11241130
const ssgPages = new Set<string>()
11251131
const ssgStaticFallbackPages = new Set<string>()
11261132
const ssgBlockingFallbackPages = new Set<string>()
@@ -1300,6 +1306,18 @@ export default async function build(
13001306
config.experimental.gzipSize
13011307
)
13021308

1309+
const middlewareManifest: MiddlewareManifest = require(join(
1310+
distDir,
1311+
SERVER_DIRECTORY,
1312+
MIDDLEWARE_MANIFEST
1313+
))
1314+
1315+
for (const key of Object.keys(middlewareManifest?.functions)) {
1316+
if (key.startsWith('/api')) {
1317+
edgeRuntimePagesCount++
1318+
}
1319+
}
1320+
13031321
await Promise.all(
13041322
Object.entries(pageKeys)
13051323
.reduce<Array<{ pageType: keyof typeof pageKeys; page: string }>>(
@@ -1388,15 +1406,16 @@ export default async function build(
13881406
let edgeInfo: any
13891407

13901408
if (pageRuntime === SERVER_RUNTIME.edge) {
1391-
const manifest = require(join(
1392-
distDir,
1393-
SERVER_DIRECTORY,
1394-
MIDDLEWARE_MANIFEST
1395-
))
1409+
if (pageType === 'app') {
1410+
edgeRuntimeAppCount++
1411+
} else {
1412+
edgeRuntimePagesCount++
1413+
}
1414+
13961415
const manifestKey =
13971416
pageType === 'pages' ? page : originalAppPath || ''
13981417

1399-
edgeInfo = manifest.functions[manifestKey]
1418+
edgeInfo = middlewareManifest.functions[manifestKey]
14001419
}
14011420

14021421
let isPageStaticSpan =
@@ -1581,6 +1600,14 @@ export default async function build(
15811600
}
15821601
}
15831602

1603+
if (pageType === 'app') {
1604+
if (isSsg || isStatic) {
1605+
staticAppPagesCount++
1606+
} else {
1607+
serverAppPagesCount++
1608+
}
1609+
}
1610+
15841611
pageInfos.set(page, {
15851612
size: selfSize,
15861613
totalSize: allSize,
@@ -2589,6 +2616,11 @@ export default async function build(
25892616
.length,
25902617
redirectsWithHasCount: redirects.filter((r: any) => !!r.has).length,
25912618
middlewareCount: Object.keys(rootPaths).length > 0 ? 1 : 0,
2619+
totalAppPagesCount,
2620+
staticAppPagesCount,
2621+
serverAppPagesCount,
2622+
edgeRuntimeAppCount,
2623+
edgeRuntimePagesCount,
25922624
})
25932625
)
25942626

packages/next/build/webpack/plugins/middleware-plugin.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ function getExtractMetadata(params: {
683683
wasmBindings: new Map(),
684684
assetBindings: new Map(),
685685
}
686+
let ogImageGenerationCount = 0
686687

687688
for (const module of modules) {
688689
const buildInfo = getModuleBuildInfo(module)
@@ -697,13 +698,10 @@ function getExtractMetadata(params: {
697698
/[\\/]node_modules[\\/]@vercel[\\/]og[\\/]dist[\\/]index.js$/.test(
698699
resource
699700
)
700-
telemetry.record({
701-
eventName: EVENT_BUILD_FEATURE_USAGE,
702-
payload: {
703-
featureName: 'vercelImageGeneration',
704-
invocationCount: hasOGImageGeneration ? 1 : 0,
705-
},
706-
})
701+
702+
if (hasOGImageGeneration) {
703+
ogImageGenerationCount++
704+
}
707705
}
708706

709707
/**
@@ -818,6 +816,13 @@ function getExtractMetadata(params: {
818816
}
819817
}
820818

819+
telemetry.record({
820+
eventName: EVENT_BUILD_FEATURE_USAGE,
821+
payload: {
822+
featureName: 'vercelImageGeneration',
823+
invocationCount: ogImageGenerationCount,
824+
},
825+
})
821826
metadataByEntry.set(entryName, entryMetadata)
822827
}
823828
}

packages/next/telemetry/events/build.ts

+12
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type EventBuildCompleted = {
5656
totalPageCount: number
5757
hasDunderPages: boolean
5858
hasTestPages: boolean
59+
totalAppPagesCount?: number
5960
}
6061

6162
export function eventBuildCompleted(
@@ -77,6 +78,7 @@ export function eventBuildCompleted(
7778
(path) =>
7879
REGEXP_DIRECTORY_TESTS.test(path) || REGEXP_FILE_TEST.test(path)
7980
),
81+
totalAppPagesCount: event.totalAppPagesCount,
8082
},
8183
}
8284
}
@@ -100,6 +102,11 @@ type EventBuildOptimized = {
100102
rewritesWithHasCount: number
101103
redirectsWithHasCount: number
102104
middlewareCount: number
105+
totalAppPagesCount?: number
106+
staticAppPagesCount?: number
107+
serverAppPagesCount?: number
108+
edgeRuntimeAppCount?: number
109+
edgeRuntimePagesCount?: number
103110
}
104111

105112
export function eventBuildOptimize(
@@ -121,6 +128,11 @@ export function eventBuildOptimize(
121128
(path) =>
122129
REGEXP_DIRECTORY_TESTS.test(path) || REGEXP_FILE_TEST.test(path)
123130
),
131+
totalAppPagesCount: event.totalAppPagesCount,
132+
staticAppPagesCount: event.staticAppPagesCount,
133+
serverAppPagesCount: event.serverAppPagesCount,
134+
edgeRuntimeAppCount: event.edgeRuntimeAppCount,
135+
edgeRuntimePagesCount: event.edgeRuntimePagesCount,
124136
},
125137
}
126138
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Image from 'next/image'
2+
import LegacyImage from 'next/legacy/image'
3+
import profilePic from '../public/small.jpg'
4+
5+
export const config = {
6+
runtime: 'experimental-edge',
7+
}
8+
9+
function About() {
10+
return (
11+
<>
12+
<h1>My Homepage</h1>
13+
<Image src={profilePic} alt="Picture of the author" />
14+
<p>Welcome to my homepage!</p>
15+
</>
16+
)
17+
}
18+
19+
export default About
20+
21+
export function AboutFutureImage() {
22+
return <LegacyImage src={profilePic} alt="Picture of the author" />
23+
}

test/integration/telemetry/test/index.test.js

+99-8
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,14 @@ describe('Telemetry CLI', () => {
331331
const event1 = /NEXT_BUILD_OPTIMIZED[\s\S]+?{([\s\S]+?)}/.exec(stderr).pop()
332332
expect(event1).toMatch(/"staticPropsPageCount": 2/)
333333
expect(event1).toMatch(/"serverPropsPageCount": 2/)
334-
expect(event1).toMatch(/"ssrPageCount": 2/)
334+
expect(event1).toMatch(/"ssrPageCount": 3/)
335335
expect(event1).toMatch(/"staticPageCount": 4/)
336-
expect(event1).toMatch(/"totalPageCount": 10/)
336+
expect(event1).toMatch(/"totalPageCount": 11/)
337+
expect(event1).toMatch(/"totalAppPagesCount": 0/)
338+
expect(event1).toMatch(/"staticAppPagesCount": 0/)
339+
expect(event1).toMatch(/"serverAppPagesCount": 0/)
340+
expect(event1).toMatch(/"edgeRuntimeAppCount": 0/)
341+
expect(event1).toMatch(/"edgeRuntimePagesCount": 2/)
337342
})
338343

339344
it('detects isSrcDir dir correctly for `next dev`', async () => {
@@ -377,7 +382,19 @@ describe('Telemetry CLI', () => {
377382
)
378383
await fs.mkdir(path.join(__dirname, '../app'))
379384
await fs.writeFile(
380-
path.join(__dirname, '../app/page.js'),
385+
path.join(__dirname, '../app/layout.js'),
386+
`
387+
export default function RootLayout({ children }) {
388+
return <html>
389+
<head/>
390+
<body>{children}</body>
391+
</html>
392+
}
393+
`
394+
)
395+
await fs.ensureFile(path.join(__dirname, '../app/hello/page.js'))
396+
await fs.writeFile(
397+
path.join(__dirname, '../app/hello/page.js'),
381398
'export default function Page() { return "hello world" }'
382399
)
383400

@@ -490,6 +507,73 @@ describe('Telemetry CLI', () => {
490507
}
491508
})
492509

510+
it('should detect app page counts', async () => {
511+
const teardown = await setupAppDir()
512+
513+
try {
514+
await fs.ensureFile(path.join(__dirname, '../app/ssr/page.js'))
515+
await fs.writeFile(
516+
path.join(__dirname, '../app/ssr/page.js'),
517+
`
518+
export const revalidate = 0
519+
export default function Page() {
520+
return <p>ssr page</p>
521+
}
522+
`
523+
)
524+
await fs.ensureFile(path.join(__dirname, '../app/edge-ssr/page.js'))
525+
await fs.writeFile(
526+
path.join(__dirname, '../app/edge-ssr/page.js'),
527+
`
528+
export const runtime = 'experimental-edge'
529+
export default function Page() {
530+
return <p>edge-ssr page</p>
531+
}
532+
`
533+
)
534+
await fs.ensureFile(path.join(__dirname, '../app/app-ssg/[slug]/page.js'))
535+
await fs.writeFile(
536+
path.join(__dirname, '../app/app-ssg/[slug]/page.js'),
537+
`
538+
export function generateStaticParams() {
539+
return [
540+
{ slug: 'post-1' },
541+
{ slug: 'post-2' },
542+
]
543+
}
544+
export default function Page() {
545+
return <p>ssg page</p>
546+
}
547+
`
548+
)
549+
const { stderr } = await nextBuild(appDir, [], {
550+
stderr: true,
551+
env: { NEXT_TELEMETRY_DEBUG: 1 },
552+
})
553+
554+
const event1 = /NEXT_BUILD_OPTIMIZED[\s\S]+?{([\s\S]+?)}/
555+
.exec(stderr)
556+
.pop()
557+
expect(event1).toMatch(/"staticPropsPageCount": 2/)
558+
expect(event1).toMatch(/"serverPropsPageCount": 2/)
559+
expect(event1).toMatch(/"ssrPageCount": 3/)
560+
expect(event1).toMatch(/"staticPageCount": 4/)
561+
expect(event1).toMatch(/"totalPageCount": 11/)
562+
expect(event1).toMatch(/"totalAppPagesCount": 4/)
563+
expect(event1).toMatch(/"serverAppPagesCount": 2/)
564+
expect(event1).toMatch(/"edgeRuntimeAppCount": 1/)
565+
expect(event1).toMatch(/"edgeRuntimePagesCount": 2/)
566+
567+
const event2 = /NEXT_BUILD_COMPLETED[\s\S]+?{([\s\S]+?)}/
568+
.exec(stderr)
569+
.pop()
570+
571+
expect(event2).toMatch(/"totalAppPagesCount": 4/)
572+
} finally {
573+
await teardown()
574+
}
575+
})
576+
493577
it('detect reportWebVitals correctly for `next build`', async () => {
494578
// Case 1: When _app.js does not exist.
495579
let build = await nextBuild(appDir, [], {
@@ -750,6 +834,7 @@ describe('Telemetry CLI', () => {
750834
stderr,
751835
'NEXT_BUILD_FEATURE_USAGE'
752836
)
837+
753838
expect(featureUsageEvents).toEqual(
754839
expect.arrayContaining([
755840
{
@@ -758,7 +843,7 @@ describe('Telemetry CLI', () => {
758843
},
759844
{
760845
featureName: 'next/image',
761-
invocationCount: 1,
846+
invocationCount: 2,
762847
},
763848
{
764849
featureName: 'next/script',
@@ -787,8 +872,14 @@ describe('Telemetry CLI', () => {
787872
stderr: true,
788873
env: { NEXT_TELEMETRY_DEBUG: 1 },
789874
})
790-
await fs.remove(path.join(appDir, 'next.config.js'))
791-
await fs.remove(path.join(appDir, 'jsconfig.json'))
875+
await fs.rename(
876+
path.join(appDir, 'next.config.js'),
877+
path.join(appDir, 'next.config.swc')
878+
)
879+
await fs.rename(
880+
path.join(appDir, 'jsconfig.json'),
881+
path.join(appDir, 'jsconfig.swc')
882+
)
792883
const featureUsageEvents = findAllTelemetryEvents(
793884
stderr,
794885
'NEXT_BUILD_FEATURE_USAGE'
@@ -963,11 +1054,11 @@ describe('Telemetry CLI', () => {
9631054
)
9641055
expect(featureUsageEvents).toContainEqual({
9651056
featureName: 'next/legacy/image',
966-
invocationCount: 1,
1057+
invocationCount: 2,
9671058
})
9681059
expect(featureUsageEvents).toContainEqual({
9691060
featureName: 'next/image',
970-
invocationCount: 1,
1061+
invocationCount: 2,
9711062
})
9721063
})
9731064

0 commit comments

Comments
 (0)