Building a customer class loader for Sencha

by Roland Schütz (comments: 0)

The Sencha class loading is a beautiful concept and brings an enormous power to javascript. After digging a bit deeper, I was surprised to be stuck pretty fast.

Most programming languages already have a class loader built in, javascript is different here. Let's take a small look at Java. Java actually splits up into multiple class loaders. A basic class loader loads Java core files, then child class loaders load extensions and a child of this the application. Ext.Loader combines all three into one. So far, so good.

But Java allows customer class loaders, which can be child loaders of the above. Sencha provides nothing similar.

Note: Java is by far not my favorite language, but they got this right. ;-)

Java has three principles for their class loaders:

  • Delegation principles
  • Visibility Principle
  • Uniqueness Principle

For details see this blog entry.

Why should I care?

So why do I care about all of this. Bancha is a system, which exposes server-side models to the client-side. This is a beautiful way of keeping your code dry and building applications faster. This means that ExtJS or Sencha Touch applications need to load Bancha models.

Since Bancha gets the model schema data from the server and then instantiates it, Bancha needs a separate loading logic.

Other use cases

But this is by far not the only use case, you could for example create a custom class loader for generating scaffolded classes. So for example every time 'Scaffold.store.*' is required you could scaffold a store from conventions. 

Starting Point

Sencha’s current structure looks like this:

Diagramm of Ext.Loader and dependencies

First Attempt

My first attempt was to implement all three principles from Java and  have custom child loader. But this did not only require a lot of changes in private Sencha methods, but also was unnecessary complex. 

The solution

After throwing all of this away and starting from scratch, I noticed that I would not need the Visibility principle, the default Sencha class loader can be the single instance to be aware of all loaded classes, and just provide a hock to add custom loading logic. Our final class loader incorporates the Java class loader principles of Delegation and Uniqueness, while still keeping all Visibility in the main Ext.Loader.

Bancha.Loader now simply extends Ext.Loader to allow the usage of custom loaders. The actual Bancha loading logic is encapsulated in custom loader: Bancha.loader.Models.

To implement your own custom loader you simply need to create a new class, which has a optional parentLoader config for chaining custom class loaders and two methods:

  • handles(className) will be called to find the correct loader for handling the class-loading. It it returns true, this loader will be used for loading the class. Otherwise is will be delegated to the parent loader.
    If no custom loader handles the class, the default Sencha class loader will be handling it.
  • loadClass(className, onLoad, onError, scope, syncEnabled) will be called every time a class needs to be loaded and the handles(classname) returned true. 

To register a new custom loader you simply use Ext.Loader.setDefaultLoader(myLoader);. The new class structure looks as follows:

Diagramm of Ext.Loader and dependencies ater injection of Bancha.Loader

 

Below you can find a sequence of various cases how a class can be loaded with the new class-loading concept:

Sequence diagram of the new Bancha.Loader

The Code

The code will be part of Bancha 2. If you want to dig into it, here are the Bancha.Loader, the customer loader interface Bancha.loader.Interface and the Bancha model class loader Bancha.loader.Models.

Final Thoughts

With the new Bancha.Loader we are able to require Bancha models with the standard Sencha dependency management. We can load classes synchronously and asynchronously, all fully transparent to the app developer. This allows Bancha developers to write code like the following, while in the background loading the model schema and creating the model definition on the client-side.

Ext.define('MyApp.store.Users', {
    extend: 'Ext.data.Store',
    requires: [
        'Bancha.model.Account'
    ],
    config: {
        model: 'Bancha.model.User',
    }
});

Go back

Comments

Add a comment

Subscribe

Sign up for exclusive Bancha news!