It came as a bit of a shock that I have been running MagicMirror in my home office for almost two years now. I even wrote two modules, one to display Prometheus alerts and one to show Status Page status.
In the past few years I have started to become more and more comfortable with Typescript, I wanted to see if I could convert my modules to Typescript.
Finding an example
As is the case with most development, the first step was to see if someone else had done it. As it turns out, a few folks have done it.
I stumbled across Michael Scharl’s post on dev.to which covered his Typescript MagicMirror module. In the same search, I ran across a forum post by Jalibu that focused a little more on the nitty-gritty, including his contribution of the magicmirror-module
in DefinitelyTyped.
Migrating to Typescript
Ultimately, the goal was to generate the necessary module files for MagicMirror through transpilation using Rollup (see below), but first I needed to move my code and convert it to Typescript. I created a src
folder, moved my module file and node_helper into there, and changed the extension to .ts
.
From there, I split things up into a more logical configuration, utilizing Typescript as well as taking advantage of ESNext based module imports. As it would all be transpiled into Javascript, I could take advantage of the module options in Typescript to clean up my code.
My modules already had a good amount of development packages around linting and formatting, so I updated all of those and added packages necessary for Typescript linting.
A Note on Typing
Originally, following Michael Scharl’s sample code, I had essentially copied the module-types.ts
file from the MagicMirror repo and renamed it ModuleTypes.d.ts
in my own code. I did not particularly like that method, as it required me to have extra code in my module, and I would have to update it as the MagicMirror types changed.
Jalibu‘s addition of the @types/magicmirror-module
package simplified things greatly. I installed the package and imported what I needed.
import * as Log from "logger";
import * as NodeHelper from "node_helper";
The package includes a Module
namespace that makes registering your module easy:
Module.register<Config>("MMM-PrometheusAlerts", {
// Module implementation
}
A few tweaks to the tsconfig.json
file, and the tsc
command was running!
Using Rollup
The way that MagicMirror is set up, the modules generally need the following:
- Core Module File, named after the module (
<modulename>.js
) - Node Helper (
node_helper.js
) that represents a Node.js backend task. It is optional, but I always seem to have one. - CSS file, if needed. Would contain any custom styling for the HTML generated in the Core Module file.
Michael Scharl’s post detailed his use of Rollup to create these files, however, as the post is a few years old, it required a few updates. Most of it was installing the scoped rollup packages (@rollup), but I also removed the banner plugin.
I configured my Rollup in a ‘one to one’ fashion, mapping my core module file (src/MMM-PrometheusAlerts.ts
) to its output file (MMM-PrometheusAlerts.js
) and my node helper (src/node_helper.ts
) to its output file (node_helper.js
). Rollup would use the Typescript transpiler to generate the necessary Javascript files, bringing in any of the necessary imports.
Taking a cue from Jalibu, I used the umd
output format for node_helper
, since it will be running on the backend, but iife
for the core module, since it will be included in the browser.
Miscellaneous Updates
As I was looking at code that had not been touched in almost two years, I took the opportunity to update libraries. I also switched over to Jest for testing, as I am certainly more familiar with it, and I need the ability to mock to complete some of my tests. I also figured out how to implement a SASS compiler as part of rollup, so that I could generate my module CSS as well.
To make things easier on anyone who might use this module, I added a postinstall
script that performs the build task. This generates the necessary Javascript files for MagicMirror using Rollup.
One down, one to go
I converted MMM-PrometheusAlerts, but I need to convert MMM-StatusPageIo. Sadly, the latter may require some additional changes, since StatusPage added paging to their APIs and I am not yet in full compliance…. I’ve never had enough incidents that I needed to page. But it has been on my task list for a bit now, and moving to Typescript might give me the excuse I need to drop back in.