Skip to content

Commit

Permalink
fix(bazel): speed up d.ts bundling by configuring worker
Browse files Browse the repository at this point in the history
Speeds up the `d.ts` bundling by configuring it as a Bazel
persistent worker. Also improve logging for the ng packager
rule to make it easier to spot which actions/bundles take
up significant time.

Type bundling will occur for every entry-point so for machines
with rather limited cores/threads, this will be useful to save
NodeJS boot and resolution time.
  • Loading branch information
devversion committed May 5, 2022
1 parent a020872 commit d01b175
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 15 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -73,6 +73,7 @@
"@bazel/rollup": "5.4.1",
"@bazel/runfiles": "5.4.1",
"@bazel/terser": "5.4.1",
"@bazel/worker": "5.4.1",
"@microsoft/api-extractor": "7.22.2",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.0",
Expand Down
1 change: 1 addition & 0 deletions packages/bazel/package.json
Expand Up @@ -30,6 +30,7 @@
"peerDependencies": {
"@angular/compiler-cli": "0.0.0-PLACEHOLDER",
"@bazel/concatjs": "^5.3.0",
"@bazel/worker": "^5.3.0",
"@rollup/plugin-commonjs": "^21.0.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"rollup": "^2.56.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/bazel/src/ng_package/ng_package.bzl
Expand Up @@ -221,7 +221,7 @@ def _run_rollup(ctx, bundle_name, rollup_config, entry_point, inputs, js_output,
if stamp and ctx.version_file:
other_inputs.append(ctx.version_file)
ctx.actions.run(
progress_message = "ng_package: Rollup %s %s" % (bundle_name, ctx.label),
progress_message = "ng_package: Rollup %s (%s)" % (bundle_name, entry_point.short_path),
mnemonic = "AngularPackageRollup",
inputs = inputs.to_list() + other_inputs,
outputs = [js_output, map_output],
Expand Down
7 changes: 2 additions & 5 deletions packages/bazel/src/types_bundle/BUILD.bazel
Expand Up @@ -10,18 +10,15 @@ ts_library(
"index.ts",
],
deps = [
"@npm//@bazel/worker",
"@npm//@microsoft/api-extractor",
"@npm//@types/node",
],
)

nodejs_binary(
name = "types_bundler",
data = [
":lib",
"@npm//@bazel/concatjs",
"@npm//@microsoft/api-extractor",
],
data = [":lib"],
entry_point = ":index.ts",
# Disable the linker and rely on patched resolution which works better on Windows
# and is less prone to race conditions when targets build concurrently.
Expand Down
7 changes: 7 additions & 0 deletions packages/bazel/src/types_bundle/index.bzl
Expand Up @@ -28,12 +28,19 @@ def bundle_type_declaration(
args.add(license_banner_file.path)
inputs.append(license_banner_file)

# Pass arguments using a flag-file prefixed with `@`. This is
# a requirement for build action arguments in persistent workers.
# https://docs.bazel.build/versions/main/creating-workers.html#work-action-requirements.
args.use_param_file("@%s", use_always = True)
args.set_param_file_format("multiline")

ctx.actions.run(
mnemonic = "BundlingTypes",
inputs = depset(inputs, transitive = [types]),
outputs = [output_file],
executable = ctx.executable._types_bundler_bin,
arguments = [args],
execution_requirements = {"supports-workers": "1"},
progress_message = "Bundling types (%s)" % entry_point.short_path,
)

Expand Down
59 changes: 50 additions & 9 deletions packages/bazel/src/types_bundle/index.ts
Expand Up @@ -9,7 +9,8 @@
/// <reference types="node"/>
/// <reference lib="es2020"/>

import {Extractor, ExtractorConfig, IConfigFile, IExtractorConfigPrepareOptions,} from '@microsoft/api-extractor';
import {runAsWorker, runWorkerLoop} from '@bazel/worker';
import {Extractor, ExtractorConfig, ExtractorMessage, IConfigFile, IExtractorConfigPrepareOptions} from '@microsoft/api-extractor';
import * as fs from 'fs';
import * as path from 'path';

Expand Down Expand Up @@ -55,7 +56,8 @@ export async function runMain(
};

const extractorConfig = ExtractorConfig.prepare(options);
const {succeeded} = Extractor.invoke(extractorConfig);
const {succeeded} =
Extractor.invoke(extractorConfig, {messageCallback: handleApiExtractorMessage});

if (!succeeded) {
throw new Error('Type bundling failed. See error above.');
Expand Down Expand Up @@ -89,12 +91,51 @@ function stripAmdModuleDirectiveComments(content: string): string {
return content.replace(/^\/\/\/ <amd-module name=.*\/>[\r\n]+/gm, '');
}

// Entry point
const [entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath] =
process.argv.slice(2);
/**
* Handles logging messages from API extractor.
*
* Certain info messages should be omitted and other messages should be printed
* to stderr to avoid worker protocol conflicts.
*/
function handleApiExtractorMessage(msg: ExtractorMessage): void {
msg.handled = true;

if (msg.messageId === 'console-compiler-version-notice' || msg.messageId === 'console-preamble') {
return;
}

if (msg.logLevel !== 'verbose' && msg.logLevel !== 'none') {
console.error(msg.text);
}
}

runMain({entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath})
.catch(e => {
console.error(e);
/** Runs one build using the specified build action command line arguments. */
async function runOneBuild(args: string[]): Promise<boolean> {
const [entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath] = args;

try {
await runMain({entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath});
return true;
} catch (e) {
console.error(e);
return false;
}
}

// Entry-point.
const processArgs = process.argv.slice(2);

if (runAsWorker(processArgs)) {
runWorkerLoop(runOneBuild);
} else {
// In non-worker mode we need to manually read the flag file and omit
// the leading `@` that is added as part of the worker requirements.
const flagFile = processArgs[0].substring(1);
const args = fs.readFileSync(flagFile, 'utf8').split('\n');

runOneBuild(args).then(success => {
if (!success) {
process.exitCode = 1;
});
}
});
}

0 comments on commit d01b175

Please sign in to comment.