Own npm library is working, but why

I built up my own npm library due to all the informations from the forum etc.
So I have the file „OH_function.js“ with the function sendMessage() and module.exports = {sendMessage }; with plenty room for more functions.

The index.js file just contains

module.exports = {get OH_function() { return require (‘./OH_function.js’) }}

So what is this line doing, when I use

var {OH_function} = require (‘./kroenert/index.js’);
In my jsscripting 2021 rules?

Perhaps another example will be useful.

I have a personal library in $OH_CONF/automation/js/node_modules/rlk_personal. One of the files there with some helper functions, alerting.js.

exports.sendAlert = function(message, logger) {
  var logger = (logger) ? logger : log('sendAlert');
  logger.warn('ALERT: ' + message);
  actions.NotificationAction.sendBroadcastNotification(message, 'alarm', 'alert');
}

exports.sendInfo = function(message, logger) {
  var logger =  (logger) ? logger : log('sendInfo');
  logger.info('INFO: ' + message);
}

exports.isNight = function() {
  const currToD = items.getItem('TimeOfDay').state;
  return currToD == 'NIGHT' || currToD == 'BED';
}

exports.isAway = function() {
  return exports.isNight() || items.getItem('Presence').state != 'ON';
}

exports.getNames = function(group, filterFunc) {
  return items.getItem(group.name || group).members
                             .filter(filterFunc)
                             .map(s => s.getMetadataValue('name') || s.label)
                             .join(', ');
}

Notice that I just defined the functions on exports directly instead of using module.exports but as far as I can tell they are functionally equivalent. So I have exported sendAlert, sendInfo, isNight, isAway, and getNames.

Now we look at index.js. index.js is what your scripts will see and load by default. The add-on is set up to automatically look in $OH_CONF/automation/js/node_modules for libraries. So if you call require with the name of a folder under node_modules, it will load index.js from that folder.

I have two .js files in my library so my index.js exposes both.

module.exports = {
  get alerting() { return require('./alerting.js') },
  get utils() { return require('./utils.js') }
}

And when I want to import and use anything from the alerting.js file in a script I’ll use:

var {alerting} = require('rlk_personal');

if(alerting.isNight()) {
...

The {alerting} part tells it I only want the alerting stuff, don’t import the other stuff listed in the index.js (in this case utils).

The require('rlk_personal') part says look for $OH_CONF/automation/js/node_modules/rlk_personal/index.js and do what it says. In this case, it says to load alerts.js and utils.js from this same folder.

Note, you have to be careful in how you create a personal library. It needs to be “installed” via npm or else any npm operation you perform on the automation folder will delete your library. At a high level:

  1. create a folder “somewhere”
  2. run npm init and answer the questions.
  3. tar that folder up and use npm install filename.tar to install it (run from the $OH_CONF/automation/js folder.
  4. from now on you can add/remove/modify the files in your installed library folder as normal, only now npm won’t remove it if you install/update/remove other libraries using npm.
3 Likes

Thanks a lot again.
I just wonder about the construct
Var {alerting} = something
So {alerting} is kind of what - function or object.

This is standard JavaScript.

In JavaScript you can assign multiple variables on one line. You can do it with arrays:

var [a, b] = ["one", "two"];

But you can also deconstruct an Object. Require returns an Object representing the exports from the module. If you don’t need/want everything from the module, you can just capture those properties of the Object you care about. index.js creates an Object with two functions that call require on the files that make up the library (in my case an Object representing everything in alerting.js and another Object representing everything in utils.js.

I only care about alerting in this example, so I use the standard JavaScript Object deconstruction to just get the alerting property of the Object returned by the require on the rlk_personal module. If I wanted both alerting and utils I’d use:

var {alerting, utils} = require('rlk_personal');

if(alerting.isNight()) {
  ...
}

if(utils.hysteresis(a, b, c)) {
  ...
}

Or if I don’t mind working with the whole imported Object:

var rlk_personal = require('rlk_personal');

if(rlk_personal.alerting.isNight()){
  ...
}

if(rlk_personal.utils.hysteresis(a, b, c)) {
  ...
}
2 Likes