Happy Function Node

Hi everybody!

Before node-red 1.3 release, it was not easy to use external npm modules directly.

For this reason I started develop a new function node, based on the "unsafe-function-node" available for node-red, which however introduces new features, and simplifies writing code on node-red.

This function node offers:

  • Ability to create *.js modules shared between all function nodes and stored on server.
  • Ability to search and manage (install, uninstall, update) npm packages
  • Use MONACO editor instead of the default ace editor (for better user experience)
  • Take advantage of code completion of all installed npm packages (with bundled type definitions, or available in definitely-typed repository)
  • Take advantage of code completion of all *.js modules created by user

Main features:

  • Own package.json file to manage npm packages
  • Configurable user modules folder path
  • More faster than a normal function node because the code don't run inside a vm
  • Custom MONACO editor bundle (created from my repository node-red-contrib-monaco) instead of the default ACE editor (for better user experience)
  • npm package manager with interactive web interface
  • Safe uninstall of npm packages, or save delete of user modules (automatically detect npm packages that are not required within function nodes or within user modules)

-> FUNCTION TAB

Here you can write the code that will be executed by the function node. The editor has a default pre-configured environment with all the global node-red variables available and several code snippets. It also provides code completion for the entire NodeJS library.

  1. The imports are resolved based on installed npm packages and available user modules
  2. When an npm package is installed or a user module is created, the editor automatically updates the code completion.

-> PACKAGES TAB

Here you can search for an npm package using an autocomplete search input field. All the npm packages can be managed via the web interface. Npm packages are shared among all function nodes.

  1. Install and fuzzy search for npm packages
  2. Update single npm package
  3. Automatic type definitions discovering (included or available in typesearch)
  4. Safe npm package uninstall (check for required dependencies in all functions nodes, or in user modules)
  5. Check for npm packages updates

NPM fuzzy search

-> MODULES TAB

This tab lists all the *.js modules created by the user...and stored on server. Each module can be edited or deleted directly from here. It is also possible to create new module, or delete unused one. User modules are shared among all function nodes.

  1. Modules folder path on server
  2. The function node takes care of checking which modules are not required by other function nodes or by the modules themselves.

TAB MODULES EDITOR
From here we can edit custom *.js modules stored on server. These modules are available in the main function, using the require statement. A little toolbar is available for common actions.

Soon I will finish the work and if anyone is interested they can try it :slight_smile:

hanc

Sounds very interessing. I'm searching for a way to set global const (or define them in a module) and use them with code-completition in all sother function-nodes. Seems like your node could do the job, but I think a very similar way is still in progress:

see: Monaco by Steve-Mcl · Pull Request #2798 · node-red/node-red · GitHub

Do you have an installable package for the node yet?

@hanc2006 given the Function node is core to the user experience of Node-RED, it would have been great to have a discussion about these features before you went your own way.

My worry is your work is now going to clash with a lot of things were trying to do in the core.

In particular, exposing external modules and providing yet another way to install them that will bypass all of the checks we have incorporated to allow for a more managed user experience. It also pulls in Monaco, something we're looking at for 2.0 - we don't want nodes pulling in their own editor components as it could well break core functionality.

Hi @knolleary, thanks for replying!

I created this node for educational and personal purposes only, I didn't plan to make it public one day. But it has grown well, and I decided to share it with the community :wink:

Monaco, something we're looking at for 2.0 - we don't want nodes pulling in their own editor components as it could well break core functionality.

The decision to integrate Monaco directly into the node was dictated by the fact that currently node-red does not have this functionality, once available (in 2.0 timeline) the node will be able to use the default editor with a few changes to the main code.

In particular, exposing external modules and providing yet another way to install them that will bypass all of the checks we have incorporated to allow for a more managed user experience.

Using external NPM packages can safely follow node-red's current restrictions, without problems.

The Monaco editor built into node-red has an initial static configuration, and does not react to external changes. Monaco is a awesome and powerful editor, but at the moment it is not being exploited at 100%. What my function node does is provide constant updates to the editor in order to use an always up-to-date code completion.

@knolleary what do you think about using NPM packages with their type definitions?
It would make sense if you want to integrate a powerful editor like Monaco.

My function node takes care of this part, for each NPM package installed it creates a map that identifies which type of definitions it uses (own types, external types, or types with dependencies) and export a new library which it will be exposed to the Monaco editor.

@knolleary it would also be nice to have a check on the JavaScript code. Verify that the require modules exist, that the code is semantically correct, etc ... My function node takes care of this too.

@knolleary what about managing external dependencies? If a function requires an external package and it doesn't exist ... it will break all the code...My function node takes care of this too, and prevents the package from being removed

Thx hanc

Hi @thomaspz, yes I saw. I also created a PR in this project. The main difference is that my builtin editor is not static. When a user creates a new JavaScript module, or install a new NPM package, the editor updates the code completion automatically.

Do you have an installable package for the node yet?

Very soon yes :smiley:

I don't have a view on all the individual features you've added - we don't yet have monaco in Node-RED and I haven't been involved with integrating it so can't comment on what extra features that may unlock.

what about managing external dependencies?

That is one of the major new features we added in 1.3. We have added the externalModules setting that allows someone embedding Node-RED to have some control over what modules their end user installs. That is a key requirement for anything that can dynamically install additional code into the runtime.

There is also the question of where/how the modules then get installed and what APIs are exposed to manage them. Again, these are all things we've looked at in the core for the 1.3 feature.

I also followed these API

externalModules: {
   allowInstall: supported
   allowUpload: not supported,
   allowList: [],	*partial supported 
   denyList: [] *partial supported
}

At the moment is not supported the package version lock inside allowList, and denyList, and is not supported externalModules.modules.*

Regarding "autoInstall" this problem does not exist because the external dependencies are installed immediately (if the user has the right). However, there is a check that verifies at the start of the function node that all required dependencies exist, and if not, they are installed automatically

@knolleary I moved the packages management out of the function node, in the sidebar area. If the installation of external modules is enabled in settings.js, this menu will be available. From here you can see the external packages installed, and the nodes that use them.