To embark on our journey into the world of tree shaking in JavaScript, let's start with the basics. At its core, tree shaking is a technique used to eliminate dead or unused code from your JavaScript application. It's like pruning a tree to ensure it bears only the ripest fruits. In this case, the ripe fruits are the essential parts of your code, making your application more efficient.
Tree shaking can be a complex concept, but fear not, as we're here to make it as simple as a walk in the park.
Why it Matters
Now, you might wonder why you should care about tree shaking. Well, it matters because it can significantly improve your web application's performance. Imagine your website as a car, and the code as its engine. Tree shaking ensures that you're not carrying around spare parts that you'll never use, making your car faster and more fuel-efficient.
Understanding Tree Shaking
What is Tree Shaking in JavaScript?
Tree shaking, also known as the removal of unused exports, is a process that prunes away unnecessary code from JavaScript bundles. This technique, popularized by Rollup and adopted by Webpack, aims to make your JavaScript bundles leaner and meaner.
Why Do We Need Tree Shaking?
Efficiency is the name of the game. Keeping your production build as lightweight as possible is crucial. A lighter build is quicker to download, process, and execute, enhancing the overall performance of your web application.
Consider this: in a 2018 survey, the average compressed JavaScript bundle size on mobile devices was around 350kb. When uncompressed, this figure ballooned to 800kb to 900kb. This bloated code is transferred to the user's device, where it is uncompressed, parsed, and executed, all of which can be quite taxing on performance.
With the rise of modern JavaScript frameworks and the move towards component-based development, code is often abstracted into separate files. While this approach has its benefits, it can lead to a new challenge. Each component may contain unused code that other components don't require. This unused code, when included in the build, increases its size, negatively impacting performance.
For instance, imagine a utility file containing various functions:
// utility.js
export function foo() {
console.log("I am foo");
}
export function bar() {
console.log("I am bar");
}
Now, if you import the foo
function in another file:
// main.js
import { foo } from './utility.js'
foo();
During the final build process with Webpack as the bundler, you'll find that even though the bar
function is not used, it's still included in the final build, annotated as an unused function.
This is where tree shaking comes to the rescue, allowing us to remove such dead code efficiently.
How Does Tree Shaking Work?
The effectiveness of tree shaking is closely tied to the introduction of Import and Export modules in ES6. This static module system enables tree shaking to function optimally.
Before ES6, dynamic imports of CommonJS modules made it challenging to determine which modules to include or exclude at build time. These decisions were made at runtime, hindering tree shaking.
With ES6 modules, the global import of all required files at the top of your script became the norm. This made it easier to identify and eliminate unused code. It's akin to modern IDEs and linters, which highlight unused code within your files.
Bundlers like Webpack are adept at tree shaking, efficiently removing almost all unused imports or code, including properties that are exported but not imported anywhere.
For example, if you have a property that's not imported, it's considered unused and will be removed in the tree shaking process:
// person.js
export const Person = {
name: "Vivek Upadhyay",
passion: "Blogging"
}
// main.js
import { name } from './person.js';
console.log(name); // "Vivek Upadhyay"
Webpack and Rollup come with built-in support for tree shaking in production mode, making this optimization process seamless.
Handling Side Effects
Not all code is created equal. There are two types of functions: pure and impure. Pure functions produce predictable results and can be safely removed as unused code. Impure functions, on the other hand, may have side effects and cannot be removed.
In the realm of tree shaking, side effects need to be managed properly. For instance, if a function modifies a variable outside of its scope, it's considered a side effect. ES6 modules can also have side effects, such as polyfills, where it's unclear when and where they'll be used.
To address this, you can inform Webpack about your code's side effect status in your package.json:
// package.json
{
"sideEffects": false
}
Alternatively, you can specify which files have side effects:
// package.json
{
"sideEffects": [
"./polyfills.js"
]
}
In Conclusion
Tree shaking is an essential tool in the arsenal of frontend developers striving for optimal web application performance. By eliminating dead code and unused exports, it streamlines your JavaScript bundles and ensures a faster, more efficient user experience. If you found this article insightful, feel free to share it within your network. And remember, an optimized, performant web application is just a tree shake away!