Hawkeye, the Ultimate esbuild Analyzer

Effortlessly analyze your JS bundles and uncover actionable insights to boost performance and enhance user experience.

emoji_objects emoji_objects emoji_objects
Kevin Kreuzer

Kevin Kreuzer

@kreuzercode

Dec 28, 2024

10 min read

Hawkeye, the Ultimate esbuild Analyzer
share

ℹ️ While our blog primarily focuses on Angular, everything covered in this post works just as well with other JavaScript frameworks — and even vanilla JS!

In modern web development, performance is crucial for delivering a seamless user experience. Users expect fast-loading applications, and with the increasing complexity of modern apps, dependencies can pile up, resulting in bloated bundles.

Bundles are the packaged versions of your application code, created by combining multiple JavaScript, CSS, and other files into a single or smaller set of files. This process reduces the number of HTTP requests, speeding up load times.

Tools like esbuild play a significant role in this process by offering fast and efficient bundling and minification, optimizing your code by removing unused parts (dead code) and reducing its overall size.

However, even with powerful tools like esbuild, developers must be cautious about how they manage dependencies. Carelessly including third-party libraries can significantly inflate the bundle size, leading to slower load times and degraded user experience.

How to prevent big bundle sizes?

In Angular, the CLI provides helpful features like build budgets to alert you when your bundles exceed a specified size.

When you run ng build, the output highlights warnings or errors if the bundle surpasses these thresholds. Once a warning or error is triggered by the build budgets, it’s a clear signal to take action.

At this point, you should either analyze the last commit to identify changes that might have caused the increase or dig into your bundles to pinpoint what is contributing to the size issue.

To analyze and optimize our bundles, we can leverage several open-source tools. In the past, the Webpack Bundle Analyzer was a popular choice among developers for this purpose. However, with Angular’s switch to esbuild in version 17, alternative tools are now required to analyze bundles effectively. Some of the most commonly used tools in the esbuild ecosystem include: source-map-explorer, esbuild-visualizer or EsBuild Bundle Size Analyzer.

I had the opportunity to try all three tools in a large enterprise setting with over 100 SPAs. While each tool had its strengths and provided useful insights, I found that none fully met my needs.

They lacked some core functionalities essential for addressing the specific challenges I faced. These missing features made it difficult to answer critical questions about bundle composition, performance bottlenecks, and optimization opportunities across such a large-scale setup.

What’s Missing in Current esbuild Analyzers?

In a large enterprise environment with multiple SPAs, it’s common to have shared components and services organized into shared libraries. These libraries might be distributed via NPM or exist as Nx libs within a monorepo.

In such an environment, developers often have questions about bundle size and composition. From my experience, the most common and critical questions include:

  • How big is our eager bundle?
    Understanding the size of the bundle loaded on app startup is key to improving initial load performance.

  • How big is our library xyz, and what contributes to its size?
    For shared libraries, it’s crucial to know their impact on the overall bundle and whether unnecessary dependencies or code are inflating their size.

  • Where does my icon or library end up?
    Is it included in the eager bundle, lazy-loaded modules, or somewhere unexpected?

  • What is part of the eager bundle, and how can we optimize it?
    Breaking down the eager bundle to identify opportunities for lazy loading, tree-shaking, or other optimizations can significantly improve performance.

These are fundamental questions that need clear and actionable answers. Unfortunately, the existing tools fell short in providing the level of granularity and context needed to address these challenges effectively.

They primarily lack two critical features that are essential for effective bundle analysis in complex enterprise settings:

  1. No Direct Visualization of the Eager Bundle
    All the tools simply show the chunks generated during the build process, but they don’t provide a clear, consolidated view of what actually constitutes the eager bundle.

    And no, just checking the size of the main.js file isn’t sufficient. The eager bundle often includes more than just main.js. In fact, I’ve encountered apps where the main.js file was only 12 KB and contained little more than pointers to other chunks.

    Esbuild seems to use heuristics to optimize the main bundle, which means the true eager bundle can be spread across multiple files. Without a straightforward way to visualize all components of the eager bundle, it's challenging to identify optimization opportunities effectively.

  2. No Robust Filtering Mechanism
    Among the tools, esbuild-visualizer is the only one that offers a basic filtering feature. However, for our use case, it wasn’t powerful enough.

    We needed advanced filtering capabilities that allows us to search for specific libraries and drill down to see exactly where they are used and in which part of the app (eager or lazy) they end up.

    For example, if I want to track down where a shared library or an icon set is being included, the existing tools make it cumbersome and time-consuming to get a clear answer. Deep filtering with precise search functionality would be a game-changer for efficiently understanding and optimizing large-scale applications.

