Thanks for the response. The only way I could find of doing #1 (including clientlibs on a per-component basis) involved putting the include in the component HTL, rather than in the document head or at the end of the body. This is why I started to look into how to add async/defer in the first place, since I didn’t want a script in the middle of the page to block the rendering.
Ideally, I wanted to keep the number of requests down by creating bundles for groups of components that are loaded as needed rather than a separate file for each component.
The reason I didn’t want to do #2 (throw everything in a single component bundle) was to keep the page size down and not load a lot of JS/CSS that is never used.
I’m relatively new to AEM development so it’s possible that I’m missing something. I did consider whether creating different static page templates and loading different bundles there would be the way to go - this might be a more "AEM way" of doing things? Potential issues with this would be a) being overly restrictive for marketers in terms of what components they can use, and b) situations where a resource-heavy component is only used in a small percentage of pages of its template type.
Thanks again, looking forward to hearing your thoughts on this!