Skip to content

Commit a6b6590

Browse files
devversionAndrewKushnir
authored andcommitted
fix(bazel): speed up d.ts bundling by configuring worker (#45900)
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. PR Close #45900
1 parent b7fca64 commit a6b6590

File tree

6 files changed

+62
-15
lines changed

6 files changed

+62
-15
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"@bazel/rollup": "5.4.1",
7474
"@bazel/runfiles": "5.4.1",
7575
"@bazel/terser": "5.4.1",
76+
"@bazel/worker": "5.4.1",
7677
"@microsoft/api-extractor": "7.22.2",
7778
"@rollup/plugin-babel": "^5.3.0",
7879
"@rollup/plugin-commonjs": "^21.0.0",

packages/bazel/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"peerDependencies": {
3131
"@angular/compiler-cli": "0.0.0-PLACEHOLDER",
3232
"@bazel/concatjs": "^5.3.0",
33+
"@bazel/worker": "^5.3.0",
3334
"@rollup/plugin-commonjs": "^21.0.0",
3435
"@rollup/plugin-node-resolve": "^13.0.4",
3536
"rollup": "^2.56.3",

packages/bazel/src/ng_package/ng_package.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def _run_rollup(ctx, bundle_name, rollup_config, entry_point, inputs, js_output,
221221
if stamp and ctx.version_file:
222222
other_inputs.append(ctx.version_file)
223223
ctx.actions.run(
224-
progress_message = "ng_package: Rollup %s %s" % (bundle_name, ctx.label),
224+
progress_message = "ng_package: Rollup %s (%s)" % (bundle_name, entry_point.short_path),
225225
mnemonic = "AngularPackageRollup",
226226
inputs = inputs.to_list() + other_inputs,
227227
outputs = [js_output, map_output],

packages/bazel/src/types_bundle/BUILD.bazel

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,15 @@ ts_library(
1010
"index.ts",
1111
],
1212
deps = [
13+
"@npm//@bazel/worker",
1314
"@npm//@microsoft/api-extractor",
1415
"@npm//@types/node",
1516
],
1617
)
1718

1819
nodejs_binary(
1920
name = "types_bundler",
20-
data = [
21-
":lib",
22-
"@npm//@bazel/concatjs",
23-
"@npm//@microsoft/api-extractor",
24-
],
21+
data = [":lib"],
2522
entry_point = ":index.ts",
2623
# Disable the linker and rely on patched resolution which works better on Windows
2724
# and is less prone to race conditions when targets build concurrently.

packages/bazel/src/types_bundle/index.bzl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,19 @@ def bundle_type_declaration(
2828
args.add(license_banner_file.path)
2929
inputs.append(license_banner_file)
3030

31+
# Pass arguments using a flag-file prefixed with `@`. This is
32+
# a requirement for build action arguments in persistent workers.
33+
# https://docs.bazel.build/versions/main/creating-workers.html#work-action-requirements.
34+
args.use_param_file("@%s", use_always = True)
35+
args.set_param_file_format("multiline")
36+
3137
ctx.actions.run(
3238
mnemonic = "BundlingTypes",
3339
inputs = depset(inputs, transitive = [types]),
3440
outputs = [output_file],
3541
executable = ctx.executable._types_bundler_bin,
3642
arguments = [args],
43+
execution_requirements = {"supports-workers": "1"},
3744
progress_message = "Bundling types (%s)" % entry_point.short_path,
3845
)
3946

packages/bazel/src/types_bundle/index.ts

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
/// <reference types="node"/>
1010
/// <reference lib="es2020"/>
1111

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

@@ -55,7 +56,8 @@ export async function runMain(
5556
};
5657

5758
const extractorConfig = ExtractorConfig.prepare(options);
58-
const {succeeded} = Extractor.invoke(extractorConfig);
59+
const {succeeded} =
60+
Extractor.invoke(extractorConfig, {messageCallback: handleApiExtractorMessage});
5961

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

92-
// Entry point
93-
const [entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath] =
94-
process.argv.slice(2);
94+
/**
95+
* Handles logging messages from API extractor.
96+
*
97+
* Certain info messages should be omitted and other messages should be printed
98+
* to stderr to avoid worker protocol conflicts.
99+
*/
100+
function handleApiExtractorMessage(msg: ExtractorMessage): void {
101+
msg.handled = true;
102+
103+
if (msg.messageId === 'console-compiler-version-notice' || msg.messageId === 'console-preamble') {
104+
return;
105+
}
106+
107+
if (msg.logLevel !== 'verbose' && msg.logLevel !== 'none') {
108+
console.error(msg.text);
109+
}
110+
}
95111

96-
runMain({entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath})
97-
.catch(e => {
98-
console.error(e);
112+
/** Runs one build using the specified build action command line arguments. */
113+
async function runOneBuild(args: string[]): Promise<boolean> {
114+
const [entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath] = args;
115+
116+
try {
117+
await runMain({entryPointExecpath, outputExecpath, packageJsonExecpath, licenseBannerExecpath});
118+
return true;
119+
} catch (e) {
120+
console.error(e);
121+
return false;
122+
}
123+
}
124+
125+
// Entry-point.
126+
const processArgs = process.argv.slice(2);
127+
128+
if (runAsWorker(processArgs)) {
129+
runWorkerLoop(runOneBuild);
130+
} else {
131+
// In non-worker mode we need to manually read the flag file and omit
132+
// the leading `@` that is added as part of the worker requirements.
133+
const flagFile = processArgs[0].substring(1);
134+
const args = fs.readFileSync(flagFile, 'utf8').split('\n');
135+
136+
runOneBuild(args).then(success => {
137+
if (!success) {
99138
process.exitCode = 1;
100-
});
139+
}
140+
});
141+
}

0 commit comments

Comments
 (0)