TypeScript and Drupal.behaviors
Back in June some of our crew attended Dinosaur JS conference in Denver, CO.
This all got me thinking about TypeScript, Closure compiler, etc... and JS performance and development in general. But I have to admit, I was struggling to see how these technologies could benefit us in Drupal since most of our JS is done in Drupal.behaviors.
Backing up a bit, way back to the days of yore, March 2017. Over the past several months I have been tinkering on a small project written in C here and there. One thing I keep being struck by is: the ability to lean on the compiler when refactoring is really nice. Want to remove a member from a struct? No problem, the compiler will tell you any place that it was accessed so you can review the code for further needed changes.
Wish we had this in our day-to-day...
Meanwhile… at Dino JS
During our trip to Colorado, I attended a workshop for getting a project up and running with TypeScript. During a section when features of the compiler were presented I thought: “wouldn’t it be nice if we could use common TypeScript interfaces in Drupal behaviors so that when there’s refactoring, we could lean on the TypeScript compiler, too?”
And it turns out we can.
I started out with the Mediacurrent Drupal theme generator, which is really cool!
Check out Mario’s post about that here: https://www.mediacurrent.com/blog/mediacurrents-drupal-theme-generator
This way I was able to get a new theme created with two example components with behaviors in a few minutes.
From there I added a gulp task in my theme (called “generated”) to handle my TypeScript code.
Note: this is not final, I just sorta jammed this in here for a test. In a production project, this would probably be a build task like the rest of the theme.
I added some simple jQuery code to CardA, and CardB to simply add a border for illustration and now you can see my two .ts behaviors are slotting into the theme just as if I had written them in es6:
But here’s the fun part! If I make a new Interface:
And then use that interface in two or more places:
And then later that Interface undergoes some changes:
Next time I run the compile task:
Yay! Now we see all the places in the project where the change to the shared interface affects the code because tsc will tell us about them.
If you’re using Visual Studio Code, it tells you right in the IDE as well:
So, is it worth it?
At this time I would say: “maybe”. If your project is already using gulp for transpiling steps, this doesn’t really change that much. You just now write things in TypeScript and you are able to benefit from the compile-time type checking.
For a large project where you have many behaviors that all have to do processing on the same types and data structures? I would say it is almost definitely worthwhile.
Taking things further...
Beyond the maintainability benefits gained from tsc in this little demo, we could add Google’s Closure Compiler into the mix as well. Then we’d be leveraging our type-checked code output into a more performant optimized bundle.
In order to translate from TypeScript to code that Closure Compiler can work on there is a transpilation step required. Good news, though, there’s a tool from the Angular project available called Tsickle which does just that allowing Closure Compiler to take advantage of type information from TypeScript.
Potential benefits recap:
- Shared interfaces, nice code completion in an IDE
- Updates to shared interfaces help with refactoring and catching issues before they present as runtime bugs
- Visual Studio Code automatically integrates TypeScript and gulp out of the box
- Gain better performance through the use of Closure Compiler after translation through Tsickle