question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Client classes aren't tree-shakable, resulting in unnecessarily large bundles

See original GitHub issue

Is 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:closed
  • Created a year ago
  • Reactions:4
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
lirenhecommented, May 27, 2022

@qiaozha , could you take a look at this ask? I am wondering whether the RLC work could help for this case.

1reaction
alexweiningercommented, Jun 23, 2022

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 work

when I passed in an API version in the constructor like so:

const client = WebSiteManagementClient(credential, {
        apiVersion: '2019-08-01'
});

I expected the api-version query parameter to be automatically added to each request. However, I had to add it myself using the queryParameters option in the .get() method.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Tree Shaking - webpack
While that may not seem like much in this contrived example, tree shaking can yield a significant decrease in bundle size when working...
Read more >
Tree-Shaking Problems with Component Libraries - Medium
Putting your components in different modules (files), and not bundling them together if you're publishing a library, will help ease this — as ......
Read more >
Optimizing client app size with lightweight injection tokens
You can manage the dependency structure among your components and injectable services to optimize bundle size by using tree-shakable providers. This normally ...
Read more >
API - esbuild
This API call is used by the command-line interface if no input files are provided and the --bundle flag is not present. In...
Read more >
Why is my React component library not tree-shakable?
Your second example bundles into multiple files but your main bundle (with the index.js input) is still a huge file that bundles everything ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found