Skip to content

Commit

Permalink
feat(@angular-devkit/build-angular): implement stats-json option for …
Browse files Browse the repository at this point in the history
…esbuild builder

When using the experimental esbuild-based browser application builder, the `--stats-json`
option can now be used to create an esbuild metafile named `stats.json` in the output
directory of the application. The metafile contents will contain information about the
application JavaScript, global stylesheets, and the component stylesheets used by the
Angular compiler. While the `--stats-json` option controls the output of the file onto
the filesystem, the metafile data is internally always created to support the future
integration of the bundle budget and console build stat output capabilities.
The metafile format follows the structure of the esbuild metafile format. Information
regarding the file format can be found here: https://esbuild.github.io/api/#metafile
  • Loading branch information
clydin authored and angular-robot[bot] committed Jan 3, 2023
1 parent 31f60f8 commit 839d0cb
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 2 deletions.
Expand Up @@ -7,6 +7,7 @@
*/

import type {
Metafile,
OnStartResult,
OutputFile,
PartialMessage,
Expand Down Expand Up @@ -237,6 +238,8 @@ export function createCompilerPlugin(
// The stylesheet resources from component stylesheets that will be added to the build results output files
let stylesheetResourceFiles: OutputFile[];

let stylesheetMetafiles: Metafile[];

let compilation: AngularCompilation | undefined;

build.onStart(async () => {
Expand All @@ -252,6 +255,7 @@ export function createCompilerPlugin(

// Reset stylesheet resource output files
stylesheetResourceFiles = [];
stylesheetMetafiles = [];

// Create Angular compiler host options
const hostOptions: AngularHostOptions = {
Expand All @@ -276,6 +280,9 @@ export function createCompilerPlugin(
(result.errors ??= []).push(...errors);
(result.warnings ??= []).push(...warnings);
stylesheetResourceFiles.push(...resourceFiles);
if (stylesheetResult.metafile) {
stylesheetMetafiles.push(stylesheetResult.metafile);
}

return contents;
},
Expand Down Expand Up @@ -403,10 +410,19 @@ export function createCompilerPlugin(
);

build.onEnd((result) => {
// Add any component stylesheet resource files to the output files
if (stylesheetResourceFiles.length) {
result.outputFiles?.push(...stylesheetResourceFiles);
}

// Combine component stylesheet metafiles with main metafile
if (result.metafile && stylesheetMetafiles.length) {
for (const metafile of stylesheetMetafiles) {
result.metafile.inputs = { ...result.metafile.inputs, ...metafile.inputs };
result.metafile.outputs = { ...result.metafile.outputs, ...metafile.outputs };
}
}

logCumulativeDurations();
});
},
Expand Down
Expand Up @@ -15,7 +15,6 @@ const UNSUPPORTED_OPTIONS: Array<keyof BrowserBuilderOptions> = [
'extractLicenses',
'progress',
'scripts',
'statsJson',

// * i18n support
'localize',
Expand Down
Expand Up @@ -7,7 +7,7 @@
*/

import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
import type { BuildInvalidate, BuildOptions, OutputFile } from 'esbuild';
import type { BuildInvalidate, BuildOptions, Metafile, OutputFile } from 'esbuild';
import assert from 'node:assert';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
Expand Down Expand Up @@ -141,6 +141,12 @@ async function execute(
const initialFiles: FileInfo[] = [...codeResults.initialFiles, ...styleResults.initialFiles];
const outputFiles: OutputFile[] = [...codeResults.outputFiles, ...styleResults.outputFiles];

// Combine metafiles used for the stats option as well as bundle budgets and console output
const metafile = {
inputs: { ...codeResults.metafile?.inputs, ...styleResults.metafile?.inputs },
outputs: { ...codeResults.metafile?.outputs, ...styleResults.metafile?.outputs },
};

// Generate index HTML file
if (indexHtmlOptions) {
// Create an index HTML generator that reads from the in-memory output files
Expand Down Expand Up @@ -191,6 +197,10 @@ async function execute(
await Promise.all(
outputFiles.map((file) => fs.writeFile(path.join(outputPath, file.path), file.contents)),
);
// Write metafile if stats option is enabled
if (options.stats) {
await fs.writeFile(path.join(outputPath, 'stats.json'), JSON.stringify(metafile, null, 2));
}

// Augment the application with service worker support
// TODO: This should eventually operate on the in-memory files prior to writing the output files
Expand Down Expand Up @@ -258,6 +268,7 @@ function createCodeBundleOptions(
mainFields: ['es2020', 'browser', 'module', 'main'],
conditions: ['es2020', 'es2015', 'module'],
resolveExtensions: ['.ts', '.tsx', '.mjs', '.js'],
metafile: true,
logLevel: options.verbose ? 'debug' : 'silent',
minify: optimizationOptions.scripts,
pure: ['forwardRef'],
Expand Down
Expand Up @@ -139,6 +139,7 @@ export async function normalizeOptions(
inlineStyleLanguage = 'css',
poll,
preserveSymlinks,
statsJson,
stylePreprocessorOptions,
subresourceIntegrity,
verbose,
Expand All @@ -153,6 +154,7 @@ export async function normalizeOptions(
crossOrigin,
externalDependencies,
inlineStyleLanguage,
stats: !!statsJson,
poll,
// If not explicitly set, default to the Node.js process argument
preserveSymlinks: preserveSymlinks ?? process.execArgv.includes('--preserve-symlinks'),
Expand Down
Expand Up @@ -34,6 +34,7 @@ export function createStylesheetBundleOptions(
assetNames: options.outputNames?.media,
logLevel: 'silent',
minify: options.optimization,
metafile: true,
sourcemap: options.sourcemap,
outdir: options.workspaceRoot,
write: false,
Expand Down Expand Up @@ -140,5 +141,6 @@ export async function bundleComponentStylesheet(
map,
path: outputPath,
resourceFiles,
metafile: result.outputFiles && result.metafile,
};
}

0 comments on commit 839d0cb

Please sign in to comment.