From 28137a48cd079936ee8c71aba2fc030d87ac80d4 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 21 Oct 2021 22:07:22 +0200 Subject: [PATCH 1/4] test: remove unnecessary boostrap module calls in size tests --- integration/size-test/material-experimental/mdc-chips/basic.ts | 3 --- integration/size-test/material/chips/basic.ts | 3 --- 2 files changed, 6 deletions(-) diff --git a/integration/size-test/material-experimental/mdc-chips/basic.ts b/integration/size-test/material-experimental/mdc-chips/basic.ts index bf44c255ee35..53c77cbb5d60 100644 --- a/integration/size-test/material-experimental/mdc-chips/basic.ts +++ b/integration/size-test/material-experimental/mdc-chips/basic.ts @@ -1,5 +1,4 @@ import {Component, NgModule} from '@angular/core'; -import {platformBrowser} from '@angular/platform-browser'; import {MatChipsModule} from '@angular/material-experimental/mdc-chips'; /** @@ -21,5 +20,3 @@ export class TestComponent {} bootstrap: [TestComponent], }) export class AppModule {} - -platformBrowser().bootstrapModule(AppModule); diff --git a/integration/size-test/material/chips/basic.ts b/integration/size-test/material/chips/basic.ts index 41cd96ab7096..8dc2673f5968 100644 --- a/integration/size-test/material/chips/basic.ts +++ b/integration/size-test/material/chips/basic.ts @@ -1,5 +1,4 @@ import {Component, NgModule} from '@angular/core'; -import {platformBrowser} from '@angular/platform-browser'; import {MatChipsModule} from '@angular/material/chips'; /** @@ -21,5 +20,3 @@ export class TestComponent {} bootstrap: [TestComponent], }) export class AppModule {} - -platformBrowser().bootstrapModule(AppModule); From c6c5d2308422cc421600eb0221565fa96f1ffcac Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 21 Oct 2021 22:07:58 +0200 Subject: [PATCH 2/4] build: add comment explaining the processing of `.mjs` in esbuild rule Adds a little comment explaining why`.mjs` is processed in the Angular esbuild rule. --- tools/angular/esbuild.config.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/angular/esbuild.config.mjs b/tools/angular/esbuild.config.mjs index 694075b696e3..99a2bd9d8e9b 100644 --- a/tools/angular/esbuild.config.mjs +++ b/tools/angular/esbuild.config.mjs @@ -9,6 +9,7 @@ import {createLinkerEsbuildPlugin} from './create_linker_esbuild_plugin.mjs'; export default { + // Note: We support `.mjs` here as this is the extension used by Angular APF packages. resolveExtensions: ['.mjs', '.js'], format: 'esm', plugins: [ From 6c0e4afd43f3867bee34cb7ddf6457ab4a3aa930 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 21 Oct 2021 22:09:04 +0200 Subject: [PATCH 3/4] build: update size test tool to work with Angular v13 Updates the size test tool to properly run with the Angular v13 compilation pipeline, matching conceptually with what the Angular CLI performs. i.e. running the Angular linker, running the non-deprecated build-optimizer variant (i.e. the Babel plugins). --- integration/size-test/BUILD.bazel | 11 +++ integration/size-test/esbuild.config.mjs | 90 ++++++++++++++++++++++++ integration/size-test/index.bzl | 23 +++--- integration/size-test/rollup.config.js | 35 --------- integration/size-test/terser-config.json | 19 ++--- package.json | 1 - 6 files changed, 119 insertions(+), 60 deletions(-) create mode 100644 integration/size-test/esbuild.config.mjs delete mode 100644 integration/size-test/rollup.config.js diff --git a/integration/size-test/BUILD.bazel b/integration/size-test/BUILD.bazel index ecd3817d7448..b8252c3f4cbf 100644 --- a/integration/size-test/BUILD.bazel +++ b/integration/size-test/BUILD.bazel @@ -1,3 +1,4 @@ +load("@npm//@bazel/esbuild:index.bzl", "esbuild_config") load("//tools:defaults.bzl", "ts_library") package(default_visibility = ["//visibility:public"]) @@ -8,6 +9,16 @@ exports_files([ "index-tmpl.ts", ]) +esbuild_config( + name = "esbuild_config", + config_file = "esbuild.config.mjs", + deps = [ + "@npm//@angular-devkit/build-angular", + "@npm//@angular/compiler-cli", + "@npm//@babel/core", + ], +) + ts_library( name = "check-size", srcs = ["check-size.ts"], diff --git a/integration/size-test/esbuild.config.mjs b/integration/size-test/esbuild.config.mjs new file mode 100644 index 000000000000..cbfef364c0f5 --- /dev/null +++ b/integration/size-test/esbuild.config.mjs @@ -0,0 +1,90 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import babel from '@babel/core'; +import {createEs2015LinkerPlugin} from '@angular/compiler-cli/linker/babel'; +import {ConsoleLogger, NodeJSFileSystem, LogLevel} from '@angular/compiler-cli'; +import {GLOBAL_DEFS_FOR_TERSER_WITH_AOT} from '@angular/compiler-cli/private/tooling'; +import adjustStaticClassMembersPlugin from '@angular-devkit/build-angular/src/babel/plugins/adjust-static-class-members.js'; +import elideAngularMetadataPlugin from '@angular-devkit/build-angular/src/babel/plugins/elide-angular-metadata.js'; +import adjustTypeScriptEnumsPlugin from '@angular-devkit/build-angular/src/babel/plugins/adjust-typescript-enums.js'; +import pureToplevelFunctionsPlugin from '@angular-devkit/build-angular/src/babel/plugins/pure-toplevel-functions.js'; +import fs from 'fs'; + +/** Babel plugin running the Angular linker. */ +const linkerBabelPlugin = createEs2015LinkerPlugin({ + fileSystem: new NodeJSFileSystem(), + logger: new ConsoleLogger(LogLevel.warn), + linkerJitMode: false, +}); + +/** + * ESBuild plugin configuring various optimization Babel plugins. The Babel plugins + * configured as part of this plugin run in the Angular CLI compilation pipeline as well. + */ +const esbuildBabelOptimizePlugin = { + name: 'ng-babel-optimize-esbuild', + setup: build => { + build.onLoad({filter: /.*/}, async args => { + const filePath = args.path; + const content = await fs.promises.readFile(filePath, 'utf8'); + const plugins = [ + linkerBabelPlugin, + adjustStaticClassMembersPlugin, + elideAngularMetadataPlugin, + adjustTypeScriptEnumsPlugin, + ]; + + // All files except for the auto-generated module entry-point are considered side-effect + // free. For these we can add the pure-top level Babel plugin. This matches conceptually + // with what is done in the Angular CLI compilation pipeline, with respect to everything + // in this repo being an official side-effect free APF package. + if (!args.path.includes('autogenerated_module_index.mjs')) { + plugins.push(pureToplevelFunctionsPlugin); + } + + const {code} = await babel.transformAsync(content, { + filename: filePath, + filenameRelative: filePath, + plugins: plugins, + // Sourcemaps are generated inline so that ESBuild can process them. + sourceMaps: 'inline', + compact: false, + }); + + return {contents: code}; + }); + }, +}; + +export default { + // Note: We prefer `.mjs` here as this is the extension used by Angular APF packages. + resolveExtensions: ['.mjs', '.js'], + conditions: ['es2020', 'es2015'], + mainFields: ['fesm2020', 'es2020', 'es2015', 'module'], + format: 'iife', + // The majority of these options match with the ones the CLI sets: + // https://github.com/angular/angular-cli/blob/0d76bf04bca6e083865972b5398a32bbe9396e14/packages/angular_devkit/build_angular/src/webpack/plugins/javascript-optimizer-worker.ts#L133. + treeShaking: true, + minifyIdentifiers: true, + minifySyntax: true, + minifyWhitespace: false, + pure: ['forwardRef'], + legalComments: 'none', + // ESBuild requires the `define` option to take a string-based dictionary. + define: convertObjectToStringDictionary(GLOBAL_DEFS_FOR_TERSER_WITH_AOT), + plugins: [esbuildBabelOptimizePlugin], +}; + +/** Converts an object to a string dictionary. */ +function convertObjectToStringDictionary(value) { + return Object.entries(value).reduce((result, [propName, value]) => { + result[propName] = String(value); + return result; + }, {}); +} diff --git a/integration/size-test/index.bzl b/integration/size-test/index.bzl index 54ff065ed190..2dc225c946c3 100644 --- a/integration/size-test/index.bzl +++ b/integration/size-test/index.bzl @@ -1,13 +1,13 @@ load("@npm//@angular/dev-infra-private/bazel:expand_template.bzl", "expand_template") load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary", "nodejs_test") load("@bazel_skylib//lib:paths.bzl", "paths") -load("@npm//@bazel/rollup:index.bzl", "rollup_bundle") +load("@npm//@bazel/esbuild:index.bzl", "esbuild") load("@npm//@bazel/terser:index.bzl", "terser_minified") load("//tools:defaults.bzl", "ng_module") """ Performs size measurements for the specified file. The file will be built as part - of a `ng_module` and then will be optimized with build-optimizer, rollup and Terser. + of a `ng_module` and then will be optimized with esbuild, babel and terser. The resulting size will be validated against a golden file to ensure that we don't regress in payload size, or that we can improvements to payload size. @@ -35,31 +35,30 @@ def size_test(name, file, deps): testonly = True, deps = [ "@npm//@angular/core", - "@npm//@angular/platform-browser-dynamic", + "@npm//@angular/platform-browser", ] + deps, ) - rollup_bundle( + esbuild( name = "%s_bundle" % name, - config_file = "//integration/size-test:rollup.config.js", + config = "//integration/size-test:esbuild_config", testonly = True, - entry_points = { - (index_file): "%s_bundled" % name, - }, + minify = True, + entry_point = index_file, deps = [ ":%s_lib" % name, - "@npm//@rollup/plugin-node-resolve", - "@npm//@angular-devkit/build-optimizer", ], + target = "es2020", + platform = "browser", # Link the workspace root so that files can be loaded from the workspace. link_workspace_root = True, - sourcemap = "false", + sourcemap = "external", ) terser_minified( testonly = True, name = "%s_bundle_min" % name, - src = ":%s_bundle" % name, + src = "%s_bundle" % name, config_file = "//integration/size-test:terser-config.json", sourcemap = False, ) diff --git a/integration/size-test/rollup.config.js b/integration/size-test/rollup.config.js deleted file mode 100644 index a3e283a6958b..000000000000 --- a/integration/size-test/rollup.config.js +++ /dev/null @@ -1,35 +0,0 @@ -const { - buildOptimizer, -} = require('@angular-devkit/build-optimizer/src/build-optimizer/build-optimizer'); -const {nodeResolve} = require('@rollup/plugin-node-resolve'); - -const buildOptimizerPlugin = { - name: 'build-optimizer', - transform: (content, id) => { - const {content: code, sourceMap: map} = buildOptimizer({ - content, - inputFilePath: id, - emitSourceMap: true, - // Always assume side-effect free source files, except for the autogenerated - // module index file. The bootstrap module call should not be eliminated. - isSideEffectFree: !id.endsWith('_autogenerated_module_index.mjs'), - isAngularCoreFile: false, - }); - if (!code) { - return null; - } - if (!map) { - throw new Error('No sourcemap produced by build optimizer'); - } - return {code, map}; - }, -}; - -module.exports = { - plugins: [ - buildOptimizerPlugin, - nodeResolve({ - mainFields: ['es2020', 'module'], - }), - ], -}; diff --git a/integration/size-test/terser-config.json b/integration/size-test/terser-config.json index 000fc5b4ef43..d0af1569ea37 100644 --- a/integration/size-test/terser-config.json +++ b/integration/size-test/terser-config.json @@ -1,17 +1,12 @@ { - "output": { - "ecma": "es2015", - "comments": false - }, + "ecma": "es2020", "compress": { - "global_defs": { - "ngDevMode": false, - "ngI18nClosureMode": false, - "ngJitMode": false - }, - "passes": 3, + "passes": 2, "pure_getters": true }, - "toplevel": true, - "mangle": true + "format": { + "ascii_only": true, + "wrap_func_args": false + }, + "mangle": false } diff --git a/package.json b/package.json index 2b9d24835792..76c4853811a5 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,6 @@ }, "devDependencies": { "@angular-devkit/build-angular": "13.0.0-next.7", - "@angular-devkit/build-optimizer": "0.1300.0-next.7", "@angular-devkit/core": "13.0.0-next.7", "@angular-devkit/schematics": "13.0.0-next.7", "@angular/bazel": "13.0.0-next.15", From 9a5cef963ad3aeac2c28a1cf7d8fd8198c117345 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 21 Oct 2021 22:43:27 +0200 Subject: [PATCH 4/4] test: update size-golden to reflect recent compilation pipeline changes --- goldens/size-test.yaml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/goldens/size-test.yaml b/goldens/size-test.yaml index 74acb5d334f8..d9e29c2b69ae 100644 --- a/goldens/size-test.yaml +++ b/goldens/size-test.yaml @@ -1,18 +1,18 @@ -cdk/drag-drop/all-directives: 160859 -cdk/drag-drop/basic: 158225 -material-experimental/mdc-chips/basic: 385551 -material-experimental/mdc-form-field/advanced: 417584 -material-experimental/mdc-form-field/basic: 416339 -material/autocomplete/without-optgroup: 392028 -material/button-toggle/standalone: 124412 -material/chips/basic: 320073 -material/datepicker/range-picker/without-form-field: 505044 -material/expansion/without-accordion: 330526 -material/form-field/advanced: 377468 -material/form-field/basic: 376144 -material/list/nav-list: 328072 -material/menu/without-lazy-content: 398590 -material/radio/without-group: 127571 -material/select/basic: 437305 -material/tabs/advanced: 369608 -material/tabs/basic: 368747 +cdk/drag-drop/all-directives: 155091 +cdk/drag-drop/basic: 152522 +material-experimental/mdc-chips/basic: 249660 +material-experimental/mdc-form-field/advanced: 296409 +material-experimental/mdc-form-field/basic: 294855 +material/autocomplete/without-optgroup: 281544 +material/button-toggle/standalone: 186619 +material/chips/basic: 228157 +material/datepicker/range-picker/without-form-field: 398783 +material/expansion/without-accordion: 200184 +material/form-field/advanced: 247973 +material/form-field/basic: 246355 +material/list/nav-list: 194468 +material/menu/without-lazy-content: 286831 +material/radio/without-group: 189803 +material/select/basic: 329893 +material/tabs/advanced: 248653 +material/tabs/basic: 247787