Skip to content

Commit 482d183

Browse files
devversionzarend
authored andcommitted
build: update e2e-app and dev-app to use esbuild
Previously, the dev-app relied on SystemJS for resolving all files. This required a lot of configuration and was very cumbersome to maintain. This commit switches both serve-targets to use ESBuild instead. ESbuild will resolve all the dependencies for us at build time; removing the manual configuration work, and it will also allow us to incorporate the linked framework ESM bundles, so that the apps would not need the Angular compiler at runtime (for JIT). Generally it seems that ESBuild is extremely fast so that it makes up for the runtime resolution through SystemJS; and manual configuration work. It also makes our tooling more modern and easier to adopt to new changes (e.g. if we'd add a dependency like `date-fns` there is no special tooling needed).
1 parent 5a6a81d commit 482d183

20 files changed

+643
-426
lines changed

src/components-examples/BUILD.bazel

+1-62
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,10 @@
11
load("//tools:defaults.bzl", "ng_module", "ng_package")
22
load("//tools/highlight-files:index.bzl", "highlight_files")
33
load("//tools/package-docs-content:index.bzl", "package_docs_content")
4+
load(":config.bzl", "ALL_EXAMPLES")
45

56
package(default_visibility = ["//visibility:public"])
67

7-
ALL_EXAMPLES = [
8-
# TODO(devversion): try to have for each entry-point a bazel package so that
9-
# we can automate this using the "package.bzl" variables. Currently generated
10-
# with "bazel query 'kind("ng_module", //src/components-examples/...:*)' --output="label"
11-
"//src/components-examples/material/tree",
12-
"//src/components-examples/material/tooltip",
13-
"//src/components-examples/material/toolbar",
14-
"//src/components-examples/material/tabs",
15-
"//src/components-examples/material/table",
16-
"//src/components-examples/material/stepper",
17-
"//src/components-examples/material/sort",
18-
"//src/components-examples/material/snack-bar",
19-
"//src/components-examples/material/slider",
20-
"//src/components-examples/material/slide-toggle",
21-
"//src/components-examples/material/sidenav",
22-
"//src/components-examples/material/select",
23-
"//src/components-examples/material/radio",
24-
"//src/components-examples/material/progress-spinner",
25-
"//src/components-examples/material/progress-bar",
26-
"//src/components-examples/material/paginator",
27-
"//src/components-examples/material/menu",
28-
"//src/components-examples/material/list",
29-
"//src/components-examples/material/input",
30-
"//src/components-examples/material/icon",
31-
"//src/components-examples/material/grid-list",
32-
"//src/components-examples/material/form-field",
33-
"//src/components-examples/material/expansion",
34-
"//src/components-examples/material/divider",
35-
"//src/components-examples/material/dialog",
36-
"//src/components-examples/material/datepicker",
37-
"//src/components-examples/material/core",
38-
"//src/components-examples/material/chips",
39-
"//src/components-examples/material/checkbox",
40-
"//src/components-examples/material/card",
41-
"//src/components-examples/material/button-toggle",
42-
"//src/components-examples/material/button",
43-
"//src/components-examples/material/bottom-sheet",
44-
"//src/components-examples/material/badge",
45-
"//src/components-examples/material/autocomplete",
46-
"//src/components-examples/material-experimental/column-resize",
47-
"//src/components-examples/material-experimental/popover-edit",
48-
"//src/components-examples/material-experimental/mdc-card",
49-
"//src/components-examples/material-experimental/mdc-form-field",
50-
"//src/components-examples/material-experimental/selection",
51-
"//src/components-examples/cdk/tree",
52-
"//src/components-examples/cdk/text-field",
53-
"//src/components-examples/cdk/table",
54-
"//src/components-examples/cdk/stepper",
55-
"//src/components-examples/cdk/scrolling",
56-
"//src/components-examples/cdk/portal",
57-
"//src/components-examples/cdk/accordion",
58-
"//src/components-examples/cdk/platform",
59-
"//src/components-examples/cdk/drag-drop",
60-
"//src/components-examples/cdk/clipboard",
61-
"//src/components-examples/cdk/a11y",
62-
"//src/components-examples/cdk/layout",
63-
"//src/components-examples/cdk/overlay",
64-
"//src/components-examples/cdk-experimental/menu",
65-
"//src/components-examples/cdk-experimental/popover-edit",
66-
"//src/components-examples/cdk-experimental/selection",
67-
]
68-
698
ng_module(
709
name = "components-examples",
7110
srcs = glob(["*.ts"]) + [":example-module.ts"],

src/components-examples/config.bzl

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
ALL_EXAMPLES = [
2+
# TODO(devversion): try to have for each entry-point a bazel package so that
3+
# we can automate this using the "package.bzl" variables. Currently generated
4+
# with "bazel query 'kind("ng_module", //src/components-examples/...:*)' --output="label"
5+
"//src/components-examples/material/tree",
6+
"//src/components-examples/material/tooltip",
7+
"//src/components-examples/material/toolbar",
8+
"//src/components-examples/material/tabs",
9+
"//src/components-examples/material/table",
10+
"//src/components-examples/material/stepper",
11+
"//src/components-examples/material/sort",
12+
"//src/components-examples/material/snack-bar",
13+
"//src/components-examples/material/slider",
14+
"//src/components-examples/material/slide-toggle",
15+
"//src/components-examples/material/sidenav",
16+
"//src/components-examples/material/select",
17+
"//src/components-examples/material/radio",
18+
"//src/components-examples/material/progress-spinner",
19+
"//src/components-examples/material/progress-bar",
20+
"//src/components-examples/material/paginator",
21+
"//src/components-examples/material/menu",
22+
"//src/components-examples/material/list",
23+
"//src/components-examples/material/input",
24+
"//src/components-examples/material/icon",
25+
"//src/components-examples/material/grid-list",
26+
"//src/components-examples/material/form-field",
27+
"//src/components-examples/material/expansion",
28+
"//src/components-examples/material/divider",
29+
"//src/components-examples/material/dialog",
30+
"//src/components-examples/material/datepicker",
31+
"//src/components-examples/material/core",
32+
"//src/components-examples/material/chips",
33+
"//src/components-examples/material/checkbox",
34+
"//src/components-examples/material/card",
35+
"//src/components-examples/material/button-toggle",
36+
"//src/components-examples/material/button",
37+
"//src/components-examples/material/bottom-sheet",
38+
"//src/components-examples/material/badge",
39+
"//src/components-examples/material/autocomplete",
40+
"//src/components-examples/material-experimental/column-resize",
41+
"//src/components-examples/material-experimental/popover-edit",
42+
"//src/components-examples/material-experimental/mdc-card",
43+
"//src/components-examples/material-experimental/mdc-form-field",
44+
"//src/components-examples/material-experimental/selection",
45+
"//src/components-examples/cdk/tree",
46+
"//src/components-examples/cdk/text-field",
47+
"//src/components-examples/cdk/table",
48+
"//src/components-examples/cdk/stepper",
49+
"//src/components-examples/cdk/scrolling",
50+
"//src/components-examples/cdk/portal",
51+
"//src/components-examples/cdk/accordion",
52+
"//src/components-examples/cdk/platform",
53+
"//src/components-examples/cdk/drag-drop",
54+
"//src/components-examples/cdk/clipboard",
55+
"//src/components-examples/cdk/a11y",
56+
"//src/components-examples/cdk/layout",
57+
"//src/components-examples/cdk/overlay",
58+
"//src/components-examples/cdk-experimental/menu",
59+
"//src/components-examples/cdk-experimental/popover-edit",
60+
"//src/components-examples/cdk-experimental/selection",
61+
]
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
1-
import {ComponentFactory, Injector, NgModuleFactory, Type} from '@angular/core';
1+
import {Injector, Type, createNgModuleRef} from '@angular/core';
22
import {EXAMPLE_COMPONENTS} from '../example-module';
33

4-
/** Asynchronously loads the specified example and returns its component factory. */
5-
export async function loadExampleFactory(name: string, injector: Injector)
6-
: Promise<ComponentFactory<any>> {
4+
/**
5+
* Asynchronously loads the specified example and returns its component and
6+
* an injector instantiated from the containing example module.
7+
*
8+
* This is used in the `dev-app` and `e2e-app` and assumes ESBuild having created
9+
* entry-points for the example modules under the `<host>/bundles/` URL.
10+
*/
11+
export async function loadExample(name: string, injector: Injector)
12+
: Promise<{component: Type<any>, injector: Injector}> {
713
const {componentName, module} = EXAMPLE_COMPONENTS[name];
8-
// TODO(devversion): remove the NgFactory import when the `--config=view-engine` switch is gone.
9-
// Note: This line will be replaced by the e2e-app when a rollup bundle is composed. Rollup needs
10-
// to run for the partial compilation in order to process sources with the Angular linker.
11-
const {moduleExports, moduleFactoryExports} = await loadModuleWithFactory(
12-
`@angular/components-examples/${module.importSpecifier}`);
13-
const moduleFactory: NgModuleFactory<any> = moduleFactoryExports[`${module.name}NgFactory`];
14+
const moduleExports = await import(
15+
`/bundles/components-examples/${module.importSpecifier}/index.js`);
16+
const moduleType: Type<any> = moduleExports[module.name];
1417
const componentType: Type<any> = moduleExports[componentName];
15-
return moduleFactory.create(injector)
16-
.componentFactoryResolver.resolveComponentFactory(componentType);
17-
}
18+
const moduleRef = createNgModuleRef(moduleType, injector);
1819

19-
/** Loads the module and factory file for the given module. */
20-
async function loadModuleWithFactory(moduleName: string) {
21-
const [moduleFactoryExports, moduleExports] = await Promise.all([
22-
import(moduleName + '/index.ngfactory'),
23-
import(moduleName)
24-
]);
25-
return {moduleFactoryExports, moduleExports};
20+
return {
21+
component: componentType,
22+
injector: moduleRef.injector,
23+
};
2624
}

src/dev-app/BUILD.bazel

+29-30
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
load("@npm//@angular/dev-infra-private/bazel:extract_js_module_output.bzl", "extract_js_module_output")
21
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_web")
3-
load("//:packages.bzl", "MDC_PACKAGE_UMD_BUNDLES")
4-
load("//tools:create-system-config.bzl", "create_system_config")
52
load("//tools:defaults.bzl", "ng_module", "sass_binary")
63
load("//tools/dev-server:index.bzl", "dev_server")
4+
load("//tools/esbuild:index.bzl", "esbuild", "esbuild_config")
5+
load("//src/components-examples:config.bzl", "ALL_EXAMPLES")
6+
load("//tools/angular:index.bzl", "LINKER_PROCESSED_FW_PACKAGES")
77

88
package(default_visibility = ["//visibility:public"])
99

@@ -13,6 +13,7 @@ ng_module(
1313
"dev-app.ts",
1414
"main.ts",
1515
"main-module.ts",
16+
"routes.ts",
1617
],
1718
deps = [
1819
"//src/cdk/bidi",
@@ -99,11 +100,33 @@ ng_module(
99100
"//src/dev-app/virtual-scroll",
100101
"//src/dev-app/youtube-player",
101102
"//src/material/core",
103+
"@npm//@angular/compiler",
102104
"@npm//@angular/localize",
103105
"@npm//@angular/router",
104106
],
105107
)
106108

109+
esbuild_config(
110+
name = "esbuild_config",
111+
config_file = "esbuild.config.mjs",
112+
)
113+
114+
esbuild(
115+
name = "bundles",
116+
config = ":esbuild_config",
117+
entry_points = [":main.ts"] + ["%s:index.ts" % e for e in ALL_EXAMPLES],
118+
platform = "browser",
119+
splitting = True,
120+
# We cannot use `ES2017` or higher as that would result in `async/await` not being downleveled.
121+
# ZoneJS needs to be able to intercept these as otherwise change detection would not work properly.
122+
target = "es2016",
123+
# Note: We add all linker-processed FW packages as dependencies here so that ESBuild will
124+
# map all framework packages to their linker-processed bundles from `tools/angular`.
125+
deps = LINKER_PROCESSED_FW_PACKAGES + [
126+
":dev-app",
127+
],
128+
)
129+
107130
sass_binary(
108131
name = "theme",
109132
src = "theme.scss",
@@ -117,11 +140,6 @@ sass_binary(
117140
],
118141
)
119142

120-
create_system_config(
121-
name = "system-config",
122-
output_name = "system-config.js",
123-
)
124-
125143
# Variables that are going to be inlined into the dev app index.html.
126144
filegroup(
127145
name = "variables",
@@ -138,18 +156,14 @@ filegroup(
138156
srcs = [
139157
"favicon.ico",
140158
"index.html",
141-
":system-config",
142159
":theme",
143160
":variables",
144161
"//src/dev-app/icon:icon_demo_assets",
145-
"//tools:system-rxjs-operators.js",
146162
"@npm//:node_modules/core-js-bundle/index.js",
147163
"@npm//:node_modules/moment/min/moment-with-locales.min.js",
148164
"@npm//:node_modules/rxjs/bundles/rxjs.umd.min.js",
149-
"@npm//:node_modules/systemjs/dist/system.js",
150-
"@npm//:node_modules/tslib/tslib.js",
151165
"@npm//:node_modules/zone.js/dist/zone.js",
152-
] + MDC_PACKAGE_UMD_BUNDLES.values(),
166+
],
153167
)
154168

155169
dev_server(
@@ -163,31 +177,16 @@ dev_server(
163177
],
164178
tags = ["manual"],
165179
deps = [
166-
":dev-app",
180+
":bundles",
167181
],
168182
)
169183

170-
# Collects all ES5 JavaScript files which are required to serve the dev-app. By default,
171-
# ts_library and ng_module targets only expose the type definition files as outputs.
172-
extract_js_module_output(
173-
name = "dev_app_js_sources",
174-
include_declarations = False,
175-
include_default_files = True,
176-
# `JSModuleInfo` resolves to the ES5 sources from TypeScript targets. See:
177-
# https://github.com/bazelbuild/rules_nodejs/blob/stable/packages/typescript/internal/build_defs.bzl#L334-L337
178-
# Note: We cannot use the named JS module provider because not all dependencies are
179-
# necessarily captured as named module. See: https://github.com/angular/components/commit/94289397cac94ca86a292b2cd64945df52bbb7fb.
180-
provider = "JSModuleInfo",
181-
tags = ["manual"],
182-
deps = [":dev-app"],
183-
)
184-
185184
# Target that builds a static web package of the dev-app. The web package can be
186185
# deployed on static hosting services (such as firebase).
187186
pkg_web(
188187
name = "web_package",
189188
srcs = [
190-
":dev_app_js_sources",
189+
":bundles",
191190
":dev_app_static_files",
192191
],
193192
additional_root_paths = [

0 commit comments

Comments
 (0)