Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial bundle logs and budget warning are working wrong #15792

Closed
mehmet-erim opened this issue Oct 9, 2019 · 3 comments · Fixed by #16268
Closed

Initial bundle logs and budget warning are working wrong #15792

mehmet-erim opened this issue Oct 9, 2019 · 3 comments · Fixed by #16268

Comments

@mehmet-erim
Copy link

mehmet-erim commented Oct 9, 2019

🐞 Bug report

Command (mark with an x)

- [ ] new
- [x] build
- [ ] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Is this a regression?

Yes, the previous version in which this bug was not present was: 8.2.0

Description

See the my production build logs:

chunk {4} polyfills-es2015.8f11f9b5202829aea96f.js (polyfills) 36.4 kB [initial] [rendered]
chunk {5} polyfills-es5.509fc4fe9eb4ca689d44.js (polyfills-es5) 123 kB [initial] [rendered]
chunk {10} 10-es2015.c32b61866de840ef129e.js () 493 kB  [rendered]
chunk {10} 10-es5.c32b61866de840ef129e.js () 493 kB  [rendered]
chunk {1} 1-es2015.067123cd46b49e92639e.js () 58.6 kB  [rendered]
chunk {1} 1-es5.067123cd46b49e92639e.js () 58.6 kB  [rendered]
chunk {3} main-es2015.9aaa072f8c4bafbb0741.js (main) 1.23 MB [initial] [rendered]
chunk {3} main-es5.9aaa072f8c4bafbb0741.js (main) 1.38 MB [initial] [rendered]
chunk {11} 11-es2015.0b8251f22b4aeeb5189d.js () 6.81 kB  [rendered]
chunk {11} 11-es5.0b8251f22b4aeeb5189d.js () 7.31 kB  [rendered]
chunk {12} 12-es2015.72933d71e5152be6b59d.js () 33.5 kB  [rendered]
chunk {12} 12-es5.72933d71e5152be6b59d.js () 34.6 kB  [rendered]
chunk {13} 13-es2015.1fc927ee306364cc00ce.js () 94.2 kB  [rendered]
chunk {13} 13-es5.1fc927ee306364cc00ce.js () 98.7 kB  [rendered]
chunk {14} 14-es2015.bb0b32700fe49a3f642f.js () 6.96 kB  [rendered]
chunk {14} 14-es5.bb0b32700fe49a3f642f.js () 7.55 kB  [rendered]
chunk {15} 15-es2015.810b7eb6e28f4c5a18a9.js () 47.4 kB  [rendered]
chunk {15} 15-es5.810b7eb6e28f4c5a18a9.js () 49.7 kB  [rendered]
chunk {16} 16-es2015.4654fbeb9ef11a461cf2.js () 1.27 kB  [rendered]
chunk {16} 16-es5.4654fbeb9ef11a461cf2.js () 1.27 kB  [rendered]
chunk {17} 17-es2015.e449da56215df3d9f458.js () 2.16 kB  [rendered]
chunk {17} 17-es5.e449da56215df3d9f458.js () 2.16 kB  [rendered]
chunk {18} 18-es2015.b5d8895043bdc2ccc136.js () 3.23 kB  [rendered]
chunk {18} 18-es5.b5d8895043bdc2ccc136.js () 3.23 kB  [rendered]
chunk {19} 19-es2015.e56ec75d19574d2ac0c7.js () 2.79 kB  [rendered]
chunk {19} 19-es5.e56ec75d19574d2ac0c7.js () 2.79 kB  [rendered]
chunk {20} 20-es2015.690e247eaeb6eb972646.js () 1.67 kB  [rendered]
chunk {20} 20-es5.690e247eaeb6eb972646.js () 1.67 kB  [rendered]
... Locale chunks...
chunk {243} 243-es2015.605d9123aa79c34ed23f.js () 1.58 kB  [rendered]
chunk {243} 243-es5.605d9123aa79c34ed23f.js () 1.58 kB  [rendered]
chunk {0} runtime-es2015.3958ea6a909818f107eb.js (runtime) 8.31 kB [entry] [rendered]
chunk {0} runtime-es5.3958ea6a909818f107eb.js (runtime) 8.31 kB [entry] [rendered]
chunk {2} font-awesome.min.css (font-awesome.min) 29.9 kB [initial] [rendered]
chunk {6} primeicons.css (primeicons) 7.47 kB [initial] [rendered]
chunk {7} primeng-nova-light-theme.css (primeng-nova-light-theme) 80.9 kB [initial] [rendered]
chunk {8} primeng.min.css (primeng.min) 76.7 kB [initial] [rendered]
chunk {9} styles.4953f15ce3da10a7ca92.css (styles) 138 kB [initial] [rendered]
Date: 2019-10-09T05:30:37.419Z - Hash: 5a3d03b7c603dc596e66 - Time: 78306ms

