Hendrik Bulens All about .NET development

Unobtrusively update an ExtJS app to TypeScript

What’s right and wrong about ExtJS

There is much to say about ExtJS. There are things which make it great but there are just as many arguments against it. Essentially it is a JavaScript framework with a bunch of built-in widgets such as grids, trees, date pickers, charts, etc. Back-end developers will find the programming model quite pleasing as it has an object-oriented feel to it.

However, this being JavaScript, it isn’t. ExtJS bridged this gap by providing a class-like system. Did you notice that I mentioned ‘bridged’ and not ‘bridges’? With the (not-so) recent updates of ECMAScript, classes have become essential and ubiquitous in JavaScript world. It is an important part of powerful frameworks such as React and Angular and it enables module bundlers such as webpack to work their magic. Still, ES6 classes are just like Ext classes in that they are not really classes, they’re just a wrapper around the JavaScript prototype-based programming model. I like how Mozilla describes it: it is syntactical sugar over the prototype-based inheritance. So there’s nothing really new and yet it has changed so much for the JavaScript developers.

With such major advances in the JavaScript language, ExtJS has somewhat fallen out of grace. Not because it’s inferior to other commercial products out there, because it’s not. In fact, I think the product has a lot of potential and its suite of widgets is actually quite good compared to other frameworks and widget vendors. It’s a batteries included framework, as opposed to React and Angular where you have to do a bit more to get up and running. With its flexible configuration and object-oriented-ish programming model, you can substantially customize your app with little effort. There’s a bit of a learning curve but once you get the hang of it, it’s fairly easy.

However, the biggest problem of ExtJS is its management. Support is poor, release cycles take much too long, bugs never get fixed in time (or at all), and for a long time they refused to let go of the 5-developer pack minimum. This is just the tip of the iceberg; I could go on for quite a while but this would lead me away from the main topic of this post. Let me just end by saying that I am not the only one who thinks this way. Just take a look at the comments section of Sencha’s roadmap updates and you’ll find that the community is pissed at Sencha. As former employee Mitchell Simoens puts it, ExtJS is destined for the legacy bin. I don’t have all the facts and information, but given my experience with Sencha for the last five years, I tend to agree with him. Whenever I start a new project, ExtJS does not end up in the shortlist of potential frameworks. And that really is a pity.

From a developer’s perspective, it is unacceptable to be still using the same methods for creating a web application. Having to use proprietary dependency loaders and command-line tools may have been okay back in the days, but today we want to use modern web development techniques. For instance, including scripts and creating bundles manually is simply a pain in the ass. Not only is it inelegant, it is also error-prone. Once upon a time, you had to explain why you wanted to use webpack or React instead of using good old jQuery, now you have to explain why you don’t. I’m sorry to say it, but ExtJS is such a reason. You could consider using ExtReact or ExtAngular but that’s just wrapping a mess in even a bigger mess – which is exactly what they did.

If ExtJS could just embrace ES modules, then we could all get on with it. But no, they don’t seem to care about that. Instead, the only thing they seem to be doing are newsletters and webinars. There even isn’t support for TypeScript. There have been some community efforts, but as these things go, they are very short-lived. I would like to suggest a lightweight approach which won’t break your application and possibly won’t even change the output of transpiled files.

Ext TypeScript definitions

In ExtJS, you describe a class with Ext.define and you instantiate Ext classes with Ext.create. You could also use the new keyword but then you would sidestep some of its features (such as loading classes).

Using ExtJS in TypeScript will give you one or two problems. For starters, TypeScript needs to know what Ext means. You could simply bypass the Ext framework entirely and declare a Ext variable:

TypeScript will ask no further questions as you told it can be any type. If you have Ext.craete in your code, TypeScript won’t complain that it doesn’t know ‘craete’. Then why bother using TypeScript if you are just going to use the any type?

There have been a few attempts (see here, here and here for some examples) to address this issue, but as I mentioned before they are short-lived and I wouldn’t want to rely on something that hasn’t been maintained in years.

When I was doing my research on the topic, I thought it would be neat to create a custom compiler for ExtJS in TypeScript. This way, I could write TypeScript code in an orderly fashion while the transpiled JavaScript is exactly the same as before. Even though that would be sublime, it’s quite a complex job, which I can’t sell to my customer. However, there’s one guy who tried to do just that and it looks quite clever. He essentially forked the TypeScript repo and added a compiler for ExtJS classes so this TypeScript class:

would churn out a good old Ext class definition:

The idea is great but the execution isn’t, which is not his fault. Having your own version of TypeScript is not really what you want for a lightweight workaround. Today, one could consider TypeScript transformers to add support for Ext. But to get started with this, one would need to be able to allocate some budget as this is not going to be a trivial task.

Instead, I decided to go with a less effective but much simpler approach: TypeScript type definitions. A type definition describes the shape of a type, function, or any other consumable item. Chances are you already have the @types/jquery in your package.json file’s devDependencies list. This package contains description of the types that the jQuery library exposes. It does not contain the actual implementation but it lets TypeScript know that there is a bunch of stuff you can do with $.

I’ve decided to do the same for ExtJS and created a bunch of .d.ts files. Such files are not required to run your app but they are necessary for compiling. This is an unobtrusive way of TypeScriptifying your solution while minimizing the risk of breaking your app. While you’re boyscouting or refactoring, you just add or modify the typing definitions.

For example, here is my ext.d.ts file:

This allows me to call Ext.create without problems and with type support in the rest of the application:

Do you see what’s going on with Ext.define<T>(className:string, config:T)? By defining an interface or type definition, we can benefit from the type safety of TypeScript while we still adhere to the Ext class model. Configuration items such as extend, selModel, columns are all recognized by the TypeScript compiler because they have been defined in the Ext type definitions.

And the great thing about this is when I run tsc, the output will exactly be the same. How’s that for unobtrusiveness? Now I have support from the TypeScript compiler while changing absolutely nothing to the output. This is exactly what I was looking for.

Such a simple modification just improved my life massively. In VS Code, I can just press F12 when I focus on Ext.grid.Panel, and I’ll be redirected to the d.ts file. Typos and passing the wrong parameters to my functions are a thing of the past, all thanks to the TypeScript definition files.

Even though this is still bodging, it is something I can safely do as part of my day to day tasks. For example, if I replace the ‘any’ type for certain variable by ‘Ext.grid.Panel’, I might get some errors as TypeScript does not recognize a method called suspendEvent(). Because I maintain my d.ts files, I can simply add a suspendEvent method to my Ext.grid.Panel interface.

Doing this also gives me a valuable insight which methods and properties are used in the app, and where they are used. As any developer will tell, you should keep your layers as isolated as possible. ExtJS code should reside only in the top layer of your app. Any business logic on the front end should be agnostic of its implementation. If done correctly, you should be able to swap the front-end framework with another without a redesign of the business layer. Thanks to my refactoring efforts, I am slowly getting there so I can get rid of ExtJS and replace it by Angular or React, eventually.

The workaround I just showed doesn’t address any of ExtJS’ flaws but at least it gives some support to improve an application’s stability. Purists will undoubtedly condemn this approach and I agree with them. However, if there is limited time and budget, you have to work with what you have. And to the very least, it’s a first step towards a modern web application.

To end on a potentially positive note, if we are to believe them, Sencha will address some of my concerns. For instance, in their update to the roadmap, they wrote the following:

“Our engineering teams are working on a transpiler transform process that will allow you to write Ext JS classes and components with ECMA Class syntax. This process will be transparent to the developer.”

Sencha, Updates to Sencha 2019/2020 Roadmap, December 11, 2019

I guess we’ll have to see where the ExtJS saga will take us. I am anxious to know what they’ll come up with. I really hope it’ll be worthwhile as companies have made serious investments, which they – understandably – would like to keep.

Until then, I wish you happy refactoring!

Advertisements

Add comment

Leave a Reply

Hendrik Bulens All about .NET development