Shaking the dependency tree

How a small change can have a big impact

Alejandro González S.

Multimedia Engineer

Context

We’re working in a monorepo with Turbo, where multiple Next.js applications are located in the apps folder.

We have a shared component library in the packages folder that is used across all these applications.

Context

The development process was being slowed down due to incorrect imports of Material UI Icons in the component library, impacting performance significantly.

THE PROBLEM

Incorrect Import

Why This Is a Problem?

The trailing slash at the end of the import path forces the entire package to be imported instead of just the necessary icons.

Consequence

Each Next.js app was loading and compiling thousands of unnecessary modules, making the development environment slow and heavy for the machine.

correct Import

Why Does the Trailing Slash Matter?

  • The trailing slash tells the module system to load everything in the package.
  • Instead of fetching just the CheckBox, CheckBoxOutlinedBlack and InfoOutlined it pulls all icons from Material UI, preventing tree shaking from working correctly.

What Is Tree Shaking?

Tree-shaking is a technique used in modern web development to eliminate unused code (dead code) from the final bundle. It can significantly reduce the size of the bundle, resulting in faster load times and better performance.

Dead code refers to the code that is not executed or used during runtime. For example, if a module exports a function that is never called in the application, then that function is considered dead code.

EXAMPLE

The Impact of Not Applying Tree Shaking

Without Tree Shaking you’re pulling in unnecessary code, which:

- Increases bundle size.

- Slows down compilation.

- Causes longer load times.

bundle size without tree shaking

The Fix: Correct Import and Optimization

  • Optimizing Imports:

    • We fixed the incorrect imports to ensure tree shaking works as expected, limiting the imported icons to only the required ones.
  • Additional Optimization in Next.js:

    • We configured the optimizePackageImports setting in Next.js to handle the packages imported from the packages folder efficiently.
    • This ensures that only the necessary modules are loaded in each app.

Instead of grabbing the whole Lego set, we only select the exact pieces we need—this is like optimizing imports.

bundle size with tree shaking

Comparison

-63.2%

-82%

-85.7%

Raw size generated by Webpack.

Size of the file in the browser memory when it is being executed.

Size of the file when compressed to reduce weight in network transfer.

Time and Cost Benefits

  • Time Savings:

    • Faster Builds: Reduced unnecessary modules speed up development and build times.
    • Quicker to Market: Shorter build times allow for faster feature delivery.
    • Significant Improvement: Reduced from compiling 30,000+ modules per app to just 4,000–5,000 modules.
  • Cost Savings:

    • Lower Infrastructure Costs: Smaller bundles reduce CPU and memory usage on build servers.
    • Bandwidth Efficiency: Smaller bundles mean faster load times and significant bandwidth savings, especially for users with slower connections.

Conclusions

  • Lessons Learned: Small mistakes in how you import modules can lead to major performance issues.
  • Tree Shaking Matters: Prevents unnecessary code, improving performance.
  • Time and Cost Savings:
    • Faster Builds and Quicker Feature Delivery.
    • Lower Infrastructure Costs and Reduced Maintenance.

Thank you

Alejandro González Suárez

Multimedia Engineer

Made with Slides.com