Magento 2 : Does javascript bundling make any difference?

Abhishek Jakhotiya
5 min readJun 26, 2022

There are currently 4 ways to deliver javascript in Magento 2.

  1. Don’t bundle or merge at all.
  2. Use built-in bundling.
  3. Merge javascripts.
  4. Use a tool like Baler, Magepack, Or do it yourself by following this

Should you even care about how javascript is being delivered? Well, if LCP of your page sucks (More than 3 seconds) , forget about bundling your javascript, focus on improving LCP. Of all the performance parameters, lighthouse gives 30% weightage to LCP and only 10% to time to interactive.

I am not undermining time to interactive at all. If user sees page in 2 seconds but no click works until 14th second, chances are, user will get frustrated.

Once your LCP is below 3 seconds, try improving Time to interactive without degrading LCP.

When you use Built-in bundling or merge javascript setting given in Magento, huge render blocking resources are added to head of the page. This will degrade your LCP. Merging and Built-in bundling both ship even unused javascript to the page. Even a tool like Baler or Magepack will add small render blocking javascripts.

Magento has an interesting setting called “Move scripts to bottom”. You can enable this setting by running

php bin/magento config:set dev/js/move_script_to_bottom 1
php bin/magento cache:flush

When you turn this on, Magento will push all scripts to the end of the page. This will further improve your LCP but further degrade time to interactive.

When you move all scripts to bottom, browser will download these scripts very late. You can fix that by preloading them. Keep in mind that you have to preload them without affecting LCP.

Now before we talk about Time to interactive, I warn you about “Move scripts to bottom” can be buggy in scenarios where you have require scripts written in ESI blocks or blocks that have a TTL. One example of this is navigation menu. For example, following script in ESI block like navigation menu

require(['jquery'],function($){
console.log('hello');
})
//THis is navigation menu will break with 'function require not //definted error

The script shown above will break your page if, You are using varnish or CDN like fastly and this script is rendered by a ESI block like catalog navigation menu.

That happens because Magento moves scripts to bottom before the page reaches varnish or fastly. Once the page reaches Varnish, Varnish will look for ESI tag and fetch block associated with that tag from the Magento. Next, Varnish will combine the fetched block with rest of the page. As a result, Javascript written into ESI rendered block will be up in the page, even before Requirejs initialization. Ideally, prefer x-magento-init over direct require call.

Now, lets talk about Time to interactive. If you don’t bundle at all then, Requirejs will keep making network calls for dependencies as it discovers them. All knockout text templates are requested with XHR and aren’t cached. All of this happens in a waterfall model. One request after another. This will delay time to interactive. Imagine landing on the website, scrolling a bit but when you try clicking burger menu, it doesn’t work! That’s why we wanna bundle javascript. Let’s discuss following 3 approaches

Enable javascript merging

One option you have is turn on javascript merging.

php bin/magento config:set dev/js/merge_files 1
php bin/magento cache:flush
Javascript merging turned on generates merged files

As you can see, magento has generated a merged file and if you look at the contents, it has merged require.js and require-config.js .

This generation of merged file happens during the main page request. This can significantly slow down your page response time. Imagin using glusterfs on aws for your static content, you will see significant increase in page response time.

Merging does not happen during static content deploy, it happens during main page render

Magento’s in-built bundling

All kind of bundling, be it buit-in bundling or be it using tools like magepack, happens during static content deploy phase.

To turn this on run

php bin/magento config:set dev/js/enable_js_bundling  1
php bin/magento cache:flush
php bin/magento setup:static-content:deploy
Built in bundling

As you can see we are delivering 3 times more javascript compared to simple merging. This is very bad for performance. The real effect on performance can be seen on mobile devices or desktop with average hardware.

Advanced Javascript bundling

Through tools, you collect information on javascript modules that are common to all pages and javascript modules that are page specific. Bundles include only what is needed on the given page.

As the name suggests, it is really “Advanced” javascript bundling. It gives you much better performance but it has it’s own gotchas. But if you can get this right, it has great impact on performance. Javascript heavy pages like “Checkout” will greatly benifit from this. Back in 2016, this was a painful activity documented in magento devdocs. Magepack automates this. Advanced javascript bundling also bundles your text html files along with javascript. Advanced javascript bundling has two phases.

Gather information on common javascript modules and page specific modules

In this phase, the tool must crawl given pages of your website to gather information on what will go into 5 bundles.

  1. common bundle
  2. cms bundle
  3. category page bundle
  4. product details page bundle
  5. cart/checkout bundle

After crawling these pages, the tool create a dependency distribution. It’s a simple config file which describes, which javascript and html templates should go in which bundle.

Bundle generation and optimization phase

Once the tool has decided what should go in which bundle, it will use requirejs optimizer (r.js) to create bundle files. These bundles are then configured in require-config.js file. Next you may choose to uglify/minify these bundles. Note that this kind of bundling is a requirejs library feature. It’s not a magento specific feature.

If you are using a tool like magepack this process happens with three commands.

php bin/magento setup:static-content:deploy;
magepack generate
magepack bundle
/* This also requires you to install magepack magento extension along with the magepack npm package */

If you want your production websites to benifit from this, this whole mechanism has to be part of your build step. This means your build environment must have nodejs and magepack installed.

While Advanced javascript bundling is great if done right, there are two gotchas to be aware of:

  1. Even if one of your javascript bundle file has a javascript module which throws an exception, nothing else will work. This is because, the javascript execution for that script is halted on exception.
  2. If there is render blocking javascript written using `require([‘something from bundle’],function(){//your code })` pattern, the whole bundle will be downloaded and parsed and compiled. Although not a very significant trade-off, the impact depends on how big your bundle is and what are your modules doing.

Finally, in my next post, we will talk about Bundling with Magepack. I will link it here when it’s ready.

--

--