Brief introduction to scope hoisting in Webpack

On its third major release, Webpack introduced a new feature: scope hoisting. Many developers are already exposing data showing great positive impacts on the initial execution time of their bundles.

But what is it, and how it works?

To answer this questions we first need to understand what happens with our code when we bundle it.

This article assumes solid understanding of closures and modules notation in Javascript.

Your bundles, under the hood

Here is a quick example of this transformation:

… which turns into this:

Basically modules get wrapped into functions isolating their scope while imports get transpiled into variables holding the result of a Webpack require function.

All our wrapped modules go to an array at the end of our bundle, that’s why this featured function receives an index as a parameter.

On top of this array, Webpack adds some overhead code to go over this array and run our code.

Here is a simplified version of it.

Simplified version of Webpacks code to handle modules

A lot it’s happening here. Let’s break it down!

First, an object is created to save the result from already accessed modules.

Below, the method which replaces import statements gets declared. This method calls the function wrapping the module and populates the exports object, or returns its cached value if it was already required.

At the end, this method is called again, but this time with our entry point module index to kick off our application.

Experience and tradeoffs

In our bundle, each import translates into an extra function call and a property access to the modules array as Webpack gets to the end of this import chain.

These constraints have been meassured in the past, like Sam Saccone detecting 400ms were spent only in Browserify module require in Tumblr or Nolan Lawson exposing brenchmarks on different bundlers.

But we still need modules. On big projects performance is a price we pay in exchange for better codebase scalability and encapsulation.

What is scope hoisting?

Let’s picture the previously described situation where a method needs to import another.

If scope hoisting is enabled, Webpack here will see the opportunity to save one require method call by inlining the helper method like this:

No call to Webpack’s require function, no access to the modules array… Faster!

We not only save an extra function call, but also an access to the modules array, so our code runs faster than before.

How to enable scope hoisting

This optimising technique might break in some edge cases, that’s why Webpack did a major release.

Make sure to run some tests and share the results with the Webpack team, they will love your feedback!

No time to help contribute? Want to give back in other ways? Become a Backer or Sponsor to webpack by donating to our open collective. Open Collective not only helps support the Core Team, but also supports contributors who have spent significant time improving our organization on their free time! ❤

webpack

The official Medium publication for the webpack open source…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store