Skip to content

Commit faac417

Browse files
committed
build: add infrastructure for performing size golden tests
1 parent c05a07e commit faac417

14 files changed

+252
-24
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,4 @@
319319
/.vscode/** @angular/dev-infra-components @mmalerba
320320
/src/* @jelbourn
321321
/goldens/ts-circular-deps.json @angular/dev-infra-components
322+
/goldens/size-test.json @jelbourn @mmalerba @crisbeto

WORKSPACE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
88
# Add NodeJS rules
99
http_archive(
1010
name = "build_bazel_rules_nodejs",
11-
sha256 = "d14076339deb08e5460c221fae5c5e9605d2ef4848eee1f0c81c9ffdc1ab31c1",
12-
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.6.1/rules_nodejs-1.6.1.tar.gz"],
11+
sha256 = "84abf7ac4234a70924628baa9a73a5a5cbad944c4358cf9abdb4aab29c9a5b77",
12+
urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.7.0/rules_nodejs-1.7.0.tar.gz"],
1313
)
1414

1515
# Add sass rules

goldens/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
exports_files([
2+
"size-test.json",
3+
])

goldens/size-test.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"material/list": 224424
3+
}

integration/size-test/BUILD.bazel

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
load("//tools:defaults.bzl", "ts_library")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
exports_files([
6+
"rollup.config.js",
7+
"terser-config.json",
8+
])
9+
10+
ts_library(
11+
name = "check-size",
12+
srcs = ["check-size.ts"],
13+
deps = [
14+
"@npm//@types/node",
15+
"@npm//chalk",
16+
],
17+
)

integration/size-test/check-size.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {statSync, readFileSync, writeFileSync} from 'fs';
2+
import chalk from 'chalk';
3+
4+
const [testId, testFileRootpath, isApprove] = process.argv.slice(2);
5+
const testFilePath = require.resolve(`angular_material/${testFileRootpath}`);
6+
const goldenFilePath = require.resolve('../../goldens/size-test.json');
7+
8+
const golden = JSON.parse(readFileSync(goldenFilePath, 'utf8'));
9+
const fileStat = statSync(testFilePath);
10+
const actualSize = fileStat.size;
11+
12+
if (isApprove) {
13+
golden[testId] = actualSize;
14+
writeFileSync(goldenFilePath, JSON.stringify(golden, null, 2));
15+
console.info(chalk.green(`Approved golden size for "${testId}"`));
16+
process.exit(0);
17+
}
18+
19+
if (golden[testId] === undefined) {
20+
console.error(`No golden size for "${testId}". Please create a new entry.`);
21+
printApproveCommand();
22+
process.exit(1);
23+
}
24+
25+
const expectedSize = Number(golden[testId]);
26+
27+
const absoluteSizeDiff = Math.abs(actualSize - expectedSize);
28+
const exceededByPercentage = absoluteSizeDiff > expectedSize / 100;
29+
const exceededByAbsoluteDiff = absoluteSizeDiff > 200;
30+
31+
if (exceededByPercentage) {
32+
console.error(`Actual size deviates by more than 1% of the expected size. ` +
33+
`(expected: ${expectedSize}, actual: ${actualSize}).`);
34+
printApproveCommand();
35+
process.exit(1);
36+
} else if (exceededByAbsoluteDiff) {
37+
console.error(`Actual size deviates by more than 200 bytes from the expected. ` +
38+
`(expected: ${expectedSize}, actual: ${actualSize}).`);
39+
printApproveCommand();
40+
process.exit(1);
41+
}
42+
43+
function printApproveCommand() {
44+
console.info(chalk.yellow('You can approve the golden by running the following command:'));
45+
console.info(chalk.yellow(` bazel run ${process.env.BAZEL_TARGET}.approve`));
46+
}

integration/size-test/index.bzl

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary", "nodejs_test")
2+
load("@npm_bazel_rollup//:index.bzl", "rollup_bundle")
3+
load("@npm_bazel_terser//:index.bzl", "terser_minified")
4+
load("//tools:defaults.bzl", "ng_module")
5+
6+
"""
7+
Performs size measurements for the specified file. The file will be built as part
8+
of a `ng_module` and then will be optimized with build-optimizer, rollup and Terser.
9+
10+
The resulting size will be validated against a golden file to ensure that we don't
11+
regress in payload size, or that we can improvements to payload size.
12+
"""
13+
def size_test(name, file, deps):
14+
# Generates an unique id for the given size test. e.g. if the macro is called
15+
# within the `integration/size-test/material` package with `name = list`, then
16+
# the unique id will be set to `material/list`.
17+
test_id = "%s/%s" % (native.package_name()[len("integration/size-test/"):], name)
18+
19+
ng_module(
20+
name = "%s_lib" % name,
21+
srcs = ["%s.ts" % name],
22+
deps = [
23+
"@npm//@angular/core",
24+
"@npm//@angular/platform-browser-dynamic",
25+
] + deps,
26+
)
27+
28+
rollup_bundle(
29+
name = "%s_bundle" % name,
30+
config_file = "//integration/size-test:rollup.config.js",
31+
entry_points = {
32+
(file): "%s_bundled" % name,
33+
},
34+
deps = [
35+
":%s_lib" % name,
36+
"@npm//rollup-plugin-node-resolve",
37+
"@npm//@angular-devkit/build-optimizer",
38+
],
39+
sourcemap = "false",
40+
)
41+
42+
terser_minified(
43+
name = "%s_bundle_min" % name,
44+
src = ":%s_bundle" % name,
45+
config_file = "//integration/size-test:terser-config.json",
46+
sourcemap = False,
47+
)
48+
49+
nodejs_test(
50+
name = name,
51+
data = [
52+
"//goldens:size-test.json",
53+
"//integration/size-test:check-size",
54+
":%s_bundle_min" % name,
55+
],
56+
entry_point = "//integration/size-test:check-size.ts",
57+
args = [test_id, "$(rootpath :%s_bundle_min)" % name],
58+
)
59+
60+
nodejs_binary(
61+
name = "%s.approve" % name,
62+
data = [
63+
"//goldens:size-test.json",
64+
"//integration/size-test:check-size",
65+
":%s_bundle_min" % name,
66+
],
67+
entry_point = "//integration/size-test:check-size.ts",
68+
args = [test_id, "$(rootpath :%s_bundle_min)" % name, "true"],
69+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
load("//integration/size-test:index.bzl", "size_test")
2+
3+
size_test(
4+
name = "list",
5+
file = "list.ts",
6+
deps = ["//src/material/list"],
7+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {Component, NgModule} from '@angular/core';
2+
import {platformBrowser} from '@angular/platform-browser';
3+
import {MatListModule} from '@angular/material/list';
4+
5+
@Component({
6+
template: `
7+
<mat-nav-list>
8+
<mat-list-item>
9+
hello
10+
</mat-list-item>
11+
</mat-nav-list>
12+
`,
13+
})
14+
export class TestComponent {}
15+
16+
@NgModule({
17+
imports: [MatListModule],
18+
declarations: [TestComponent],
19+
bootstrap: [TestComponent],
20+
})
21+
export class AppModule {}
22+
23+
platformBrowser().bootstrapModule(AppModule);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const {buildOptimizer} = require('@angular-devkit/build-optimizer');
2+
const node = require('rollup-plugin-node-resolve');
3+
4+
const buildOptimizerPlugin = {
5+
name: 'build-optimizer',
6+
transform: (content, id) => {
7+
const {content: code, sourceMap: map} = buildOptimizer({
8+
content,
9+
inputFilePath: id,
10+
emitSourceMap: true,
11+
isSideEffectFree: true,
12+
isAngularCoreFile: false,
13+
});
14+
if (!code) {
15+
return null;
16+
}
17+
if (!map) {
18+
throw new Error('No sourcemap produced by build optimizer');
19+
}
20+
return {code, map};
21+
},
22+
};
23+
24+
module.exports = {
25+
plugins: [
26+
buildOptimizerPlugin,
27+
node({
28+
mainFields: ['es2015_ivy_ngcc', 'module_ivy_ngcc','es2015', 'module'],
29+
}),
30+
],
31+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"output": {
3+
"ecma": "es2015",
4+
"comments": false
5+
},
6+
"compress": {
7+
"global_defs": {
8+
"ngDevMode": false,
9+
"ngI18nClosureMode": false,
10+
"ngJitMode": false
11+
},
12+
"passes": 3,
13+
"pure_getters": true
14+
},
15+
"mangle": true
16+
}

integration/size-test/tsconfig.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"compilerOptions": {
3+
"lib": ["es2015"],
4+
"types": ["node"]
5+
}
6+
}

package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,12 @@
7979
"@bazel/bazelisk": "^1.4.0",
8080
"@bazel/buildifier": "^2.2.1",
8181
"@bazel/ibazel": "^0.13.0",
82-
"@bazel/jasmine": "^1.6.0",
83-
"@bazel/karma": "^1.6.0",
84-
"@bazel/protractor": "^1.6.0",
85-
"@bazel/terser": "^1.4.1",
86-
"@bazel/typescript": "^1.6.0",
82+
"@bazel/jasmine": "^1.7.0",
83+
"@bazel/karma": "^1.7.0",
84+
"@bazel/protractor": "^1.7.0",
85+
"@bazel/rollup": "^1.7.0",
86+
"@bazel/terser": "^1.7.0",
87+
"@bazel/typescript": "^1.7.0",
8788
"@firebase/app-types": "^0.3.2",
8889
"@octokit/rest": "16.28.7",
8990
"@schematics/angular": "^10.0.0-rc.2",

yarn.lock

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -400,37 +400,42 @@
400400
resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.13.0.tgz#2307bdf9ba0ad9835ee603b8fb521822bf3b8a11"
401401
integrity sha512-SFyS6oiibp8KW9BgAU+Tk0DhrH/sJx9om/OlB/Mg4hDEn8F8dj2QRqJE6CVhBCtLDcZDeD7WIAZKQDxKRYIShw==
402402

403-
"@bazel/jasmine@^1.6.0":
404-
version "1.6.0"
405-
resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-1.6.0.tgz#c469ab8725d9a2e48c0c3c965861ff8add9272ac"
406-
integrity sha512-WtOQDtIMHKTxlp0+FcdrADV6LMrpJV7eEGZippSNFPL5YhwwrPfCSOs5WkooatsrjL5YEszswzqQXFjvC7EZKQ==
403+
"@bazel/jasmine@^1.7.0":
404+
version "1.7.0"
405+
resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-1.7.0.tgz#429df76e6628aa139176340434729cc091e371d7"
406+
integrity sha512-LXq6nfBBEczjsDLwFW9kesGdewRrnFiAOZzXAAivCV3xtq516xK4QnVWA9tQGq+R1DnY50IaODpCJhh8PDezdg==
407407
dependencies:
408408
jasmine "~3.5.0"
409409
jasmine-core "~3.5.0"
410410
jasmine-reporters "~2.3.2"
411411
v8-coverage "1.0.9"
412412

413-
"@bazel/karma@^1.6.0":
414-
version "1.6.0"
415-
resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.6.0.tgz#98950b71114dd9ec169e6778a35d31ae1f578655"
416-
integrity sha512-9cX0E1SiMWwA70ZMFnMzeqSRn3biduGx03bGV77FSUYKocZpyfU2cOEygYGfxAqHnyM7x4cS8nflRv3+ZE0Aqg==
413+
"@bazel/karma@^1.7.0":
414+
version "1.7.0"
415+
resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.7.0.tgz#ec7e97a2629f5af0b2abe9a99ae30363a34af97d"
416+
integrity sha512-mGYVD9DldB3v/DjxJpS39X1vUD6M32Al96DMoilwW3TSAazcRWwUAC6HY9z5Wtyeqwxyk8BY1Mg1/berWpoTxg==
417417
dependencies:
418418
tmp "0.1.0"
419419

420-
"@bazel/protractor@^1.6.0":
421-
version "1.6.0"
422-
resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.6.0.tgz#cf095a1dbc038def7031c513a3b87f4e79bedb00"
423-
integrity sha512-gPiRv0oUJbVPpQ9nrwe5vjkffAc8VsYJhpTGgG+8aPdOaTLWgmBP/sy4BdfijU9O1Z/mNYojQCZgMzQz6kAvdg==
420+
"@bazel/protractor@^1.7.0":
421+
version "1.7.0"
422+
resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.7.0.tgz#1ced325a64d77bccca4bf881e62982d017d6b639"
423+
integrity sha512-sLbejWwmwTupCS3JKdBeiZMUbylLpJxJdlrz8sZ9t4KV6YiFAXNOloCScrrdOkeiJz5QQZRG3p3rqHbIszUAwQ==
424+
425+
"@bazel/rollup@^1.7.0":
426+
version "1.7.0"
427+
resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.7.0.tgz#5c0f0d51d2f3f14e78781a4b9e6a9ffba87f1579"
428+
integrity sha512-Pp5aCJw3gwu77zn6/fQgZ39ArrWEI5O3dja5wKadBnfOQ66PImIEr+bf7JgROoWvACH1kGxaS423rq51fiuCsA==
424429

425-
"@bazel/terser@^1.4.1":
430+
"@bazel/terser@^1.7.0":
426431
version "1.7.0"
427432
resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.7.0.tgz#c43e711e13b9a71c7abd3ade04fb4650d547ad01"
428433
integrity sha512-u/UXk0WUinvkk1g5xxfqGieBz3r12Bj2y2m25lC5GjHBgCpGk7DyeGGi9H3QQNO1Wmpw51QSE9gaPzKzjUVGug==
429434

430-
"@bazel/typescript@^1.6.0":
431-
version "1.6.0"
432-
resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.6.0.tgz#8dfd29e71bcf917d5f9cb67f19ac4dcfc9082439"
433-
integrity sha512-vAKuwy1Hgl+t3M3sH/G0oqHRYN35TdENj+0lsCI3x7EbSzyI6cbA3YQrLrlyvdScksqOpZa3PZ3UBGqfJJq2DA==
435+
"@bazel/typescript@^1.7.0":
436+
version "1.7.0"
437+
resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.7.0.tgz#8dc02b8a161f4fff3285186066b5f73666793452"
438+
integrity sha512-M6JPXJZ+W6457QZfPHmGg/Mejnp7//YTnffGmnmeK9vDqybXeCCRWW1/iEOwopLJYQViBHfaoulde0VXelx9sA==
434439
dependencies:
435440
protobufjs "6.8.8"
436441
semver "5.6.0"

0 commit comments

Comments
 (0)