Skip to Content

Webpack in Salesforce Commerce Cloud: Solving the need for speed

Capgemini
2019-12-29
The Case for Performance

In digital, every second matters. In fact, Mobify found that only a half second variance in page load times can significantly impact conversion rates: an impact that can easily equate to hundreds of thousands of dollars in lost revenue. If a mobile user has to wait more than three seconds for a page to load, there’s a fifty-fifty chance they’ve lost patience and abandoned the effort to load your page entirely.

These findings aside, it’s self-evident that page load speed and responsiveness are absolutely critical to providing an experience that drives deeper engagement and leaves the end-user coming back for more. However, it’s a difficult endeavor to design and develop eCommerce sites that provide a feature-packed and content-rich experience while also staying mindful to performance. How can we continue to focus on implementing complex features, integrating advanced front-end services, and provide high-quality site aesthetics without sacrificing speed and convenience?

Why Webpack Helps

The speed at which the browser is able to load, process, and render any page on the web today is dependent on the amount and size of the resources that are returned to its initial request.

In the past, it was acceptable to return a monolithic JavaScript and CSS file, i.e. main.js and global.css, containing the contents of the entire application for the browser to process on every page request. However, as complexity continues to increase, and thus the amount of code within a web application, this will severely impact performance.

To launch robust, content-rich experiences that also render and load quickly, merchants need a build system that generates optimized code for the browsers’ processing capabilities, intelligently splits code across multiple files to take advantage of modern networking protocols, and effectively identifies and eliminates unused code. Webpack steps in to fulfill the requirements of this system and more.

Webpack defines itself as “a static module bundler for modern JavaScript applications”. In other words, it scans over every JavaScript file (modules) within a web application, optimizes the code, and generates new files (bundles) containing those JavaScript files in a way that promotes top-notch performance for browser consumption.

Webpack doesn’t just stop at JavaScript files though. The tool is highly configurable and can be extended to support many different assets such as stylesheets, fonts, and even images.

Let’s cover the basics of a Webpack configuration in-detail and take a look at its advanced features that provide the boost to performance.

The Basics

There are four core configuration concepts behind Webpack: entry, output, loaders, and plugins. The first two concepts are autological but still deserve a proper explanation.

Entry

The entry configuration tells Webpack on which file to begin its bundling process and provides the contextual root of the web application. The magic behind Webpack comes from its idea of building an internal dependency graph from this entry point. Webpack does so by recursively identifying all dependencies within the web application starting from this file with the purpose of producing optimized output bundles. Recall that these dependencies are not limited exclusively to JavaScript files but can be any type of supported assets like stylesheets or images.

Output

The output configuration simply tells Webpack where to emit, and how to name its generated bundles. Note, that a bundle is simply the naming convention Webpack places on the JavaScript files it outputs. These bundles are creatively crafted to help the browser make light work when it comes time to parse them.

Loaders

Adding loaders to the mix extends Webpack’s ability to interpret and process different types of assets. By default, Webpack only understands JavaScript and JSON files. Loaders provide transformation logic to convert a given file type into a valid module that can be added to the dependency graph. For example, cutting-edge ES6+ JavaScript can be transpiled by a loader to produce JavaScript that will be widely supported by all browsers.

Plugins

Plugins are provided to the configuration to fill in any limitations of the loaders. They “plug into” Webpack’s compiler and can “listen” for the emission of certain events. Thus, they can be utilized to perform a specific task at a certain point in the build process, like fine-tuning bundle optimizations. Or, they can go to work over the entire build process to provide features like advanced logging and statistical analysis of bundle creation.

Code Splitting

With minimal changes to the out-of-the-box configuration, code splitting is a solution Webpack offers to further reduce the outputted bundles’ sizes beyond the default, built-in optimizations.

The key insight here is that the entry configuration of Webpack also accepts the passing of multiple entry points where each supplied entry point generates its own dependency graph and subsequent output bundles.

In a multi-page web application (the norm for large eCommerce sites), development efforts can manually divide the code into modules that are specific to a designated page. Each of these page-specific modules may then be passed as an entry point to Webpack to generate bundles unique to certain pages. This achieves smaller bundles and controls resource load prioritization per page, which, if used properly, can have a major positive impact on load time.

Combining this technique with the usage of the built-in plugin, SplitChunksPlugin, will take this optimization a step further. Enabling SplitChunksPlugin instructs Webpack to compare each internal dependency graph of these page-specific modules and extract shared application code amongst them into a single bundle. This effectively removes any possible duplication of logic and ensures minimal bundle sizing.

Webpack also supports dynamic imports by splitting dynamically loaded modules (logic declared unnecessary for the initial page load by a developer), into separate bundles to be lazy-loaded at a later time. This concept is coined as dynamic code splitting.

For instance, the code required to support the opening of a modal, and the generation of dynamic content within it when clicking a button, can be delayed past the initial page load as it doesn’t contribute to the initial experience. Essentially, there is no reason for the page to try and load the data if it is an optional, later interaction.

Webpack can identify this code, separate it into a small, singular bundle, and only retrieve it when the button is clicked. If dynamic imports are implemented for all components on a page that do not contribute to the initial page experience, load times can be reduced significantly, thereby keeping users engaged as they move throughout the site.

Tree Shaking

Through the usage of ES6 modules, Webpack’s tree shaking abilities are enabled. Webpack has a nice, little metaphor in its online documentation on this functionality:

“You can imagine your application as a tree. The source code and libraries you actually use represent the green, living leaves of the tree. Dead code represents the brown, dead leaves of the tree that are consumed by autumn. In order to get rid of the dead leaves, you have to shake the tree, causing them to fall.”

Tree shaking is simply the process of eliminating unused dependencies, dead code, from a project.

In certain situations, this can greatly reduce the overall size of a web application. For example, if a developer pulls in multiple large, third-party libraries to aid in the development of advanced site customizations, but only uses a fraction of each library to accomplish the task only the code utilized remains in the application after Webpack emits its bundles. Again, Webpack grants the assurance that only the code contributing to a user’s experience is shipped to the browser.