Enhancement proposal: more developer control over organization of Node implementations

To create a Node, one must create a .html file and associated .js file with the same base name, and they must live in the same directory (as far as I know; this is what the docs say).

Having implemented a few–and having attempted to use “modern” workflows while doing so–I’ve run into some speed bumps due to this restriction.

  1. Any Node developer wishing to use ES2015+ features is naturally limited by Node.js v4’s implementation, since that’s the oldest version of Node.js that Node-RED supports.
    1. To work around this, compilation or transpilation is necessary.
    2. This generates build artifacts (“dist files”) which typically live in a separate directory (e.g., dist/).
    3. Build artifacts shouldn’t live in version control.
    4. Unless an additional script would copy a .html file into dist/, the .html files must be under version control and live in dist/, while the build artifacts are ignored. This is awkward.
  2. Adding such a workflow to JS living in the .html file is something I haven’t explored, because it would require nonexistent, particular-to-Node-RED build tooling to output in the structure that NR wants. That isn’t to say this sort of thing couldn’t work (see .vue files as an example where this does work), but it requires tooling.
  3. The requirement that the front-end JS lives in a <script> tag in the the .html file means it’s difficult/impossible to use linters and formatters against it, as well as run isolated unit tests.
  4. The requirement that the front-end template lives in a <script> tag in the .html file can confuse many text editors.
  5. It’s unclear how to use a 3rd-party front-end view or template library (e.g., React or Handlebars) if so desired. For many simple Nodes, this isn’t a problem, but others can suffer from an overabundance of jQuery.

The proposal is, then: allow the developer more freedom to specify the paths to each of these components (the backend JS, the frontend JS, and the template body). This would give the developer the means to work towards further solutions. This needn’t be a breaking change.

Interesting thoughts.
1, but we won’t be on node 4 for very much longer.
3, see grunt-inline-lint in node-red-nodes that does exactly that
4, How so. Not seen or heard of any so far ?
5, indeed, and actually is something that is appearing as part of the split work, so is going to have to be addressed. At least jquery is built in. Won’t encouraging each node to load its favourite library lead to significant bloat ?

1 but we won’t be on node 4 for very much longer.

Yes, but the features that developers (and myself) want to use don't just end where Node.js v6 begins. async/await didn't land until v7.5ish, for example. There's still no stable implementation of ES modules.

3, see grunt-inline-lint in node-red-nodes that does exactly that

This depends on Grunt and uses JSHint; that may work for NR itself, but is a non-starter for many. Someone could write a custom tool to do this against a Node's UI, but that sounds like pain to me.

  1. How so. Not seen or heard of any so far ?

VSCode, in particular, doesn't know what to do with a type of text/x-red; we lose "intellisense" and syntax highlighting. I think WebStorm or JetBrains' IDEs can likely be "taught" to interpret these tags as HTML. I don't know about others.

5 indeed, and actually is something that is appearing as part of the split work, so is going to have to be addressed. At least jquery is built in. Won’t encouraging each node to load its favourite library lead to significant bloat ?

Yes, well, it's overkill to add Angular to a Node. Perhaps support for a "blessed" set of frameworks/libs and versions would work, via plugins. Maybe it's as simple as supporting web components--who knows! The problem is really just complexity--complex Nodes (e.g. switch) could benefit from view bindings and state management. But the way forward is unclear.

That said, solutions like this will be more easily explored only if Node developers are allowed more flexibility. There's currently too much friction in trying to step out of the box. What I'm suggesting is, in my opinion, a great starting point.

1, well maybe jump straight to node 8 then ? Next Debian looks like it may well do so.
3, … But it works, so not impossible :slight_smile:
4, so how do they handle angular tags and others from other libraries ?
5, yes, certainly don’t want a free for all, but likewise more options could be useful, even if we do like the box we are in. Maybe a scaffolding tool that leads devs a certain way would also be useful.

1, well maybe jump straight to node 8 then ? Next Debian looks like it may well do so.

The version of Node.js doesn't matter, which is my point. v8 will always lag behind what Babel can do; likewise, someone probably wants to use TypeScript.

3, … But it works, so not impossible :slight_smile:

The idea is to reduce friction by enabling popular tooling to work out of the box; improving the developer experience.

