Client classes aren't tree-shakable, resulting in unnecessarily large bundles
See original GitHub issueIs your feature request related to a problem? Please describe.
Clients like WebSiteManagamentClient
are implemented as extremely large classes with large nested classes inside. Module bundlers like webpack are not able to tree-shake unused code from these client classes. Meaning >75% of the bundled code is not needed. This is frustrating considering the SDK bundle is larger than all other bundled node modules combined, and in some projects is larger by 2-3x.
As I mentioned above, the design of the client classes (ex: WebSiteManagementClient
) makes it impossible to exclude unused client methods from the bundle via tree shaking (dead-code elimination). Webpack, rollup, and other popular JS module bundlers are not capable of tree-shaking classes and class methods. ^1
This is pretty frustrating considering in some projects, we’re only using 3-4 methods from a client, but the SDK bundle ends up being almost 900 KB (parsed) ^2. Over half of our bundle is made up of the Azure SDK bundles (~2 MB out of ~4 MB).
The most important reason we are motivated to reduce our bundle size is that it directly correlates to reducing the activation time (startup time) for our VS Code extensions.
A great example of the issue is https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/appservice/arm-appservice/src/webSiteManagementClient.ts#L821-L840, where 20 of these (sometimes very large) classes are nested inside the WebSiteManagementClient
class. All 20 are always bundled regardless of which ones are actually referenced within the consumer code.
appServiceCertificateOrders: AppServiceCertificateOrders;
certificateOrdersDiagnostics: CertificateOrdersDiagnostics;
certificateRegistrationProvider: CertificateRegistrationProvider;
domains: Domains;
topLevelDomains: TopLevelDomains;
domainRegistrationProvider: DomainRegistrationProvider;
appServiceEnvironments: AppServiceEnvironments;
appServicePlans: AppServicePlans;
certificates: Certificates;
containerApps: ContainerApps;
containerAppsRevisions: ContainerAppsRevisions;
deletedWebApps: DeletedWebApps;
diagnostics: Diagnostics;
global: Global;
kubeEnvironments: KubeEnvironments;
provider: Provider;
recommendations: Recommendations;
resourceHealthMetadataOperations: ResourceHealthMetadataOperations;
staticSites: StaticSites; // I only need to access this, but everything is bundled anyway
webApps: WebApps;
Describe the solution you’d like
Since class methods cannot be easily tree-shaked, the ideal solution is to refactor the clients to ES6 modules instead of nested classes. I realize that this might be an unrealistic ask due to the scope of the changes (breaking changes, Autorest, etc.). So maybe there is an easier solution that could make some tree-shaking possible. Maybe make the clients more granular, i.e. consumers should be able to import just the WebApps
portion of the WebSiteManagementClient
. Essentially make it possible to be more granular with imports. I’m open to suggestions here 😄.
Describe alternatives you’ve considered
Since we do only use a handful of methods from a handful of clients in each project, our team has considered removing the SDK dependencies and creating a client with only the API endpoints we need. However, concerns about maintenance and keeping up with API changes make this unattractive.
Additional context
Issue Analytics
- State:
- Created a year ago
- Reactions:4
- Comments:9 (5 by maintainers)
@qiaozha , could you take a look at this ask? I am wondering whether the RLC work could help for this case.
I’ve done some surface level exploration and PoC work using the released JS rest level client package for appservice. The client works as expected and is very promising for our use case. I’m excited to be able to eventually convert our projects to use only rest level clients in the future.
It seems like we have some engineering work to do until we are able to easily move to the RLC. For example, we have extended
ServiceClient
from ms-rest-js. I’m a bit unclear after reading the Core 2 docs on where ms-rest-js stands. Is ms-rest-js still the recommended rest client?We’ll be tracking the exploration into the rest level clients here: https://github.com/microsoft/vscode-azurestaticwebapps/issues/713.
Thanks for the quick turn around on this beta package!
Small issue I found:
I found that the client constructor
apiVersion
option doesn’t seem to workwhen I passed in an API version in the constructor like so:
I expected the
api-version
query parameter to be automatically added to each request. However, I had to add it myself using thequeryParameters
option in the.get()
method.