So, since I couldn’t find the tool I needed, I decided to take matters into my own hands and build one myself. Allow me to introduce the new kid on the block in the world of bundle visualization: Hawkeye! 🚀

Hawkeye — An Enterprise Esbuild Bundle Visualizer

Before we dive into the details of setting up Hawkeye, it’s probably time to give you a sneak peek at what the Hawkeye interface looks like.

To demonstrate its capabilities, I’ve uploaded a stats.json file generated from a mid-sized application with moderate complexity. While not overly complex, this app serves as a great showcase for highlighting Hawkeye’s features and how it visualizes bundles effectively. Let’s take a look!

Hawkeye EsBuild Bundle Analyzer aggregates all eager chunks and summarizes the total bundle size

On first glance, we can see some insightful metrics: the Eager bundle is 2.2 MB, while the Lazy bundle is 6.9 MB. Interestingly, the main.js file itself is only 523.6 KB. Hawkeye automatically extracts and composes everything that belongs to the main bundle, giving you a complete picture beyond just the size of main.js.

The interface also organizes chunks by size, starting with the largest. For example, we can see that chunk-JDQX3ANA.js is the biggest, weighing in at 1.4 MB. On the left, checkboxes allow us to isolate and display specific chunks, enabling targeted exploration. Additionally, the ruler in the top-right corner lets us align all chunks on a single row for a true side-by-side size comparison. This feature is especially useful for quickly identifying disproportionately large chunks.

Hawkeye offers even more functionality — like the sorting arrow in the top-right, which allows you to sort chunks in ascending or descending order by size. These tools make it easier to navigate and analyze complex bundle data.

Now, let’s put Hawkeye to work and uncover some actionable insights! 🚀

As mentioned earlier, chunk-JDQX3ANA.js is the largest chunk, coming in at 1.4 MB. Let’s dive in and figure out why it’s so big. The simplest way to investigate is to just click on the chunk. This opens up a detailed view, where Hawkeye breaks down the content of the chunk, showing which files, libraries, or assets contribute to its size.

This quick action allows us to immediately identify any potential culprits, such as oversized dependencies, duplicated code, or unused assets, enabling us to pinpoint optimization opportunities with minimal effort. Let’s take a closer look!

Hawkeye detailed view of used Libraries within a JavaScirpt chunk

In this case, we can instantly see that a custom icon library from my company is a significant contributor to the size of this chunk. We can now however each individual icon to see which ones are included.

With this information, we can take targeted action — such as optimizing the eager module by lazy-loading unused icons or implementing better tree-shaking practices to remove redundant code.

Of course, there might be cases where these icons are indeed necessary for the eager bundle. Even so, having this clarity helps us understand exactly where to look and ensures that informed decisions are made about bundle optimization. This kind of transparency is invaluable when dealing with large-scale applications and shared resources.

Let’s explore another common use case. Imagine you’re the author of a UI component library, and you want to ensure your library is tree-shakable. More specifically, you’d like to know which parts of your library end up in the main bundle, and in what size.

With Hawkeye, this analysis is straightforward. Simply use the search field in the top-right corner of the interface and type in component. This instantly filters the view, highlighting all instances where your UI component library is included in the bundle. You can now:

  • Verify tree-shakability: Check whether only the components actually used in the application are included in the bundle.

  • Assess bundle contribution: See the size of each component and its impact on the main bundle or lazy-loaded chunks.

  • Optimize usage: If unnecessary parts of the library are included, investigate why they weren’t tree-shaken out and consider adjustments, such as refactoring exports or improving build configuration.

Hawkeye with an applied filter to show the content of our UI component library

In the middle or right section of the Hawkeye interface, we can see that our components take up 62.6 KB. However, at this point, we don’t yet know exactly which bundle they end up in.

Here’s where one of Hawkeye’s neat tricks comes in handy: click on the components. A popup will appear, providing detailed information about the components and their placement in the bundle hierarchy. At the top of the popup, you’ll find a breadcrumb navigation that shows the hierarchy and lets you navigate up through the bundle structure.

Hawkeye overlay that shows the hierarchy of a chunk as a breadcrumb

Using this breadcrumb, it quickly becomes clear that the UI components are part of the main-HR7VBWDD.js file. This insight helps us confirm their inclusion in the eager bundle and allows us to assess whether they truly need to be there or if further optimization, like lazy loading, can help reduce the eager bundle size.

This feature not only helps identify placement but also makes it easy to explore and understand the full context of your bundle structure.

Getting started with Hawkeye

Want to give Hawkeye a try? The good news is, Hawkeye is completely free, so you can start exploring your bundles right away.

There are two ways you can use Hawkeye today:

  1. Web App: Simply head to the web app and upload your stats.json file. Hawkeye will process the file and provide you with a detailed, interactive interface to analyze your bundles.

  2. Command line / NPM Script: For a more integrated approach, you can install Hawkeye via npm. Running the script will automatically spin up Hawkeye in your browser, letting you visualize and explore your bundles directly from your development environment.

Hawkeye via command line

Hawkeye offers command-line support, making it incredibly simple to analyze your bundle from your terminal.

npx @angular-experts/hawkeye pathToTheEsBuildMetaJsonFile

Don’t let the package name fool you — we’re all about Angular, but this tool works seamlessly with React, Vue, or even plain JavaScript! All you need is an esbuild meta file, and you’re good to go. 🚀

But let’s be real — Angular is our favorite framework! ❤️ That’s why we’ve packed in some extra goodies just for Angular developers. 🚀

Hawkeye in Angular projects

When it comes to command-line support, it’s common practice to include an npm script that preconfigures the command for easy use. Setting up this command can be a hassle, so we thought — why not take care of it for you?

That’s where our init command comes into play. This command automatically sets up the npm script for you. With just a single command, you can configure everything you need without worrying about the syntax or consulting the docs. Just go ahead and run the following command inside your project’s root directory:

npx @angular-experts/hawkeye init

After running the setup command, you’ll be guided through a simple wizard. Just step through the prompts and answer the questions about your project setup. Based on your answers, Hawkeye will automatically configure the appropriate script for your workspace.

The script builds your Angular application with the esbuild meta file (stats.json) and named chunks. It will then invoke Hawkeye by running npx @angular-experts/hawkey with the path to the meta file. Hawkeye then opens in your browser, ready to visualize and analyze your bundles. 🚀

Once the setup is complete, you’re ready to analyze your bundles. Simply run the generated script.

Hawkeye via Browser

If you’re not ready to use Hawkeye via an npm script or the command line, no problem! Simply head over to hawkeyapp.dev and upload your stats.json file. Hawkeye will instantly visualize your bundle and provide the insights you need. 🚀

To build the stats.json file simply invoke a ng build with the --statsJson option set to true. When doing so we always recommend to also set the --named-chunks flag to true.

That’s it! Go ahead and give Hawkeye a try — it’s completely free and ready to help you optimize your bundles with ease.

Once you’ve tried it, let me know in the comments how it worked for you. And if you found Hawkeye helpful, please share this with your fellow developers! Sharing not only helps others discover the tool but also brings more attention to the project, helping us improve and grow it further. 🚀

Do you enjoy the theme of the code preview? Explore our brand new theme plugin

Skol - the ultimate IDE theme

Skol - the ultimate IDE theme

Northern lights feeling straight to your IDE. A simple but powerful dark theme that looks great and relaxes your eyes.

Prepare yourself for the future of Angular and become an Angular Signals expert today!

Angular Signals Mastercalss eBook

Angular Signals Mastercalss eBook

Discover why Angular Signals are essential, explore their versatile API, and unlock the secrets of their inner workings.

Elevate your development skills and prepare yourself for the future of Angular. Get ahead today!

Get notified
about new blog posts

Sign up for Angular Experts Content Updates & News and you'll get notified whenever we release a new blog posts about Angular, Ngrx, RxJs or other interesting Frontend topics!

We will never share your email with anyone else and you can unsubscribe at any time!

Emails may include additional promotional content, for more details see our Privacy policy.

Responses & comments

Do not hesitate to ask questions and share your own experience and perspective with the topic

Nivek - GDE for Angular & Web Technologies

Nivek

Google Developer Expert (GDE)
for Angular & Web Technologies

A trainer, consultant, and senior front-end engineer with a focus on the modern web, as well as a Google Developer Expert for Angular & Web technologies. He is deeply experienced in implementing, maintaining and improving applications and core libraries on behalf of big enterprises worldwide.

Kevin is forever expanding and sharing his knowledge. He maintains and contributes to multiple open-source projects and teaches modern web technologies on stage, in workshops, podcasts, videos and articles. He is a writer for various tech publications and was 2019’s most active Angular In-Depth publication writer.

58

Blog posts

2M+

Blog views

39

NPM packages

4M+

Downloaded packages

100+

Videos

15

Celebrated Champions League titles

You might also like

Check out following blog posts from Angular Experts to learn even more about related topics like Modern Angular !

Empower your team with our extensive experience

Angular Experts have spent many years consulting with enterprises and startups alike, leading workshops and tutorials, and maintaining rich open source resources. We take great pride in our experience in modern front-end and would be thrilled to help your business boom

or