-
Notifications
You must be signed in to change notification settings - Fork 13.5k
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
bug: All Angular standalone components are not tree shaken from the main JS chunk #28574
Comments
See @liamdebeasi answer. |
Thanks for the report. The comment in #28574 (comment) has an explanation for the behavior you are seeing. Ionic is working correctly, but the problem is that the bundle analyzer tool is not showing you the complete picture. Using the tool I noted in the linked comment will give you a more accurate picture of your build size. |
@liamdebeasi Thanks for the link, but I'm still confused 🤔 . Why are all components (even if it's just the ones that I use) included in the main chunk? This defies the very purpose of Angular standalone components. Yes, I believe you that this makes the overall size of the bundle smaller but this benefit is overshadowed by the overhead on my main.js. In the example that you show, the overhead is ~50kb (which I would willingly take) but in my case it's an increase from 600kb to almost 1.3 MB which is a deal breaker, especially for my web vitals. It seems I'll stick to the "old" lazy loaded components for now until something changes. How long do you plan supporting them? |
@StefanNedelchev is |
Last I checked this behavior is controlled by the Angular CLI/bundler, not Ionic. I'll double check with the Angular team, but as far as I know this is not something Ionic is able to control.
We don't have any immediate plans to remove, but we do plan to slowly move away from
Please file a separate issue with a reproduction. |
I spoke with the Angular team and it sounds like Angular should be doing the desired behavior automatically. I'm working with them to determine why that's not happening right now. I'll follow up here when I have more to share. |
In my case it's almost similar in both webpack and esbuild. There was a difference but it seemed insignificant to me.
Thanks a lot, it will be appreciated. If it's an Angular CLI issue then I hope they will investigate it. |
The team has been investigating this for the past few days. I've included my findings below. TL;DRBoth Ionic and Angular/Webpack/ESBuild are working as intended here. Tree shaking is working (meaning unused components are being eliminated from the final build), but code splitting is not ideal due to limitations in bundlers such as Webpack and ESBuild. Ionic can change how components are imported to avoid this limitation, but it comes with breaking changes and a degraded developer experience. While we're open to making this change in the future, we'd like to have a Request For Comments (RFC) period first and investigate mitigation techniques to preserve the developer experience. DefinitionsFor anyone unclear on the difference between tree shaking and code splitting, MDN has some good definitions: What behavior is happening?Ionic components are being included in the first chunk that loads in an Angular application as opposed to being added to the chunks where they are actually used. For example, if Why is this behavior happening?Ionic ships components from a single entry point (i.e.
Why do we ship components from a single entry point?This was originally done to make it easy for developers to know where to import components from. In other words, it removes the guess-work associated with figuring out the correct import paths. Our Angular, React, and Vue integrations all have this design. The alternative is each component is shipped in its own entry point. Developers would need to have 1 import per component which can be cumbersome to manage. We felt it was imported to prioritize developer experience here. Can bundlers change to account for this behavior?Yes, but it's not a straightforward process. In fact, ESBuild used to have this behavior but later removed it when top-level await was added: evanw/esbuild#2869. As a result, we don't expect bundlers to support splitting code from a single entry point across chunks anytime soon. Can Ionic change to account for this behavior?Yes, but it comes with breaking changes. To optimize for code splitting, each component would need to be in its own entry point. Developer code would need to change like so: - import { IonHeader, IonToolbar, IonTitle, IonButtons, IonBackButton, IonContent } from '@ionic/angular/standalone';
+ import { IonHeader } from '@ionic/angular/standalone/header';
+ import { IonToolbar } from '@ionic/angular/standalone/toolbar';
+ import { IonTitle } from '@ionic/angular/standalone/title';
+ import { IonButtons } from '@ionic/angular/standalone/buttons';
+ import { IonButton } from '@ionic/angular/standalone/button';
+ import { IonContent } from '@ionic/angular/standalone/content'; Doing this for every single component in an application is time consuming and also makes the code more verbose than before. Other non-component imports such as Is there a path forward to optimize for code splitting while avoiding a degraded developer experience?I think so, but it's a large amount of work that we do not have bandwidth for at the moment. The original motivation for shipping components from a single entry point still applies, but I think nowadays we have more tools to mitigate the degraded developer experience than we did several years ago. In an ideal world we'd release an RFC that details the following steps we'd take. These steps would need to be taken for Angular, React, and Vue at a minimum:
We could focus on shipping item 2 to save a significant amount of development time, but I think that would be challenging for Ionic developers since they'd effectively have no support in migration/maintenance of this approach. I can't promise the team will make all of the proposed changes here, but I think it's worth us at least doing an RFC to collect community feedback to start. |
Angular Material library is currently using similar code splitting technique where you import |
To be clear, we aren't set on the approach I detailed above. It was mainly there to give an idea of what a path forward could look like.
If you're using VSCode you can stop it from suggesting |
No, WebStorm, but they might have a similar solution. Haven't looked for it. |
First of all, big thanks for doing such a thorough investigation and solid summary.
I can second the comment on the Angular Material library approach here, with automatic imports in most IDEs these days it doesn't really feel like a degraded developer experience. Of course you are right in that this means adapting all imports in a transition which is a bit of effort. Would be interested to see the RFC and joining the discussion there! |
@liamdebeasi thank you for not ignoring the "issue" and diving into it. Your comment provides some good insights and also makes me understand why Angular Material imports work the way they do at the moment. |
I haven't tried this, but at first glance this does seem possible.. We'd be migrating the import syntax which I believe is mostly consistent across frameworks (i.e.
Yeah that's a good thought. My understanding is the optimized code splitting solution could never export anything from Thanks for the feedback, everyone! As noted, our first step here is a public RFC to collect feedback from the community. We'll use that feedback to inform our decisions moving forward. |
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out. |
Prerequisites
Ionic Framework Version
v7.x
Current Behavior
I tried migrating my current app to Angular 17 and then migrating to Standalone Ionic components. I followed the official guideline and used the automated tool for help. Then I found out that the main JS chunk suddenly became ~1.3MB (compared to the previous ~600kb).
All my modules and pages are lazy loaded and this was a surprise for me. I double checked that all instances of
IonicModule
are gone and all imports come from the/standalone
path. I also double checked that I only import what is needed and where it's needed. Everything seems to be fine. The app is a mixture between modules and standalone components (if this matters).After checking the bundle that's what I found:
As you can see - the main chink is full of Ionic components which are not tree-shaken.
Actually I could also reproduce this in a clean Ionic standalone project with the latest CLI:
The issue happens with both webpack and esbuild.
Expected Behavior
I would expect all components to be tree-shaken and bundled in their respective places away from main JS.
Steps to Reproduce
Code Reproduction URL
No response
Ionic Info
Ionic:
Ionic CLI : 7.1.5 (/usr/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 7.5.6
@angular-devkit/build-angular : 17.0.3
@angular-devkit/schematics : 17.0.3
@angular/cli : 17.0.3
@ionic/angular-toolkit : 9.0.0
Capacitor:
Capacitor CLI : 5.5.1
@capacitor/android : not installed
@capacitor/core : 5.5.1
@capacitor/ios : not installed
Utility:
cordova-res : not installed globally
native-run (update available: 2.0.0) : 1.7.4
System:
NodeJS : v18.17.1 (/usr/bin/node)
npm : 9.8.1
OS : Linux 6.2
Additional Information
The app has only Browser platform. It's a mixture between modules and standalone components and all routes are lazy loaded.
The text was updated successfully, but these errors were encountered: