Large enterprise applications often include millions of lines of code, and offer many specialized features for different constituencies. While these apps are crucial to the business, they can also get a reputation for loading slowly and offering poor performance to users.
All of the functionality is important, but very few individual users will utilize all of that functionality. In fact, on any given day or interaction with the app, a user will typically use just a small subset of it. They likely only care about how the app behaves on their particular client or device, for example, and the functionality related to whatever task they happen to be performing.
You could break the app into smaller, more focused apps but that forces users to remember which app does what they need. A better approach is to keep everything in the same app but improve it, so different functionality can be loaded only when it’s needed. Users have access to everything they need, without getting bogged down by the parts they won’t use.
Ext JS has long supported the concept of packages which provide modular functionality such as resources, styling, and code. Those packages have typically been incorporated by Sencha Cmd at build time, which doesn’t enable developers to control the user experience dynamically.
Table of Contents
Dynamic Package Loading with Sencha Cmd 6.5
With Sencha Cmd 6.5, we’ve added support for dynamic package loading – enabling developers to better control the startup time and network footprint of their apps. Developers still define which packages are used by the app, but Sencha Cmd can now work with a dynamic package loader class that manages dependencies at build time, but it doesn’t force apps to load all the packages at startup. Instead, the developer can implement logic that loads packages – with any necessary dependencies loaded automatically – at an appropriate time in the application workflow. For example, a resource-heavy data visualization might be loaded only on a large screen and when the user activates the appropriate menu or tab. On devices with small screens, a different package might be loaded.
The rest of this post will use a simple sample app to show how you can leverage dynamic package loading in your own apps.
Example App Walkthrough
Our sample app is available on GitHub. If you clone the repo, it will contain everything you need except for the Ext JS bits. Please follow the instructions in the project’s README if you’d like to run it yourself.
If you’re adding dynamic package loading to your own app, you’ll need to start with a package to add. Probably the easiest place to start is creating a new package with Sencha Cmd:
sencha generate package -require NewDevCard
Where “NewDevCard” is the name of the package, and we’ve used the -require
option to avoid automatically adding the package to the requires
array in the project’s app.json
. Packages included in the requires
array will be automatically loaded at startup – exactly what we’re trying to avoid.
Instead, we’ll add our dynamic package loader to the requires
array in our project’s app.json
:
"requires": [ "package-loader" ],
Now, we’ll add the package to the “uses” array:
"uses": [ "NewDevCard" ],
The Ext.Package.load()
method then makes it trivial to load packages when you’re ready for them. The package loader handles the package’s JavaScript and CSS assets as well as recursively loading any packages that it may require.
In our sample app, we load the package when the user opens a tab which uses the package. Most of the code goes into the controller, which we’ll detail below. In the view, we add a property pkg to the config object for the panel displayed in the tab (from view/main/Devcards.js):
}, { // the contact tab using data from the developer record xtype: 'panel', pkg: 'NewDevCard', layout: 'fit', title: 'ContactFromPkg' }
The pkg
property doesn’t have any special significance; we just coded the controller to use that property as an indication that the panel uses a dynamically-loaded package.
The controller (view/main/MainViewController.js) contains the bulk of the package-handling code. We use the requires
array to ensure the package loader is available:
requires: [ 'Ext.Package' // from "package-loader" ],
We set up a handler for tab activations which ensures that the package is appropriately loaded:
onItemActivate: function(sender, value, oldValue, eOpts) { let tabpanel = sender; let tab = value; let pkg = tab.pkg; if (pkg) { if (Ext.Package.isLoaded(pkg)) { this.handlePackage(pkg); } else { tabpanel.setMasked({ message: 'Loading Package...' }); setTimeout(()=>{ Ext.Package .load(pkg) .then(this.handlePackage.bind(this, pkg)); }, 250); } } }
If the tab we’re activating has the pkg property set, we first check whether the specified package is loaded. If not, we mask the tab and use Ext.package.load()
to load the package. When it’s available, we use this.handlePackage()
to activate the loaded package.
handlePackage: function(pkg) { let tabpanel = this.lookupReference('main-tabpanel') let tab = tabpanel.child('[pkg=' + pkg + ']'); tabpanel.setMasked(null); //only add item if the item isn't already added if (!tab.hasPkgItem) { tab.hasPkgItem = true; tab.add({ xclass: 'MyApp.view.' + pkg.toLowerCase() + '.Main' }); } },
First, we identify the correct tab and unmask it. Unless we have already processed the package for the tab, we add the MyApp.view.newdevcard.Main
xclass to the tab to activate the package code.
In terms of coding, that’s basically all that’s needed:
- In
app.json
, requirepackage-loader
anduse
the package (NewDevCard). - In the controller, require
Ext.package
and add some logic, soExt.package.load()
loads the package at an appropriate time. - Use the newly-loaded package in the app.
Now we just need to build and package up the app. The normal way of making a development build is with sencha app build --dev
. This includes packages specified in the requires
array, ensuring that everything is included. When using dynamic package loading, we need to add the --uses
option to ensure that the packages specified in the “uses” array are also included in the build.
The following command will perform a full development build of the application, including (but not automatically loading) all of its external packages:
sencha app build --dev --uses
The application and each of the use
packages will be placed in separate bundles. When your application loads, it will include only its code and the code from its require
packages. The JavaScript, CSS, and resources for the use
packages will be in the application’s build folder just like images or other assets.
Running the dev server as usual, with
sencha web start
will automatically serve up the app and handle asset dependencies and use
packages as required. In production scenarios, you can include the bundled packages along with your other assets to be served up by your production server.
See It In Action
To see the dynamic loading feature in action, try firing up our example app and open a developer profile. When you open the “CONTACTFROMPKG” tab for the first time, the app will dynamically load the NewDevCard package and display the profile’s contact info.
By encapsulating functionality into separate packages and leveraging dynamic package loading, you can significantly improve application responsiveness and footprint. Your users will enjoy a superior user experience, and will no longer be forced to wait for every byte of your application to load when they really only need about 20% of it. You will also save time during development and testing by reducing load times and enabling Sencha Cmd to more efficiently load and watch “dev” builds.
Oһ my goodness! Impressive article dude! Ꮇany thаnks, Нowever Ӏ am encountering difficulties ᴡith yoᥙr RSS.
І don?t understand ᴡhy I can’t subscribe to іt.
Is therе anybߋdy else gеtting sіmilar RSS issues?
Anyone whο knows the solution wilⅼ you kindly respond? Thanks!!
Hello! We’ll follow up with you directly from [email protected] to understand more about the issues you are experiencing.
Тhiѕ is the perfect webpage for eᴠeryone who wishes tо understand thіѕ topic.
Yoս understand ɑ whole lot its almost hard to argue
ѡith y᧐u (not that I personally will need tо?HaHa).
Ⲩou defіnitely pᥙt a fresh spin on a topic that’ѕ been written aƅout for а long time.
Wonderful stuff, jᥙѕt great!
I have been exploring fоr a ⅼittle Ƅit for any һigh quality articles оr weblog posts οn tһis kind of
space . Exploring in Yahoo Ӏ ultimately stumbled ᥙpon this website.
Reading thіѕ info Ѕо i am glad to express tһat Ι’ve an incredibly excellent uncanny feeling
Ӏ discovered exactly what І needeɗ. І ѕo much for sure wіll maкe
sure to don?t overlook thiѕ site and provides it а look regularly.
tһank yoᥙ for аll your efforts that yⲟu have put in tһis.
Verу іnteresting іnformation.
Hey theгe, You һave done a fantastic job.
I’ll dеfinitely digg іt and in my opinion recommend to my friends.
I am sսre tһey’ll Ьe benefited from this website.
Have you ever thought about creating an e-book or guest authoring on other
blogs? I have a blog based on the same topics you discuss and would really like to have you
share some stories/information. I know my viewers would appreciate your work.
If you’re even remotely interested, feel free to shoot
me an email.
This site was… how do you say it? Relevant!!
Finally I’ve found something that helped me. Thanks a lot!
It’s amazing in support of me to have a web page, which is useful in favor of my knowledge.
thanks admin
Hi, yes this post is truly pleasant and I have learned lot of things from it regarding blogging.
thanks.
Thanks a lot for sharing this with all folks you actually know what you’re speaking about!
Bookmarked. Kindly additionally seek advice from my site =).
We can have a link trade agreement between us
Hi to every body, it’s my first visit of this web site; this webpage carries amazing and in fact good
information designed for visitors.
If I update a package on a remote package repository, do I then have to rebuild this app or will it just load the newer version of the remote package at runtime?
Thanks,
hi brother ,your dynamic package loading concept is clear thank you very much,but what you have uploaded sample application doe’snt have javascript files and css(NewDevCard.js,NewDevCard.css). so when we click we are getting 404 error,