Javascript Bundling in Magento 2

Javascript bundling is a technique that groups separate files in order to reduce the number of HTTP requests that are required to load a page. Bundling is commonly used in today’s “module-based” development where some functionalities are basically split into Modules (roughly explained). For loading modules, we usually use some of popular module loaders such as rollup.js or RequireJS (which is Magento’s weapon of choice).

HTTP2 is here so this technique will be probably deprecated in the future. You could still use bundling for reducing the number of requests for a specific page but I don’t think it will be worth of it.
Right before we start with “reverse” optimisation, we can use bundling to help us organise our assets and serve less files to the client which will (should) result in faster website.

One of our services is Technical audit which covers various tests on both Frontend and Backend part of the client’s store. Since i’m Frontend Developer, performance is my key point during analysis.

First thing I check is wether Javascript and CSS files are merged/minified/bundled (hello bundle). When I was Junior Developer, I was so happy/angry when I discovered someone didn’t turn these ON since I was thinking that technical level of Developers who worked on site was low and we can do a lot to improve site… and of course, I could get a “quick win” with turning merging/minifying ON.

Well, in theory that was great. Usually I was right about their expertise level but I was wrong about one thing – they didn’t “forgot” to turn these ON.

Explaining to the client that you would probably have to refactor 80% of the code to change that “simple option” is something I wouldn’t want to go through again.

We were doing Technical audit of the Magento 2 store and when I found out that Javascript and CSS files were not merged/minified/bundled I was in shock and first question that was going through my head was “shall I report this to the client?!”.

Strange question, I know. But it does make sense because if I report it, I’ll have to fix it.

Just kidding, of course this was included in our report and was first thing I changed when we took over the project.
How did it go? Well, do you write articles about stuff that work as expected?

Magento 2 Bundling

I must note that official docs do not give us a lot of information and there are only few discussions online about it.
Therefore, I may be wrong in some of my conclusions so feel free to correct me in comments 🙂

For start, let’s see 2 proper ways to load assets in Magento 2.
In this example, you can see how assets are loaded on two different Magento pages – Homepage and product page.

As you can see on example above, requireJS loaded different assets through different pages while all bundles were loaded regardless of wether they are needed or not.
With RequireJS, we can load specific JS modules on specific pages which means you will load only necessarily assets and reduce number of requests.

(If you wish to know more about how to load Javascript files with RequireJS, you can read this excelent article from my coleague Domagoj Potkoc. )

While RequireJS did help us with reducing number of requests through the page, we still have few JS files being loaded and “few” in Magento 2 means 40-50. We need a way to merge those assets into just few files. We need to create 5 files out of 50.
Files are being loaded asynchronously but still, if we could merge these files into just few, we could improve performance even more.
Bundling comes as a problem solver since it is used to merge modules and it dependencies into single file.
Bundling denies main benefit of using module loaders such as RequireJS since assets aren’t loaded asynchronously. Bundles are included with <script> tag, inside <head> section of the page.

So, why use it?

With bundling we could decide on where to load specific bundle and that’s the best part of it! For example, we want to put all checkout-related stuff into one bundle and load it only on checkout page!

Feeling happy?

Well, Magento folks didn’t implement RequireJS optimizer which is required for ordering and organising module load across different pages. You can exclude some scripts from bundle but you CAN’T decide on bundle content for a specific page.

So, why use it?

With Merging, you can only merge Javascript files that are NOT being loaded through RequireJS. If you wish to “merge” JS modules, you will have to use bundling.

You probably have so many questions in your head right now. So do I. And I’m still searching for the answers.

Here is a random Zen image, just to chill you down.

Bundling misses key features (imho) but you can still change few things in order to organize your bundles.

Bundle size and exclude list

In Vendor/Theme/etc/view.xml you can change bundle size and exclude some scripts from bundle.

Default size for bundle is 1MB.
Bundle size determines number of bundles that will be created. For example, if you have 4MB of script files and bundle size is set to 1MB, you will have 4 bundles created.

If number is too low, you will probably have 10 and more small bundles which will block each other during rendering so be careful with this.
Remember that bundles are not loaded asynchronously.

We can also exclude certain scripts from bundles. They will be loaded with RequireJS when needed.
Keep in mind that Luma and Blank themes have their own exclude lists and if you are not properly fallbacking and don’t have your own exclude list, bundles will be huge since all JS modules will be bundled, regardless of whether you need them or not.

<exclude> handle takes care of files that should be excluded from bundle. As far Magento 2 is concerned – since we can’t decide on bundle content for each page, at least we can exclude assets that will not be required through the whole site, therefore bundles will consist only files that are required everywhere. As you can see in above example (Luma theme exclude list), jQuery assets are probably required everywhere so i don’t understand idea behind excluding these from bundles. Probably Magento folks wanted to leave most important stuff under RequireJS control.

Activating bundling

After we have configured our bundle size and exclude list, it is time that we turn bundling on and enjoy great performance impact.

We can turn bundling on here: Stores > configuration > advanced >developer

After bundling is ON, clear cache and switch to production mode (bundling will not work in “Developer” mode). Static files will be deployed and you will see your bundles being loaded on the Frontend.

What about performance?

We did a lot in order to reduce number of requests through the site. But, there is one small problem with performance.

This is Homepage of the Luma theme.
Testing was done on Magento 2.2.0 “dev” version, with following setting in Dev console (Chrome):

Before turning bundling ON:

  • Number of JS requests : 137
  • Size: 2.0MB
  • Loadtime: 9.46sec

With bundling turned ON:

  • Number of JS requests : 8
  • Size: 4.2MB
  • Loadtime: 20.12sec

Take a look at size and load time?
We did reduce the number of JavaScript files being loaded, but the total filesize of generated bundles is larger than the total filesize of all non-bundled JavaScript files on the frontend.
Reason? With RequireJS you load only needed JS files on a specific page. Bundling merges all JS  assets and serves them on all pages.

Conclusion

I must say I am disappointed with bundling, especially with the fact that we don’t have RequireJS optimizer by default. Without it, whole idea behind bundling is missed.

Pros:

  • Bundles multiple files into single file

Cons:

  • negates benefits of using module loader
  • filesize of bundles is larger than all non-bundled javascript files size in total (per page)
  • you can’t define bundle content precisely
  • you can’t decide in which pages which bundle will be loaded

I don’t see any reason we should use bundling right now.
Bundling will make sense in the future if Magento folks create additional functionalities for us to use.
We need configuration file where we will be able to decide on :

  • number of bundles
  • bundle size
  • bundle content
  • which pages specific bundle will be loaded

Thanks for reading and i hope we can roll up some discussion about this topic in comments 🙂