Skip to content

Commit 47c1b57

Browse files
authored
Migrate to Angular's app_bundle for bundling. (#6049)
The upcoming upgrade to Angular 13+ introduces a number of bundling-related problems for our tests and applications. Angular has developed some internal tooling to help resolve these problems. This change uses Angular's internal app_bundle() macro to allow us to continue to bundle Angular13+-compatible apps. Note: app_bundle() is Angular-internal and not supported for external use. We use it at our own risk. Googlers, see the following documents for background and justification: http://go/angular-bazel-problems, http://go/tb-oss-bundling. Note: We migrated our tests to use the similar spec_bundle() in #6036. Our usage of app_bundle() is largely guided/inspired by the usage in the angular/components repo. This is the version at HEAD as of early November: https://github.com/angular/components/blob/871f8f231a7a86a7a0778e345f4d517109c9a357/tools/defaults.bzl We will now have two bundling targets: tf_js_binary(), which remains unchanged; and tf_ng_prod_js_binary(), which is new and delegates to app_bundle(). tf_ng_prod_js_binary() is, in practice, only used for one bundle: The production Angular bundle at //tensorboard/webapp:tb_webapp_binary. All other bundles, including our dev Angular bundle, continue to use tf_js_binary(). Googlers, see detailed reasoning in http://go/tb-oss-bundling. Highlights. 1. Run the following commands to install additional Angular build tooling and terser and then clean the environment: * `yarn add @angular-devkit/[email protected] @bazel/[email protected] --dev` * `yarn run yarn-deduplicate` * `rm -rf node_modules; bazel clean --expunge; yarn;` 2. Patch the Angular build tooling to suit our code base: * Patch the esbuild config to point to old paths for tools in @angular/compiler-cli. When we upgrade @angular/compiler-cli to Angular 13+ then we will be able to delete this portion of the patch. * Patch some of the babel-based optimization code to remove one particular plugin that is too aggressive in removing symbols. It is incompatible with the TensorBoard code base. 3. Add tf_ng_prod_js_binary, which delegates to app_bundle(), and use it for //tensorboard/webapp:tb_webapp_binary. Impact on "//tensorboard" build: * "//tensorboard/webapp:tb_webapp_binary" bundle size: * Before: 5,440,612 bytes * After: 4,790,003 * "//tensorboard/webapp:tb_webapp_binary" bundle time: * Before: 1 or 2 seconds. * After: ~20 seconds. * This is an ok tradeoff since we continue to encourage engineers to use the faster "//tensorboard:dev" and its dev bundle for local development. Impact on "//tensorboard:dev" target: * No impact on either bundle size or bundle time since we continue to use tf_js_binary(). It remains big but fast. * Note that when we update to Angular 13 we will have to change "//tensorboard:dev" to use Angular JIT compilation. Initial observations show that the JIT compilation does not meaningfully slow down app load or interaction times.
1 parent ed5e9d0 commit 47c1b57

File tree

6 files changed

+1581
-152
lines changed

6 files changed

+1581
-152
lines changed

WORKSPACE

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ load("@build_bazel_rules_nodejs//:index.bzl", "yarn_install")
7979

8080
yarn_install(
8181
name = "npm",
82-
data = ["//patches:@bazel+concatjs+5.7.0.patch"],
82+
data = [
83+
"//patches:@angular+build-tooling+0.0.0-7d103b83a07f132629592fc9918ce17d42a5e382.patch",
84+
"//patches:@bazel+concatjs+5.7.0.patch",
85+
],
8386
# "Some rules only work by referencing labels nested inside npm packages
8487
# and therefore require turning off exports_directories_only."
8588
# This includes "ts_library".

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
},
2929
"homepage": "https://github.com/tensorflow/tensorboard#readme",
3030
"devDependencies": {
31+
"@angular-devkit/build-angular": "14.0.0-next.3",
3132
"@angular/build-tooling": "https://github.com/angular/dev-infra-private-build-tooling-builds.git#fb42478534df7d48ec23a6834fea94a776cb89a0",
3233
"@angular/cli": "^12.2.0",
3334
"@angular/compiler": "^12.2.0",
@@ -37,6 +38,7 @@
3738
"@bazel/esbuild": "5.7.0",
3839
"@bazel/ibazel": "^0.15.9",
3940
"@bazel/jasmine": "5.7.0",
41+
"@bazel/terser": "5.7.0",
4042
"@bazel/typescript": "5.7.0",
4143
"@types/d3": "5.7.2",
4244
"@types/jasmine": "^3.8.2",
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
diff --git a/node_modules/@angular/build-tooling/bazel/app-bundling/esbuild.config-tmpl.mjs b/node_modules/@angular/build-tooling/bazel/app-bundling/esbuild.config-tmpl.mjs
2+
index 618bbc5..05a112f 100755
3+
--- a/node_modules/@angular/build-tooling/bazel/app-bundling/esbuild.config-tmpl.mjs
4+
+++ b/node_modules/@angular/build-tooling/bazel/app-bundling/esbuild.config-tmpl.mjs
5+
@@ -9,9 +9,18 @@
6+
import * as path from 'path';
7+
8+
import {createEsbuildAngularOptimizePlugin} from '@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs';
9+
-import {createEs2015LinkerPlugin} from '@angular/compiler-cli/linker/babel';
10+
-import {ConsoleLogger, NodeJSFileSystem, LogLevel} from '@angular/compiler-cli';
11+
-import {GLOBAL_DEFS_FOR_TERSER_WITH_AOT} from '@angular/compiler-cli/private/tooling';
12+
+// For TensorBoard: Patch the esbuild config template so that imports are
13+
+// grabbed from the correct places. This is just the consequence of some
14+
+// skew using pre-13.X @angular/compiler-cli binaries. This should be resolved
15+
+// once we upgrade to Angular 13+.
16+
+//import {createEs2015LinkerPlugin} from '@angular/compiler-cli/linker/babel';
17+
+import {createEs2015LinkerPlugin} from '@angular/compiler-cli/linker/babel/index.js';
18+
+//import {ConsoleLogger, NodeJSFileSystem, LogLevel} from '@angular/compiler-cli';
19+
+import {NodeJSFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.js';
20+
+import {LogLevel} from '@angular/compiler-cli/src/ngtsc/logging/index.js';
21+
+import {ConsoleLogger} from '@angular/compiler-cli/src/ngtsc/logging/src/console_logger.js';
22+
+//import {GLOBAL_DEFS_FOR_TERSER_WITH_AOT} from '@angular/compiler-cli/private/tooling';
23+
+import {GLOBAL_DEFS_FOR_TERSER_WITH_AOT} from '@angular/compiler-cli/src/tooling.js';
24+
25+
/** Root path pointing to the app bundle source entry-point file. */
26+
const entryPointSourceRootPath = path.normalize(`TMPL_ENTRY_POINT_ROOTPATH`);
27+
diff --git a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs
28+
index 57cd2b9..2e5eaf1 100755
29+
--- a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs
30+
+++ b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs
31+
@@ -43,9 +43,12 @@ export function createEsbuildAngularOptimizePlugin(
32+
33+
// If the current file is denoted as explicit side effect free, add the pure
34+
// top-level functions optimization plugin for this file.
35+
- if (isSideEffectFreeFn !== null && isSideEffectFreeFn(args.path)) {
36+
- plugins.push(pureToplevelFunctionsPlugin);
37+
- }
38+
+ // For TensorBoard: This plugin aggressively culls symbols in a way that
39+
+ // is incompatible with TensorBoard source. Remove it. The binary is
40+
+ // bigger than it otherwise could be but the bundle also happens faster.
41+
+ //if (isSideEffectFreeFn !== null && isSideEffectFreeFn(args.path)) {
42+
+ // plugins.push(pureToplevelFunctionsPlugin);
43+
+ //}
44+
45+
const {code} = await babel.transformAsync(content, {
46+
filename: filePath,

tensorboard/defs/defs.bzl

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
1717
load("@io_bazel_rules_sass//:defs.bzl", "npm_sass_library", "sass_binary", "sass_library")
18+
load("@npm//@angular/build-tooling/bazel/app-bundling:index.bzl", "app_bundle")
1819
load("@npm//@angular/build-tooling/bazel/spec-bundling:index.bzl", "spec_bundle")
1920
load("@npm//@angular/build-tooling/bazel:extract_js_module_output.bzl", "extract_js_module_output")
2021
load("@npm//@bazel/concatjs:index.bzl", "karma_web_test_suite", "ts_library")
@@ -33,7 +34,13 @@ def tf_js_binary(
3334
dev_mode_only = False,
3435
includes_polymer = False,
3536
**kwargs):
36-
"""Rules for creating a JavaScript bundle.
37+
"""Rule for creating a JavaScript bundle.
38+
39+
This uses esbuild() directly and is generally used for any bundle that is
40+
non-Angular or non-Prod. It is faster than tf_ng_prod_js_binary.
41+
42+
Angular apps that use this rule will have to be run with the Angular JIT
43+
compiler as this rule does not support Angular AOT compilation.
3744
3845
Args:
3946
name: Name of the target.
@@ -84,6 +91,43 @@ def tf_js_binary(
8491
**kwargs
8592
)
8693

94+
95+
def tf_ng_prod_js_binary(
96+
name,
97+
compile,
98+
**kwargs):
99+
"""Rule for creating a prod-optimized JavaScript bundle for an Angular app.
100+
101+
This uses the Angular team's internal toolchain for creating these bundles:
102+
app_bundle(). This toolchain is not officially supported. We use it at our
103+
own risk.
104+
105+
The bundles allow for Angular AOT compilation and are further optimized to
106+
reduce size. However, the bundle times are significantly slower than those
107+
for tf_js_binary().
108+
109+
Args:
110+
name: Name of the target.
111+
compile: Whether to compile when bundling. Only used internally.
112+
**kwargs: Other keyword arguments to app_bundle() and esbuild(). Typically
113+
used for entry_point and deps. Please refer to
114+
https://esbuild.github.io/api/ for more details.
115+
"""
116+
117+
app_bundle_name = '%s_app_bundle' % name
118+
app_bundle(
119+
name = app_bundle_name,
120+
**kwargs
121+
)
122+
123+
# app_bundle() generates several outputs. We copy the one that has gone
124+
# through a terser pass to be the output of this rule.
125+
copy_file(
126+
name = name,
127+
src = '%s.min.js' % app_bundle_name,
128+
out = '%s.js' % name,
129+
)
130+
87131
def tf_ts_config(**kwargs):
88132
"""TensorBoard wrapper for the rule for a TypeScript configuration."""
89133

@@ -137,9 +181,9 @@ def tf_ts_library(srcs = [], strict_checks = True, **kwargs):
137181
def tf_ng_web_test_suite(name, deps = [], **kwargs):
138182
"""TensorBoard wrapper for the rule for a Karma web test suite.
139183
140-
We use the Angular team's internal toolchain for bundling Angular-compatible
141-
tests: extract_js_module_output() and spec_bundle(). This toolchain is not
142-
officially supported and is subject to change or deletion.
184+
This uses the Angular team's internal toolchain for bundling
185+
Angular-compatible tests: extract_js_module_output() and spec_bundle().
186+
This toolchain is not officially supported. We use it at our own risk.
143187
"""
144188

145189
# Call extract_js_module_output() to prepare proper input for spec_bundle()

tensorboard/webapp/BUILD

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("//tensorboard/defs:defs.bzl", "tf_external_sass_libray", "tf_js_binary", "tf_ng_module", "tf_ng_web_test_suite", "tf_sass_binary", "tf_svg_bundle", "tf_ts_library")
1+
load("//tensorboard/defs:defs.bzl", "tf_external_sass_libray", "tf_ng_module", "tf_ng_prod_js_binary", "tf_ng_web_test_suite", "tf_sass_binary", "tf_svg_bundle", "tf_ts_library")
22
load("//tensorboard/defs:js.bzl", "tf_resource_digest_suffixer")
33
load("//tensorboard/defs:web.bzl", "tb_combine_html", "tf_web_library")
44

@@ -173,7 +173,7 @@ tf_ng_module(
173173
)
174174

175175
# Compile the prepared Angular app to a JS binary.
176-
tf_js_binary(
176+
tf_ng_prod_js_binary(
177177
name = "tb_webapp_binary",
178178
compile = 1,
179179
entry_point = "main_prod.ts",

0 commit comments

Comments
 (0)