How I created my first MagicMirror² module with Typescript
Michael Scharl
Posted on August 22, 2019
I recently created my first MagicMirror² module. Now I want to "talk" about how I did it.
📦 The Build Tools
As with most of my little side projects, I started from scratch by creating my build toolkit. I usually create a Webpack config install all the loaders and start building. This time I wanted to try rollup, one of the tools I had on my "I want to check this out when I have time"-list. The setup was quite simple and I like the fact that you can create multiple entries and outputs with different plugins that handle you code generation. This is ideal for this project since I want to create the core module file wich is targeted for the browser while the helper module is targeted for a node environment. In the end my config ended up looking like this.
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
import typescript from 'rollup-plugin-typescript';
import pkg from './package.json';
export default [
/**
* The core module file
* Written in Typescript and bundled with all dependencies.
*/
{
input: './src/MMM-edgerouter-throughput.ts',
plugins: [
typescript(),
resolve(),
commonjs(),
],
output: {
file: './MMM-edgerouter-throughput.js',
format: 'iife',
},
},
/**
* The module helper file
* Written in Typescript and only compiled to be used within node.
*/
{
input: './src/node_helper.ts',
plugins: [
typescript(),
],
external: ['node_helper', ...Object.keys(pkg.dependencies)],
output: {
file: './node_helper.js',
format: 'umd',
},
},
]
For a more convenient use I usually create three npm scripts for compiling my code. watch
to continuously compile my code while developing, dev
to build everything once for developing/testing and build
to create a production ready package.
{
"scripts": {
"build": "rollup -c",
"dev": "rollup -c --sourcemap=inline",
"watch": "npm run dev -- --watch"
}
}
🏗️ The Development Environment
To ensure a fluid and easy development process I installed MagicMirror on my machine to be used in the "server-only" mode. This allows me to add every module I create as a symlink. I also created a symlink in my projects directory to the node_helper
modules folder. This is not mandatory but helps my IDE figuring out what I mean when I include the node_helper
.
.
├── MMM-edgerouter-throughput
│ └── …
├── MMM-oebb-station-board
│ └── …
├── …
├── MagicMirror
│ ├── …
│ └── modules
│ ├── MMM-edgerouter-throughput -> ../../MMM-edgerouter-throughput
│ ├── MMM-oebb-station-board -> ../../MMM-oebb-station-board
│ ├── …
│ └── node_modules
└── node_modules -> MagicMirror/modules/node_modules
📘 Using Typescript
To be honest, it's not the best possible integration. The MagicMirror repository includes a module-types.ts
file, containing the most important types, which I extended a little to fit my needs. A deeper integration, like being able to get correct typings/autocompletion for the this
object in functions, is not available. If I find myself using it more in the future, I may look into improving this.
Beside that it works without any problems and I feel like Typescript is giving me a more robust and worriless development experience in the long run. In the end it just gets compiled to pure Javascript before being loaded into the MagicMirror. Those files need to be inside the root folder. Therefore I decided to put the Typescript files into a src
folder, for a more obvious separation.
✋ Any questions.
If you have any question regarding my process or the like, feel free to ask me in the comments!
Posted on August 22, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.