Skip to content

Commit 994708e

Browse files
authored
Webapp Angular upgrade 15 to 16 (#7056)
## Motivation for features / changes This PR is the first step in a planned major Angular upgrade cycle, where each major version will be delivered in a separate PR, incrementally progressing until the project reaches Angular 20. This specific PR upgrades TensorBoard from Angular 15 to Angular 16, initiating the migration path toward Angular 20+. Keeping the framework and aligned dependencies (NgRx, TypeScript, RxJS, zone.js, etc.) up to date ensures continued compatibility, security support, and maintainability, while preparing the project for future Angular features and ecosystem improvements. ## Technical description of changes Upgrade the TensorBoard web application from Angular 15 to Angular 16 following TensorBoard’s DEVELOPMENT.md guidelines and the official Angular migration guide. ## Detailed steps to verify changes work correctly (as executed by you) - Follow steps to run Tensorboard from clean state https://github.com/tensorflow/tensorboard/blob/master/DEVELOPMENT.md#how-to-develop-tensorboard - Execute docker build - Run with iBazel
1 parent 29f809f commit 994708e

17 files changed

Lines changed: 3227 additions & 2955 deletions

File tree

package.json

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030
"devDependencies": {
3131
"@angular-devkit/build-angular": "^15.2.9",
3232
"@angular/build-tooling": "https://github.com/angular/dev-infra-private-build-tooling-builds.git#fb42478534df7d48ec23a6834fea94a776cb89a0",
33-
"@angular/cli": "^15.2.9",
34-
"@angular/compiler": "15.2.9",
35-
"@angular/compiler-cli": "^15.2.9",
33+
"@angular/cli": "^16.2.0",
34+
"@angular/compiler": "16.2.12",
35+
"@angular/compiler-cli": "^16.2.12",
3636
"@babel/core": "^7.16.12",
3737
"@bazel/concatjs": "5.7.0",
3838
"@bazel/esbuild": "5.7.0",
@@ -65,16 +65,16 @@
6565
"yarn-deduplicate": "^5.0.0"
6666
},
6767
"dependencies": {
68-
"@angular/animations": "^15.2.9",
69-
"@angular/cdk": "^15.2.9",
70-
"@angular/common": "15.2.9",
71-
"@angular/core": "^15.2.9",
72-
"@angular/forms": "^15.2.9",
73-
"@angular/localize": "^15.2.9",
74-
"@angular/material": "^15.2.9",
75-
"@angular/platform-browser": "^15.2.9",
76-
"@angular/platform-browser-dynamic": "^15.2.9",
77-
"@angular/router": "^15.2.9",
68+
"@angular/animations": "^16.2.12",
69+
"@angular/cdk": "^16.2.14",
70+
"@angular/common": "16.2.12",
71+
"@angular/core": "^16.2.12",
72+
"@angular/forms": "^16.2.12",
73+
"@angular/localize": "^16.2.12",
74+
"@angular/material": "^16.2.14",
75+
"@angular/platform-browser": "^16.2.12",
76+
"@angular/platform-browser-dynamic": "^16.2.12",
77+
"@angular/router": "^16.2.12",
7878
"@ngrx/effects": "^15.4.0",
7979
"@ngrx/store": "^15.4.0",
8080
"@polymer/decorators": "^3.0.0",
@@ -131,6 +131,15 @@
131131
"three": "~0.137.0",
132132
"umap-js": "^1.3.2",
133133
"web-animations-js": "^2.3.2",
134-
"zone.js": "^0.12.0"
135-
}
134+
"zone.js": "^0.13.3"
135+
},
136+
"resolutions": {
137+
"@types/d3-brush": "1.1.8",
138+
"@types/d3-axis": "1.0.19",
139+
"@types/d3-transition": "1.3.6",
140+
"@types/d3-zoom": "1.8.7",
141+
"@types/d3-drag": "1.2.8",
142+
"@types/d3-scale-chromatic": "1.5.4"
143+
},
144+
"packageManager": "yarn@1.22.22"
136145
}

