Analyzing Your Webpack Bundle Like a Pro
Recently, I was deep in debugging our fairly large React application that we have here at Outreach when I noticed some unusual behavior from React Developer Tools. Upon investigating further, I discovered that React Developer Tools was attempting to connect to a different React renderer. Which renderer, you might wonder? It turns out, it was attempting to connect to the renderer originating from
To put it simply, due to certain race conditions, it was randomly selecting either our main React renderer or the TestRenderer. This behavior was definitely unexpected — after all, the TestRenderer should only be utilized in testing scenarios. So, who was importing it? And why?
To start with, I verified that indeed we had bundled
As part of our CI pipeline, we utilize the Webpack Bundle Analyzer to generate outputs. With this tool at hand, I could easily use its built-in search feature to confirm my suspicions. Snap!
Now that we’ve identified the issue, the next step is to uncover how this undesired dependency made its way into the bundle. You might be tempted to simply use the search function in your IDE, and if you’re lucky, you might stumble upon its usage in
App.tsx. However, in most cases, it’s not so straightforward. Our monorepo contains over 1 million lines of TypeScript code, which made me quickly realize that a more sophisticated approach was needed. 🤓
Enter Statoscope. All we require are the stats data from Webpack. The process is relatively straightforward (although in our case, we had to chain this command with
— max-old-space-size to avoid running out of memory — a challenge we managed to overcome 😀).
webpack — json stats.json
Once we possess our
stats.json file (ours was a whopping 2.1 GB), it’s a simple matter of dragging and dropping it into Statoscope — rest assured, it’s a local-first application and no data is uploaded, so don’t worry it takes just a few seconds. With Statoscope, we can then examine why the particular module was required.
In our scenario, the root cause was clear:
react-test-renderer was being required (as part of React Testing Library) within a
util file that was utilized by both tests and app code. Because the code wasn’t effectively tree-shaken (given that it’s a third-party dependency and Webpack, which plays it safe, can’t be sure it doesn’t consist of side effects), it unintentionally became part of the bundle itself.
P.S: Statoscope also provides CLI tools that can seamlessly integrate into your CI/CD system, ensuring that no such unwanted dependencies make their way into the production bundle. This serves as a valuable safeguard to prevent such occurrences in the future.