Our Journey in Optimizing and Bundling JavaScript for Web Applications
When building a web application, optimizing the loading process is important.
Previously, we used Uglify-ES and recently Terser to minify individual JavaScript files to help reduce the packages and load time.
With the next release of iPhora Automatic coming very soon, we wanted to significantly reduce the loading time needed and the number of HTTP requests handled by the Domino server.
Our struggles for the past few weeks have been figuring out the right JavaScript bundler that works with our Dojo Toolkit-based framework.
So why are we still using Dojo Toolkit you might first ask? Many have moved away from Dojo Toolkit, the granddaddy of JavaScript frameworks. Dojo provides us the core widget inheritance framework that is not just used for creating widgets like fields and combo boxes, but is used for building the many different app layers of iPhora not just statically but dynamically in real-time. It allows us to have a secure and fast SPA (single page application) architecture. We don't use any of the original Dojo widgets (Dijits). Each widget that appears in the UI is a custom widget object that is built specifically to work within our framework.
We first looked at Webpack which is probably the most popular JavaScript and resource bundler. IBM/HCL created the dojo-webpack plugin to bundle and minify Dojo Toolkit based applications and is still in use. We got dojo-webpack working with the latest version of Webpack, v5.98 and Dojo 1.17.3. But we had to upgrade to Node 18.20.8 and NPM 9.3.1. This reduced the loading time from 4.5 to 3.5 seconds.
Everything was great until a user try to navigate to different parts of the iPhora interface. Our iPhora SPA framework relies heavily on Dojo Require to dynamically load different parts of the UI. These modules may or may not exist when a bundle is created. In fact, for each instance the modules are totally different. So we went deep dive into the Dojo code and the dojo-webpack code and attempted many hacks. After many many tries, I was informed that one cannot dynamically load AMD (Asynchronous Module Definition) modules when bundling with the dojo-webpack plugin. Unfortunately, Webpack replaces all Dojo Require with their own Webpack require which only allow static modules. So frustrating.
Since Webpack does not address our requirements. We looked at newer bundlers like Vite and Pascal, but that was going to require a significant effort since no one has a Dojo plug-in. The biggest struggle was finding examples and answers to questions.
Since the Dojo Toolkit comes with a bundler, we went back to looking at it. However, much of the documentation and examples are very simple as usual and limited. Much of the content was older and incomplete.
The advantage of the Dojo Build framework is that it allows you to create independent bundles called layers which conforms to how we are using Require to load the AMD modules. It uses the Google Closure compiler which is much more restrictive than Uglify-ES or Terser (used in webpack). We have been using Uglify-ES and then later Terser for a long time, but Closure does a better job in finding errors.
With Dojo Build we are able to build a custom dojo bundle that includes only the dojo modules that we needed and the individual modules that contain our initial loader and custom iPhora widgets.
So here are the results.
Before Using Dojo Build Bundling
Comments