patches/@angular+build-tooling+0.0.0-7d103b83a07f132629592fc9918ce17d42a5e382.patch

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
diff --git a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel
2+
index d5a8645..4b57378 100755
3+
--- a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel
4+
+++ b/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/BUILD.bazel
5+
@@ -23,6 +23,7 @@ js_library(
6+
deps = [
7+
"@npm//@babel/core",
8+
"@npm//@babel/helper-annotate-as-pure",
9+
+ "@npm//@babel/helper-split-export-declaration",
10+
],
11+
)
12+
113
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
214
index 57cd2b9..2e5eaf1 100755
315
--- a/node_modules/@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs

patches/@bazel+concatjs+5.7.0.patch

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
diff --git a/node_modules/@bazel/concatjs/internal/common/compilation.bzl b/node_modules/@bazel/concatjs/internal/common/compilation.bzl
2+
index fed787a..377915a 100755
3+
--- a/node_modules/@bazel/concatjs/internal/common/compilation.bzl
4+
+++ b/node_modules/@bazel/concatjs/internal/common/compilation.bzl
5+
@@ -160,25 +160,11 @@ def _outputs(ctx, label, srcs_files = []):
6+
closure_js_file = ctx.actions.declare_file(basename + ".mjs")
7+
closure_js_files.append(closure_js_file)
8+
9+
- # Temporary until all imports of ngfactory/ngsummary files are removed
10+
- # TODO(alexeagle): clean up after Ivy launch
11+
- if getattr(ctx.attr, "use_angular_plugin", False):
12+
- closure_js_files.append(ctx.actions.declare_file(basename + ".ngfactory.mjs"))
13+
- closure_js_files.append(ctx.actions.declare_file(basename + ".ngsummary.mjs"))
14+
-
15+
if not is_dts:
16+
devmode_js_file = ctx.actions.declare_file(basename + ".js")
17+
devmode_js_files.append(devmode_js_file)
18+
transpilation_infos.append(struct(closure = closure_js_file, devmode = devmode_js_file))
19+
declaration_files.append(ctx.actions.declare_file(basename + ".d.ts"))
20+
-
21+
- # Temporary until all imports of ngfactory/ngsummary files are removed
22+
- # TODO(alexeagle): clean up after Ivy launch
23+
- if getattr(ctx.attr, "use_angular_plugin", False):
24+
- devmode_js_files.append(ctx.actions.declare_file(basename + ".ngfactory.js"))
25+
- devmode_js_files.append(ctx.actions.declare_file(basename + ".ngsummary.js"))
26+
- declaration_files.append(ctx.actions.declare_file(basename + ".ngfactory.d.ts"))
27+
- declaration_files.append(ctx.actions.declare_file(basename + ".ngsummary.d.ts"))
28+
return struct(
29+
closure_js = closure_js_files,
30+
devmode_js = devmode_js_files,
131
diff --git a/node_modules/@bazel/concatjs/web_test/karma.conf.js b/node_modules/@bazel/concatjs/web_test/karma.conf.js
232
index 90a03ef..28778c9 100755
333
--- a/node_modules/@bazel/concatjs/web_test/karma.conf.js

patches/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
We use [patch-package](https://www.npmjs.com/package/patch-package) to apply
44
TensorBoard-specific patches to some of our npm/yarn dependencies.
55

6+
After creating or updating a patch, ensure there is no trailing whitespace on
7+
any line (CI runs `./tensorboard/tools/whitespace_hygiene_test.py`). You can
8+
strip it with `sed -i '' 's/[[:space:]]*$//' patches/<patch-file>.patch`.
9+
610
To regenerate @bazel/concatjs patch:
711
* `vi node_modules/@bazel/concatjs/web_test/karma.conf.js`
812
* make edits

tensorboard/defs/defs.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,8 @@ def tf_ng_web_test_suite(name, deps = [], **kwargs):
224224
name = name,
225225
bootstrap =
226226
[
227-
"@npm//:node_modules/zone.js/dist/zone-evergreen.js",
228-
"@npm//:node_modules/zone.js/dist/zone-testing.js",
227+
"@npm//:node_modules/zone.js/bundles/zone.umd.js",
228+
"@npm//:node_modules/zone.js/bundles/zone-testing.umd.js",
229229
"@npm//:node_modules/reflect-metadata/Reflect.js",
230230
],
231231
# The only dependency is the esbuild bundle from spec_bundle().

tensorboard/plugins/mesh/tf_mesh_dashboard/mesh-viewer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ limitations under the License.
1818
*/
1919

2020
import * as THREE from 'three';
21-
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
21+
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
2222

2323
interface LayerConfig {
2424
showBoundingBox?: boolean;

tensorboard/plugins/projector/vz_projector/scatterPlot.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
1515
import * as THREE from 'three';
16-
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
16+
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js';
1717
import {ProjectorEventContext} from './projectorEventContext';
1818
import {CameraType, LabelRenderParams, RenderContext} from './renderContext';
1919
import {

tensorboard/webapp/app_routing/views/router_outlet_component.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ limitations under the License.
1515
import {
1616
ChangeDetectionStrategy,
1717
Component,
18-
ComponentFactoryResolver,
1918
Input,
2019
OnChanges,
2120
SimpleChanges,
21+
Type,
2222
ViewChild,
2323
ViewContainerRef,
2424
} from '@angular/core';
@@ -33,22 +33,16 @@ export class RouterOutletComponent implements OnChanges {
3333
@ViewChild('routeContainer', {static: true, read: ViewContainerRef})
3434
private readonly routeContainer!: ViewContainerRef;
3535

36-
@Input() activeNgComponent!: unknown | null;
37-
38-
constructor(
39-
private readonly componentFactoryResolver: ComponentFactoryResolver
40-
) {}
36+
@Input() activeNgComponent!: Type<Component> | null;
4137

4238
ngOnChanges(changes: SimpleChanges) {
4339
const activeComponentChange = changes['activeNgComponent'];
4440
if (activeComponentChange) {
4541
this.routeContainer.clear();
46-
if (activeComponentChange.currentValue) {
47-
const componentFactory =
48-
this.componentFactoryResolver.resolveComponentFactory(
49-
activeComponentChange.currentValue
50-
);
51-
this.routeContainer.createComponent(componentFactory);
42+
const componentType =
43+
activeComponentChange.currentValue as Type<Component> | null;
44+
if (componentType) {
45+
this.routeContainer.createComponent(componentType);
5246
}
5347
}
5448
}

tensorboard/webapp/bootstrap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ limitations under the License.
1717
// https://angular.io/guide/migration-localize
1818
import '@angular/localize/init';
1919
import {platformBrowser} from '@angular/platform-browser';
20-
import 'zone.js/dist/zone.js'; // Angular runtime dep
20+
import 'zone.js'; // Angular runtime dep
2121
import {AppModule} from './app_module';
2222

2323
// Bootstrap needs to happen after body is ready but we cannot reliably

tensorboard/webapp/customization/customizable_component.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
See the License for the specific language governing permissions and
1313
limitations under the License.
1414
==============================================================================*/
15-
import {
16-
Component,
17-
ComponentFactoryResolver,
18-
Input,
19-
OnInit,
20-
Type,
21-
ViewContainerRef,
22-
} from '@angular/core';
15+
import {Component, Input, OnInit, Type, ViewContainerRef} from '@angular/core';
2316

2417
/**
2518
* A Component that defines a customization point. Ideal for use for small
@@ -70,7 +63,7 @@ import {
7063
* declarations: [MyCustomButtonComponent],
7164
* providers: [{
7265
* provide: CustomizableButton,
73-
* useClass: MyCustomButtonComponent,
66+
* useValue: MyCustomButtonComponent,
7467
* }]
7568
* })
7669
*/
@@ -86,18 +79,11 @@ import {
8679
export class CustomizableComponent implements OnInit {
8780
@Input() customizableComponent!: Type<Component> | undefined;
8881

89-
constructor(
90-
private readonly viewContainerRef: ViewContainerRef,
91-
private readonly componentFactoryResolver: ComponentFactoryResolver
92-
) {}
82+
constructor(private readonly viewContainerRef: ViewContainerRef) {}
9383

9484
ngOnInit() {
9585
if (this.customizableComponent) {
96-
const componentFactory =
97-
this.componentFactoryResolver.resolveComponentFactory(
98-
this.customizableComponent.constructor as Type<unknown>
99-
);
100-
this.viewContainerRef.createComponent(componentFactory);
86+
this.viewContainerRef.createComponent(this.customizableComponent);
10187
}
10288
}
10389
}

0 commit comments

Comments
 (0)