Skip to content

application builder generates many initial chunks #26307

Closed as not planned
Closed as not planned

Description

@jnizet

Command

build

Description

I just migrated a small project to v17 and the application builder.
The ng build command generates 13 initial (i.e. not lazy-loaded) bundles.

I don't know if it's expected or not, but if it is, I don't understand the point of having so many initial bundles (the browser builder used to generate only 3).

Won't that automatically cause performance issues, given that browsers limit the number of concurrent requests to a given domain?

Describe the solution you'd like

Unless there is a good reason (that I'm currently missing) for so many bundles, I'd like the builder to generate fewer bundles: one for the polyfills (that could be cached for a long time) and one for the application for example.

If there is a good reason for so many bundles, please enlighten me :-)

Describe alternatives you've considered

No response

Activity

  1. pumano commented on Nov 10, 2023

    @pumano

    @jnizet that how esbuild works. If you don't use http/2 it's would be drop in core web vitals. esbuild has open issue evanw/esbuild#207 but that is not implemented.

    If you have http/2 setup that amount of chunks not an issue for you

  2. alan-agius4 commented on Nov 10, 2023

    @alan-agius4
    Collaborator

    Indeed this is expected, this is becasue esbuild does cross chunk code motion which webpack does not, which results in a more smaller chunks.

    When using HTTP/2 or HTTP/3 the number of files does not have any performance penalty.

  3. jnizet commented on Nov 10, 2023

    @jnizet
    ContributorAuthor

    OK. Too bad this isn't considered.
    Couldn't the CLI, which is able to know which chunks are initial and which chunks are lazy-loaded, concatenate the initial chunks generated by esbuild?

  4. alan-agius4 commented on Nov 10, 2023

    @alan-agius4
    Collaborator

    @jnizet, containing the chunks will actually cause unnecessary code to be downloaded when navigating to a particular page.

    Thus, for a performance perspective, having a lot of chunks should be better if using modern HTTP protocols. Although I do see that sometimes esbuild does generate super small chunks under 1 kb, but that is by esbuild design.

    Concatenating chunks is definitely not something the Angular CLI should be doing. The bundler has the full context of how chunks should be split to download as code as possible.

  5. elgerm commented on Nov 28, 2023

    @elgerm

    @alan-agius4 when you say should be better, is this tested? How does esbuild know which pages where are thus creating chunks per page as webpack builder does?

    Our website shows very bad performance after upgrading to angular 17. Lighthouse reports too many chained requests (150 chunks!):
    image
    before with angular 16 it was only 3 chunks and much better perf:

    image

  6. pumano commented on Nov 28, 2023

    @pumano

    @elgerm you are right, but check my message above, try to upgrade your http to http/2 or better http/3 to get better performance, because http 1.1 has only 6 parallel connections in browser (that IS reason why concatenation in vendor chunk exist) while http/2 has 100

  7. alan-agius4 commented on Nov 28, 2023

    @alan-agius4
    Collaborator

    Hi @elgerm,

    Which HTTP version are you using? In the case of HTTP 1 it is expected that there is a performance regression. It is also important mentioning that lighthouse should not be ran against a the local dev-server.

    Esbuild performs code motion and splits the code based on it's usage which does create more chunks. This is described here: https://github.com/evanw/esbuild/blob/main/docs/architecture.md#code-splitting. Webpack has less chunks as it's unable to perform this sort of advanced optimization.

    What is the lighthouse score before and now?

  8. elgerm commented on Nov 28, 2023

    @elgerm

    Hi guys, Lighthouse score went down from 70ish to 39.

    We're behind cloudflare and have http3 enabled.

    I switched back to 16 for now as this was unacceptable performance.

    We get about 50k daily unique visitors from SE Asia, 33% use old devices and may find this unusable. Hence the question if it has been tested that so many small chunks don't degrade performance. There must be a penalty from loading and bootstrapping so many small chunks?

    Angular went from module based to component based and now switched to esbuild that now generates a chunk per component/directive/pipe. There's 450 chunks in the dist folder 🤯.

    Is it possible to go back to webpack build w 17?

  9. pumano commented on Nov 28, 2023

    @pumano

    @elgerm its possíble to use webpack with 17 angular. Just use browser target, not browser-esbuild

  10. sod commented on Dec 8, 2023

    @sod
    Contributor

    The lighthouse block Avoid chaining critical requests is unfortunate reporting. You can only pick one:

    1. many chunks but less unused code
    2. few chunks but more unused code

    The old way (less & bigger chunks) is apparently worse as it's reported under reduce unused javascript with a real penalty.

    But 152 files on initial load indeed does sound scary. Sadly esbuild has no minChunkSize setting like webpack does.

  11. aiwha-dev commented on Jan 3, 2024

    @aiwha-dev
    Contributor

    Our system creates waay more than those 150 chunks, it's actually at 240+ initial chunks (and 472 lazy chunks).

    It is a rather large platform.
    We went from 58 requests at initial load to over 400

    It's still fast though, but I would like the preload to be reduced/delayed.

    Tbh, though Angular is made for larger systems. It often feels like the really really large systems like this are not being tested out well. (not trying to bash here, just how it feels, I still love angular and the way it works a lot)

    (Though it could just be that we should set things up differently, but there isn't much documentation about building a big system)

    Angular 16: (still on webpack)
    image

    Angular 17: (no longer on webpack)
    image

  12. Martinspire commented on Jan 23, 2024

    @Martinspire

    Small project but a lot of dependencies that didn't combine their scripts which results in 698 chunks. I'm all for optimizing, but this is just weird. Especially seeing most are external dependencies which could very well be combined (or at least provide the option to do it). It currently serves 304 chunks for the first page of our project (most of it are external dependencies)

  13. pumano commented on Jan 23, 2024

    @pumano

    what I really recommend to all as workaround is to use webpack for production and serve app for development with --forceEsbuild=true it run your project faster for development purposes, but production code build as previously using webpack. Some problems can be potentially found with background-image resolving difference, but in other cases all works same. We use it in our large app until esbuild not provide some solution for it.

  14. joewIST commented on Feb 16, 2024

    @joewIST

    This is also an issue for us. Looks like we may need to revert to using webpack for production as well, as the chaining of chunks on initial load is causing non-trivial performance issues.

  15. born2net commented on Mar 2, 2024

    @born2net

    same here, our server is http (not http/2) and so we need a way to keep total files same as webpack. Any updates? solutions?

  16. sod commented on Mar 2, 2024

    @sod
    Contributor

    Any updates? solutions?

    First step is look what is in those small chunks. Lets say it's lots of lodash-es code, because lodash is 200 little functions. You could use commonjs lodash instead. esbuild will still delete unused code, but won't rip it apart anymore, as it can't guarantee side effect freeness.

    If your 500 byte chunks contain simple strings, you could move those strings behind a barrel.

    e.g. if you have constants like here:

    // constants-a.ts
    export const foo = 'foo string';
    export const bar = 'bar string';
    
    // constants-b.ts
    export const lorem = 'lorem string';
    export const ipsum = 'ipsum string';

    you create a barrel like:

    // constants.ts
    export * from './constants-a.ts';
    export * from './constants-b.ts';

    And if you import {lorem} from 'constants' it won't put const lorem = 'lorem string'; into a chunk, as esbuild doesn't split chunks for barrels (at least right now, could of course change)

    So there are some ways to bend esbuild to your will.

    Third option might be, to contribute to esbuild something like a minChunkSize option like webpack has.

  17. aiwha-dev commented on Mar 2, 2024

    @aiwha-dev
    Contributor

    Honestly I commented because the amount of chunks can be insane, and imho should be improved with better bundling/lazy loading.

    but it is faster for us and working fine on chromebooks even. Cloudflare is caching it for free (and if you want you could even upload it to cloudflare workers)

    Probably an Unpopular opinion, solutions because people are still on http1 should imho not happen. Use webpack then or upgrade your servers. Http 2 is from may 2015 and almost 9 years old now.

  18. LuisTovar0 commented on Mar 4, 2024

    @LuisTovar0

    this issue is causing my colleagues to call me "the chunk man"

  19. Martinspire commented on Mar 5, 2024

    @Martinspire

    Honestly I commented because the amount of chunks can be insane, and imho should be improved with better bundling/lazy loading.

    This is the main reason yes. I would already be happy if I could force every module to be a chunk, so that with lazy routes it at least only needs to do one request. But its difficult to probably see what belongs where. For standalone stuff it will likely be even more difficult and the only one to tell esbuild to do better, is angular itself. Since it could figure out a dependency tree that can be used to optimize it. Perhaps using routes to bundle them or something.

    Probably an Unpopular opinion, solutions because people are still on http1 should imho not happen. Use webpack then or upgrade your servers. Http 2 is from may 2015 and almost 9 years old now.

    You assume that every company owns their own servers or that their security/monitoring/etc tools can handle http2 already. Lets be real here, some bad admins can't be bothered or simply don't want to do anything about it. So having the option is always going to be of some benefit to people.

    Third option might be, to contribute to esbuild something like a minChunkSize option like webpack has.

    That or a dependency tree that can be used to figure out what is connected and can be bundled. With hot modules replacement / reloading, you already need to know what stuff needs to be reloaded with the changes you've made.

  20. mihailik commented on Mar 20, 2024

    @mihailik

    How can we post-process this exponential explosion of files?

    Shipping ESBuild mode in Angular without built-in handling of chunks makes it highly disruptive.

    Apart from complicating debugging/diagnostics in browser, it rakes up deployment and support risks couple orders of magnitude.

    • Network errors during deployment are way more probable, being 100x more transactional updates to the filesystem.
    • It becomes impossible to spot partial/incomplete deployment.
    • Every and all DevOps processes that were tuned to small number of files will grind nearly to halt

    Anecdotal case:

    • we used to have Angular15 deployment taking 20-30 minutes using rsync to transfer dist/ files
    • by using webpack.optimize.MinChunkSizePlugin we lowered it to 3-4 minutes
    • now we're risking going back to excessively long deployments, even way worse

    If Angular team is not ready to improve the situation at this point, can you folks please give us direction and help adding customisations/plugin/script to implement chunk coalescing at the project side?

  21. angular-automatic-lock-bot commented on Apr 20, 2024

    @angular-automatic-lock-bot

    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.

  22. locked and limited conversation to collaborators on Apr 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions