Start writing a NodeRed node
3 min read

Start writing a NodeRed node

Here's how I develop a node in typescript.
Start writing a NodeRed node


Development for NodeRed is half-documented from my point of view. There is a bunch of documentation showing how to develop a basic node.

Node components

A node has a JS/TS component which implements the business logic and a HTML one which implements its configuration options (parameters). Both of them are inter-connected via data structures, but I have not (yet?) found a way to define a common data structure in a file, nor merge the two aspects in a single file (like react). Probably one could do it in something like Svelte with a specific adapter, but I have not yet investigated this avenue.

There are also two types of nodes:

  1. Normal nodes, which you can see in your flow and
  2. Configuration nodes which you can define globally and refer them from a normal node.

I was able to get inspiration from other code on how to develop a normal node, but there are significantly less resources for configuration nodes (or maybe I wasn't looking too attentive).

Get a template

I like to write TypeScript (TS) rather than plain JS, so I've been looking for a starting point in TS. I found one here and I've mirrored it here. There is also another one. It looks a bit more structured (I've seen its layout in other code), but it has not been updated in three years 😞.

My adaptations

I like to look at the node while developing it rather than perform unit tests, so I've expanded the execution script for my own implementation (not replicated in the mirror above):

"scripts": {
    "copyassets": "copyfiles -V ./lib/**/*.html ./dist && copyfiles -f ./lib/icons/* ./dist/lib/icons",
    "start": "npm run nodered:prepare && npm run nodered:install && node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS",
    "build": "tsc && npm run copyassets",
    "build:production": "rimraf build/* && tsc --sourceMap false -p . && npm run copyassets",
    "build:docker": "npm run build && docker build --progress=plain -t node-red-contrib-twitter -f ./Docker/Dockerfile .",
    "nodered:clean": "rimraf ~/.node-red/node_modules/node-red-contrib-twitter",
    "nodered:copy:package": "copyfiles -f ./package.json ~/.node-red/node_modules/node-red-contrib-twitter",
    "nodered:copy:module": "copyfiles -u 1 -V ./dist/lib/**/* ~/.node-red/node_modules/node-red-contrib-twitter",
    "nodered:copy:index": "copyfiles -u 1 -V ./dist/lib/** ~/.node-red/node_modules/node-red-contrib-twitter",
    "nodered:prepare": "npm run nodered:copy:package && npm run nodered:copy:module && npm run nodered:copy:index",
    "nodered:prepare:clean": "npm run nodered:clean && npm run nodered:prepare",
    "nodered:install": "cd ~/.node-red/node_modules/node-red-contrib-twitter && npm install --omit=dev",
    "clean": "rimraf ./dist",
    "test": "mocha --recursive --require ts-node/register test/*.ts",
    "lint": "eslint lib/*.ts",
    "postlint": "echo ✅ lint valid"

Changes are:

  • copyassets - copies the non-JS/TS files
  • nodered:clean - removes the locally installed node
  • nodered:copy:module - copies JS code resulted from build in a local NodeRed location
  • nodered:copy:index - copies the index.js file in a local NodeRed location
  • nodered:copy:package - copies the package.json file in a local NodeRed location
  • nodered:prepare - copies executes the nodered:copy:* defined above
  • nodered:prepare:clean - cleans the installed nodes and re-copies them. This is useful if you e.g., refactor the file names
  • nodered:install - performs a npm install on the installed node

I've also changed the start code so it performs a nodered:prepare and a nodered:install before launching the local instance of NodeRed
Now I can do a npm run build and a npm run start to have a NodeRed instance with my in-development node.