External settings.js file misunderstood

I read something about the possibility to import an external js file to settings.js, and as I use an embedded device that run node-red and the manufacturer likes to overwrite the settings file with updates, I thought it would be nice If I could fix it after the update with a single line addition.
But I think I misunderstood anything because It doesn't work.
So I issue:

cat <<EOT > customSettings.js
module.exports = {
  tz: process.env.TZ="Europe/Madrid",
  dbusAddress: process.env.NODE_RED_DBUS_ADDRESS="10.1.5.35:78",

  flowFilePretty: true,
  functionExternalModules: true,

  contextStorage: {
      default: {
          module:"localfilesystem"
      },
  },
  
  editorTheme: {
    theme: 'midnight-red-scroll',
    projects: {
      enabled: false,
    },
    codeEditor: {
      lib: 'monaco',
      options: {
        theme: 'brilliance-black',
      },
    },
  },
}
EOT

And then

sudo sed -i "0,/^module.exports = {.*/s/^module.exports = {.*/var mySettings = require(\'.\/customSettings.js\');\n\n&/" settings.js

And it doesn't seem to be picking the settings. Can't be used like that?

The inside of the module.exports in the settings.js file is a JavaScript object. Therefore, you can't use plain JavaScript code as you have done.

Also, while you certainly can merge 2 objects relatively easily on modern versions of Node.js (e.g. probably v12+), you need to know how to do that. I generally have to look it up each time :slight_smile:

Probably the easiest thing by far is simply to create a settingsCopy.js with everything in it. Then simply replace the original with the custom one. No need then to mess with error-prone sed commands.

Of course, you also then need to restart Node-RED so that it picks up the new file.

The problem is that the settings.js file they include is not standard and includes their own settings. (Victron Energy). So it's not as simple as replacing it.
Geez, they even like to change the flows.json name and play with credentials.

What do you mean with plain js object?
I would want to override existing settings with the new ones.

OK, I wondered about that. A couple of choices I think.

Personally, I would probably copy their file after each update, and make my changes then put the amended file back. You could doubtless use sed to make the changes if you wanted to mostly automate it. Though how often does it happen? If it is only occasionally, maybe even do it by hand? Of course, if you don't have a useful editor on the device then sed or even a node.js script would perhaps be needed.


another choice is to a variation on what you are doing. Firstly though, are you sure you need sudo to do the edit? Don't use it unless you have to as it will mess up the permissions.

I'm no sed expert so I'm struggling to see what you are actually doing with that line. But again, I would apply a series of text replaces to change the settings to what I wanted rather than trying to import your custom settings and merge them at arms length.


Then the final choice I can think of would be to do what you have tried so far but you need to fix the code. To do that, you need to understand a bit more about how Node.js modules work so you may want to do some reading. You can't have a var .... statement inside the module.exports because settings.js exports a JavaScript object. Any statements like that would have to be before the module.exports not inside it. Then you would need to still replace some of the code inside the export object to pick up the properties from your imported object.

You can probably already see why I'm suggesting that a straight set of search/replace actions might be better or at least easier.

Again, you need to do a bit of reading about JavaScript objects. An object is something that holds a series of properties. Those properties can contain pretty much anything such as another object, a function, ... But an object cannot have JavaScript statements (like var xxxx = 10) at the top level, only property names can be at the top level of the object.

Ah, ok. Then I may explain: What the seed line is doing is placing the import in the original file like this:

...
 **/

var mySettings = require('./customSettings.js');

module.exports = {

/*******************************************************************************
 * Flow File and User Directory Settings

Before the original module.exports. It could have been better to be a const instead a var.

I then see your solution of replacing the settings in those objects like:
contextStorage: mySettings.contextStorage;

But it defeats my purpose of not running through a diff process to see what they changed every time. They upgrade every week or two.

PS: Sorry I just slipped sudos everywhere.

Mmmmm... And can't you simply do a require('./customSettings.js'); without container object, at the bottom of the file and overwrite the previous definitions?

Kind of, but you need to think about what you actually get when you do it. Worth doing some quick tests so that you get a feel for it.

If you have a test1.js file:

module.exports = 42

And in a test2.js file you have:

console.log( require('./test1.js') )

You can then add more to the exported object. A require is also very efficient and you can use it multiple times and it will always reference the first require. You can also use a spread to import multiple properties into multiple variables.

But you can't do what you suggest. A single require without an assignment to a property is a statement and that isn't allowed inside an Object. So you can't merge objects that way. As mentioned, there are ways to merge objects but that isn't one of them.