Skip to content

Commit 394eddb

Browse files
authoredJul 1, 2024··
[cli] Collect diagnostics from builders during vc build (#11653)
Adds the ability for builders to define a `diagnostics` step that is called after the build operation is done (either failed or successful). Implements the diagnostics step in the next builder. **References** - vercel/next.js#66187
1 parent 7181dd0 commit 394eddb

File tree

4 files changed

+71
-17
lines changed

4 files changed

+71
-17
lines changed
 

‎.changeset/hot-rules-tickle.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@vercel/build-utils': minor
3+
'@vercel/next': minor
4+
'vercel': minor
5+
---
6+
7+
Adds the ability for builders to define a `diagnostics` step that is called after the build operation is done.
8+
Implements the diagnostics step in the `next` builder.

‎packages/build-utils/src/types.ts

+3
Original file line numberDiff line numberDiff line change
@@ -362,13 +362,15 @@ export interface ProjectSettings {
362362
export interface BuilderV2 {
363363
version: 2;
364364
build: BuildV2;
365+
diagnostics?: Diagnostics;
365366
prepareCache?: PrepareCache;
366367
shouldServe?: ShouldServe;
367368
}
368369

369370
export interface BuilderV3 {
370371
version: 3;
371372
build: BuildV3;
373+
diagnostics?: Diagnostics;
372374
prepareCache?: PrepareCache;
373375
shouldServe?: ShouldServe;
374376
startDevServer?: StartDevServer;
@@ -477,6 +479,7 @@ export interface BuildResultV3 {
477479
export type BuildV2 = (options: BuildOptions) => Promise<BuildResultV2>;
478480
export type BuildV3 = (options: BuildOptions) => Promise<BuildResultV3>;
479481
export type PrepareCache = (options: PrepareCacheOptions) => Promise<Files>;
482+
export type Diagnostics = (options: BuildOptions) => Promise<Files>;
480483
export type ShouldServe = (
481484
options: ShouldServeOptions
482485
) => boolean | Promise<boolean>;

‎packages/cli/src/commands/build/index.ts

+29-17
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,22 @@ import { join, normalize, relative, resolve, sep } from 'path';
77
import { frameworkList } from '@vercel/frameworks';
88
import {
99
getDiscontinuedNodeVersions,
10+
getInstalledPackageVersion,
1011
normalizePath,
11-
Files,
1212
FileFsRef,
13-
PackageJson,
14-
BuildOptions,
15-
Config,
16-
Meta,
17-
Builder,
18-
BuildResultV2,
19-
BuildResultV2Typical,
20-
BuildResultV3,
2113
NowBuildError,
22-
Cron,
2314
validateNpmrc,
15+
type Files,
16+
type PackageJson,
17+
type BuildOptions,
18+
type Config,
19+
type Meta,
20+
type Builder,
21+
type BuildResultV2,
22+
type BuildResultV2Typical,
23+
type BuildResultV3,
24+
type Cron,
2425
type FlagDefinitions,
25-
getInstalledPackageVersion,
2626
} from '@vercel/build-utils';
2727
import {
2828
detectBuilders,
@@ -34,15 +34,15 @@ import {
3434
appendRoutesToPhase,
3535
getTransformedRoutes,
3636
mergeRoutes,
37-
MergeRoutesProps,
38-
Route,
37+
type MergeRoutesProps,
38+
type Route,
3939
} from '@vercel/routing-utils';
4040
import { fileNameSymbol } from '@vercel/client';
4141
import type { VercelConfig } from '@vercel/client';
4242

4343
import pull from '../pull';
4444
import { staticFiles as getFiles } from '../../util/get-files';
45-
import Client from '../../util/client';
45+
import type Client from '../../util/client';
4646
import { parseArguments } from '../../util/get-args';
4747
import cmd from '../../util/output/cmd';
4848
import * as cli from '../../util/pkg-name';
@@ -51,17 +51,17 @@ import readJSONFile from '../../util/read-json-file';
5151
import { CantParseJSONFile } from '../../util/errors-ts';
5252
import {
5353
pickOverrides,
54-
ProjectLinkAndSettings,
5554
readProjectSettings,
55+
type ProjectLinkAndSettings,
5656
} from '../../util/projects/project-settings';
5757
import { getProjectLink, VERCEL_DIR } from '../../util/projects/link';
5858
import confirm from '../../util/input/confirm';
5959
import { emoji, prependEmoji } from '../../util/emoji';
6060
import stamp from '../../util/output/stamp';
6161
import {
6262
OUTPUT_DIR,
63-
PathOverride,
6463
writeBuildResult,
64+
type PathOverride,
6565
} from '../../util/build/write-build-result';
6666
import { importBuilders } from '../../util/build/import-builders';
6767
import { initCorepack, cleanupCorepack } from '../../util/build/corepack';
@@ -476,6 +476,7 @@ async function doBuild(
476476
const overrides: PathOverride[] = [];
477477
const repoRootPath = cwd;
478478
const corepackShimDir = await initCorepack({ repoRootPath }, output);
479+
const diagnostics: Files = {};
479480

480481
for (const build of sortedBuilders) {
481482
if (typeof build.src !== 'string') continue;
@@ -527,7 +528,18 @@ async function doBuild(
527528
output.debug(
528529
`Building entrypoint "${build.src}" with "${builderPkg.name}"`
529530
);
530-
const buildResult = await builder.build(buildOptions);
531+
let buildResult: BuildResultV2 | BuildResultV3 | undefined;
532+
try {
533+
buildResult = await builder.build(buildOptions);
534+
} finally {
535+
// Make sure we don't fail the build
536+
try {
537+
Object.assign(diagnostics, await builder.diagnostics?.(buildOptions));
538+
} catch (error) {
539+
output.error('Collecting diagnostics failed');
540+
output.debug(error);
541+
}
542+
}
531543

532544
if (
533545
buildResult &&

‎packages/next/src/index.ts

+31
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
Diagnostics,
23
FileBlob,
34
FileFsRef,
45
Files,
@@ -2725,6 +2726,36 @@ export const build: BuildV2 = async ({
27252726
};
27262727
};
27272728

2729+
export const diagnostics: Diagnostics = async ({
2730+
config,
2731+
entrypoint,
2732+
workPath,
2733+
repoRootPath,
2734+
}) => {
2735+
const entryDirectory = path.dirname(entrypoint);
2736+
const entryPath = path.join(workPath, entryDirectory);
2737+
const outputDirectory = path.join('./', config.outputDirectory || '.next');
2738+
const basePath = repoRootPath || workPath;
2739+
const diagnosticsEntrypoint = path.relative(basePath, entryPath);
2740+
2741+
debug(
2742+
`Reading diagnostics file in diagnosticsEntrypoint=${diagnosticsEntrypoint}`
2743+
);
2744+
2745+
return {
2746+
// Collect output in `.next/diagnostics`
2747+
...(await glob(
2748+
'diagnostics/*',
2749+
path.join(basePath, diagnosticsEntrypoint, outputDirectory, 'diagnostics')
2750+
)),
2751+
// Collect `.next/trace` file
2752+
...(await glob(
2753+
'trace',
2754+
path.join(basePath, diagnosticsEntrypoint, outputDirectory)
2755+
)),
2756+
};
2757+
};
2758+
27282759
export const prepareCache: PrepareCache = async ({
27292760
workPath,
27302761
repoRootPath,

0 commit comments

Comments
 (0)
Please sign in to comment.