WARNING in budgets, maximum exceeded for initial. Budget 2 MB was exceeded by 462 kB.

Sum up the es2015 or es5 sizes. The result isn't more than 2 MB.

Also, these chunks are not initial. Because I marked the lazy.

chunk {2} font-awesome.min.css (font-awesome.min) 29.9 kB [initial] [rendered]
chunk {6} primeicons.css (primeicons) 7.47 kB [initial] [rendered]
chunk {7} primeng-nova-light-theme.css (primeng-nova-light-theme) 80.9 kB [initial] [rendered]
chunk {8} primeng.min.css (primeng.min) 76.7 kB [initial] [rendered]

See the my angular.json:

 "build": {
  "builder": "@angular-devkit/build-angular:browser",
  "options": {
    "outputPath": "dist/dev-app",
    "index": "apps/dev-app/src/index.html",
    "main": "apps/dev-app/src/main.ts",
    "polyfills": "apps/dev-app/src/polyfills.ts",
    "tsConfig": "apps/dev-app/tsconfig.app.json",
    "aot": false,
    "assets": ["apps/dev-app/src/favicon.ico", "apps/dev-app/src/assets"],
    "extractCss": true,
    "styles": [
      "apps/dev-app/src/styles.scss",
      "node_modules/bootstrap/dist/css/bootstrap.min.css",
      {
        "input": "node_modules/font-awesome/css/font-awesome.min.css",
        "lazy": true,
        "bundleName": "font-awesome.min"
      },
      {
        "input": "node_modules/primeng/resources/themes/nova-light/theme.css",
        "lazy": true,
        "bundleName": "primeng-nova-light-theme"
      },
      {
        "input": "node_modules/primeicons/primeicons.css",
        "lazy": true,
        "bundleName": "primeicons"
      },
      {
        "input": "node_modules/primeng/resources/primeng.min.css",
        "lazy": true,
        "bundleName": "primeng.min"
      }
    ],
    "scripts": []
}

🔬 Minimal Reproduction

ng new angular-repro-app

cd angular-repro-app

npm install bootstrap

And then open the angular.json, replace the styles array as shown below:

"architect": {
   "build": {
      "builder": "@angular-devkit/build-angular:browser",
         "options": {
           ...
          "styles": ["src/styles.css", 
              { "input": "node_modules/bootstrap/dist/css/bootstrap.css", "lazy": true }],
     }

ng build --prod

See the build logs:

chunk {0} runtime-es2015.e8a2810b3b08d6a1b6aa.js (runtime) 1.45 kB [entry] [rendered]
chunk {0} runtime-es5.e8a2810b3b08d6a1b6aa.js (runtime) 1.45 kB [entry] [rendered]
chunk {2} main-es2015.13bd2a83958218d67a87.js (main) 245 kB [initial] [rendered]
chunk {2} main-es5.13bd2a83958218d67a87.js (main) 294 kB [initial] [rendered]
chunk {3} polyfills-es2015.d1c6d91d83aaea5467fa.js (polyfills) 36.4 kB [initial] [rendered]
chunk {4} polyfills-es5.f6de9812ead48897ca6c.js (polyfills-es5) 123 kB [initial] [rendered]
chunk {1} bootstrap.css (bootstrap) 138 kB [initial] [rendered] // wrong
chunk {5} styles.3ff695c00d717f2d2a11.css (styles) 0 bytes [initial] [rendered]

🌍 My Environment


Angular CLI: 8.3.8
Node: 10.16.0
OS: darwin x64
Angular: 8.2.9
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.803.8
@angular-devkit/build-angular      0.803.8
@angular-devkit/build-ng-packagr   0.803.8
@angular-devkit/build-optimizer    0.803.8
@angular-devkit/build-webpack      0.803.8
@angular-devkit/core               8.3.8
@angular-devkit/schematics         8.3.8
@angular/cdk                       8.2.2
@angular/cli                       8.3.8
@ngtools/webpack                   8.3.8
@schematics/angular                8.3.8
@schematics/update                 0.803.8
ng-packagr                         5.5.1
rxjs                               6.4.0
typescript                         3.5.3
webpack                            4.39.2
@dgp1130
Copy link
Collaborator

dgp1130 commented Nov 14, 2019

I pulled the example build log provided to do some of my own math and I'm also not able to verify the number given by the CLI.

douglasparker@gryphon (~/Source/Angular CLI)
[19-11-14 12:53:25]$ cat build.log | grep "^chunk" | grep "\[initial\]" | grep -v "-es2015" | awk '{ if ($6 == "MB") sum += $5 * 1024; else sum += $5 } END { print sum }'
1869.09
douglasparker@gryphon (~/Source/Angular CLI)
[19-11-14 12:54:21]$ cat build.log | grep "^chunk" | grep "\[initial\]" | grep -v "-es5" | awk '{ if ($6 == "MB") sum += $5 * 1024; else sum += $5 } END { print sum }'   
1628.89

Neither differential build exceeds 2 MB by my calculation. Including [entry] files and the incorrectly included CSS files still doesn't cross 2 MB.

I'm able to reproduce the problem of a CSS file being incorrectly labeled as [initial] when it should be lazy (thanks for the minimal example). I'll dig in a little further to try and understand what's going on here.

@dgp1130
Copy link
Collaborator

dgp1130 commented Nov 18, 2019

Talked with @clydin a bit about this. Ultimately the problem comes down to the fact that Webpack's abstractions are leaking through in an unintended fashion. Webpack should be an implementation detail unrelated to the external interface.

In this case, Webpack considers any "entry" files to be initial because they must be loaded from somewhere. It is not aware of the lazy option provided in angular.json and can't really take that into account. We do process these statistics in an existing Webpack plugin, but this happens mid-build where some computations have yet to run.

The solution here is to pull out that plugin's logic to run after the build has completed with the final statistics generated by Webpack. We can also update the logic which prints these statistics to correct the mislabeled styles by taking angular.json into account.

dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 22, 2019
…be post-build

Refs angular#15792.

This provides access to all the size information necessary because all build steps have already completed. This commit is roughly a no-op because it simply moves the budget checks to be executed post-build.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 22, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 22, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 22, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 22, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 25, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 25, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 26, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 26, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 26, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 28, 2019
…be post-build

Refs angular#15792.

This provides access to all the size information necessary because all build steps have already completed. This commit is roughly a no-op because it simply moves the budget checks to be executed post-build.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 28, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Nov 28, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 4, 2019
…be post-build

Refs angular#15792.

This provides access to all the size information necessary because all build steps have already completed. This commit is roughly a no-op because it simply moves the budget checks to be executed post-build.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 4, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 4, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 4, 2019
…be post-build

Refs angular#15792.

This provides access to all the size information necessary because all build steps have already completed. This commit is roughly a no-op because it simply moves the budget checks (for different builds) to be executed post-build.

The lone exception is the AnyComponentStyle budget. Component stylesheet files are not emitted after the build is completed, so there is no size information to work with. Instead, these budgets are checked during a separate plugin (exected for different builds **and** non-differential builds).
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 4, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 4, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 9, 2019
…be post-build

Refs angular#15792.

This provides access to all the size information necessary because all build steps have already completed. This commit is roughly a no-op because it simply moves the budget checks (for different builds) to be executed post-build.

The lone exception is the AnyComponentStyle budget. Component stylesheet files are not emitted after the build is completed, so there is no size information to work with. Instead, these budgets are checked during a separate plugin (exected for different builds **and** non-differential builds).
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 9, 2019
… bundle budget.

Refs angular#15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
dgp1130 added a commit to dgp1130/angular-cli that referenced this issue Dec 9, 2019
…ial builds separately

Fixes angular#15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
vikerman pushed a commit that referenced this issue Dec 9, 2019
…be post-build

Refs #15792.

This provides access to all the size information necessary because all build steps have already completed. This commit is roughly a no-op because it simply moves the budget checks (for different builds) to be executed post-build.

The lone exception is the AnyComponentStyle budget. Component stylesheet files are not emitted after the build is completed, so there is no size information to work with. Instead, these budgets are checked during a separate plugin (exected for different builds **and** non-differential builds).
vikerman pushed a commit that referenced this issue Dec 9, 2019
… bundle budget.

Refs #15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
vikerman pushed a commit that referenced this issue Dec 9, 2019
…ial builds separately

Fixes #15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
vikerman pushed a commit that referenced this issue Dec 10, 2019
…be post-build

Refs #15792.

This provides access to all the size information necessary because all build steps have already completed. This commit is roughly a no-op because it simply moves the budget checks (for different builds) to be executed post-build.

The lone exception is the AnyComponentStyle budget. Component stylesheet files are not emitted after the build is completed, so there is no size information to work with. Instead, these budgets are checked during a separate plugin (exected for different builds **and** non-differential builds).
vikerman pushed a commit that referenced this issue Dec 10, 2019
… bundle budget.

Refs #15792.

Static files listed in `angular.json` were being accounted in the `initial` bundle budget even when they were deferred asynchronously with `"lazy": true` or `"inject": false`. Webpack belives these files to be `initial`, so this commit corrects that by finding all extra entry points and excluding ones which are explicitly marked by the application developer as asynchronous.

One edge case would be that the main bundle might transitively depend on one of these static files, and thus pull it into the `initial` bundle. However, this is not possible because the files are not present until the end of the build and cannot be depended upon by a Webpack build step. Thus all files listed by the application developer can be safely assumed to truly be loaded asynchronously.
vikerman pushed a commit that referenced this issue Dec 10, 2019
…ial builds separately

Fixes #15792.

Previously, budgets would include content for both versions of a differential build. Thus the `initial` budget would count content from the ES5 **and** ES2015 bundles together. This is a very misleading statistic because no user would download both versions. I've updated the budget calculators to take this into account and generate size values for both builds which are then checked independently of each other.

The only calculators I changed are the `InitialCalculator` (for computing `initial` bundle sizes) and `BundleCalculator` (for computing named bundles). Since budgets are handled by Webpack for builds without differential loading, the `initial` bundle will always have those two sizes. The `BundleCalculator` might reference a bundle which does not have differential loading performed (such as a CSS file), so it emits sizes depending on whether or not multiple builds were found for that chunk.

Most of the other calculators don't really need to take differential loading into account. `AnyScriptCalculator` and `AnyCalculator` already apply on a file-by-file basis, so they generate sizes for both build versions already. `AnyComponentStyleCalculator` only applies to CSS which does not have differential builds.

The wierd ones here are `AllCalculator` and `AllScriptCalculator` which reference files with and without differential builds. Conceptually, they should be separated, as a "total" budget specified by an app developer probably wanted it to mean "the total resources a user would have to download", which would only be one differential build at a time. However, I don't see a good way of identifying which assets belong to which differential build. Even if an asset belongs to a chunk with differential builds, we don't know which build takes which assets into account. I decided to leave this for the time being, but it is probably something we should look into separately.

Since budgets take differential loading into account, users might reasonably want to set different budgets for different builds (ie. "initial-es2015 bundle should be capped at 100k, but initial-es5 bundle can go to 150k"). That's more of a feature request, so I also left that out for a future PR.
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jan 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.