4, so how do they handle angular tags and others from other libraries ?

Plugins. Again, this can be solved, but someone would need to write a plugin. The reason nobody has is probably because NR is much less popular than Angular and React. :laughing:

It is worth exploring how we might approach this; what are possible ways to break up the HTML file into multiple files. There are three main parts to a node:

  • the edit template (html)
  • the help text (html)
  • some javascript to register the node

A node may also want to provide

  • css
  • other js libraries they depend on - maybe an external library (like the geofence node uses leaflet.js) or a shared library between multiple nodes in the same, or related, modules.
  • icons
  • message catalog

My starting point would be to say the requirement is for the runtime to be able to load those individual files and reassemble back into the equivalent of the single HTML file - as that is what the editor loads. That works for most of what I list above - except for an additional js libraries. The runtime/editor split work has already identified this particular piece as something that needs a better solution.

Currently the package.json file points the runtime at the .js file of the node:

"node-red": {
   "nodes": {
      "random": "random.js"
   }
},

A simply way to extend this would be for the value to be an object rather than a string:

"node-red": {
   "nodes": {
      "random": {
         "module": "random.js",
         "template": "random-edit-template.html",
         "help": "random-help.html",
         "messages": "locales/random.json",
         "resources": [ /* a list of paths to additional files the node needs in the editor */ ]
      }
   }
},

That isn't a complete proposal... just a sketch of the sort of thing.

This is basically exactly what I was thinking! Taking it a step further, load those settings via cosmiconfig.

Is NR really incompatible with NodeJS > v4 ? I’m running NR with NodeJS v10 and haven’t noticed any incompatibility for now …

The discussion here is about our minimum supported node version. In other words, we won’t add code that requires node 10 whilst we contine to support earlier versions. You are free to run node-red on anythng from 4.8 (currently) through to the latest.

1 Like

ah ok, I get it now :blush:

Node authors should, of course, specify the minimum (and maximum if necessary) version of Node.JS in the package.json file as with any other Node.JS module. Some of mine for example require Node v6 as a minimum I think.

1 Like

Rather than having the runtime assemble the files, could we leverage a tool like webpack to do some of this work, preparing files for the editor browser app and providing sourcemaps for debugging?

I am not sure what using a Webpack or bundler would buy us other than faster load times. That’s important if we begin to target mobile devices–that’s another can of worms (which I am happy to discuss in another thread).

@knolleary Insofar as “extra stuff” (or any static assets, really; I guess that’s resources above) perhaps an array of directories or globs would do the trick. This assumes Express will serve them, of course. I recall a mention of serving static files from e.g., S3? I don’t know the use case / requirements there.

Thinking it would reduce the code that needs to be implemented and maintained in the runtime, and leverage the work of others who are already doing something similar…

I’m not inclined to jump to a webpack/bundler type solution. That puts a lot of overhead on the developer to create a node. That’s not to say a developer wouldn’t be able to do it… just not a primary concern.

I think the first step is to list out the possible files a node may get broken out into.

@boneskull for extra files, take a look at node-red-node-geofence. It loads up the leaflet.js library in its edit dialog. To do that, it defines some custom http routes to serve up the files.

1 Like

re: geofence, yes, that’s how it’s currently done, but IMO would improve developer experience by allowing these directories/files to be declared in either the Node’s config (package.json) or via a shortcut method under the RED API…

Sorry I wasn't clear - I agree. The geofence node is an example of a node that wants to provide additional resources. Finding a way for it to do so, without it having to add custom express routes is one of the requirements here.

1 Like

Each Node is actually four parts–not three–lest we forget the “help text” template. :wink:

The first thing I’d do with an arbitrary “help text” file is create it with remark.

Although I have built only a few nodes and not published any, I can understand the appeal of applying the sort of development tools and workflows used by professional developers. At the same time, I would hate to see the process made more complex for the beginner. There is usually a balance to be struck between power and complexity. Despite a lot of programming experience in “dead” languages, it took me a while to learn enough about JavaScript, html, Git, and npm to deal with the current system. I think the best way to approach the topic of this thread would be to create the option of more developer control, while keeping something at least as simple as the present organization and not forcing the beginner to master any additional tools.

3 Likes