Not strictly true.
You could add a flow that reads your settings.js & presents it to an end point that provides a code editor for you edit and post back to your node-red instance where it can be saved. e.g...
The flow
What you see when you access http://IPorHOST:port/settings.js
The demo flow...
[{"id":"dcba6627.393f68","type":"http in","z":"553814a2.1248ec","name":"","url":"/settings.js","method":"get","upload":false,"swaggerDoc":"","x":460,"y":1640,"wires":[["b5c4e3f5.703f2"]]},{"id":"3abb312.de8d1ce","type":"template","z":"553814a2.1248ec","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n <head>\n <script src=\"https://unpkg.com/monaco-editor@0.23.0/min/vs/loader.js\"></script>\n <style>\n .editor{\n height: 90%;\n } \n </style>\n </head>\n <body>\n\n <div id=\"container\" class=\"editor\"></div>\n <button id='saveSettings' onclick=\"saveSettings()\">Save settings</button>\n \n <script>\n require.config({ paths: { 'vs': 'https://unpkg.com/monaco-editor@0.23.0/min/vs' }});\n window.MonacoEnvironment = { getWorkerUrl: () => proxy };\n var settings = {{{payload}}};\n let proxy = URL.createObjectURL(new Blob([`\n self.MonacoEnvironment = {\n baseUrl: 'https://unpkg.com/monaco-editor@0.23.0/min/'\n };\n importScripts('https://unpkg.com/monaco-editor@0.23.0/min/vs/base/worker/workerMain.js');\n `], { type: 'text/javascript' }));\n\n require([\"vs/editor/editor.main\"], function () {\n window.editor = monaco.editor.create(document.getElementById('container'), {\n value: settings.code,\n language: 'javascript',\n theme: 'vs-dark',\n scrollBeyondLastLine: true,\n roundedSelection: true,\n autoIndent: true,\n cursorStyle: \"line\",\n fontWeight: 400,\n automaticLayout: true\n });\n\n });\n function saveSettings() {\n let newSettings = window.editor.getValue();\n\n const data = { code: newSettings };\n\n fetch('/upsettings', {\n method: 'POST', // or 'PUT'\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(data),\n })\n .then(response => response.json())\n .then(data => {\n alert('Settings sent to node-red :)');\n })\n .catch((error) => {\n alert('Error:' + error.message); \n });\n\n console.log(newSettings);\n }\n </script>\n\n </body>\n</html>\n","output":"str","x":1240,"y":1640,"wires":[["1fa0de6f.8f7bb2"]]},{"id":"1fa0de6f.8f7bb2","type":"http response","z":"553814a2.1248ec","name":"","statusCode":"","headers":{"content-type":"text/html","Access-Control-Allow-Origin":"*"},"x":1370,"y":1640,"wires":[]},{"id":"b5c4e3f5.703f2","type":"file in","z":"553814a2.1248ec","name":"","filename":"settings.js","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":620,"y":1640,"wires":[["4c9dce0c.f807e"]]},{"id":"4c9dce0c.f807e","type":"change","z":"553814a2.1248ec","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t \"code\": payload\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":960,"y":1640,"wires":[["eaaf7a35.9ceef8"]]},{"id":"eaaf7a35.9ceef8","type":"json","z":"553814a2.1248ec","name":"","property":"payload","action":"","pretty":false,"x":1110,"y":1640,"wires":[["3abb312.de8d1ce"]]},{"id":"d43c53d7.fe247","type":"http in","z":"553814a2.1248ec","name":"","url":"upsettings","method":"post","upload":false,"swaggerDoc":"","x":460,"y":1680,"wires":[["93673240.88549"]]},{"id":"d26fc95.3c58d38","type":"http response","z":"553814a2.1248ec","name":"","statusCode":"","headers":{},"x":1370,"y":1680,"wires":[]},{"id":"cc743046.c87b4","type":"function","z":"553814a2.1248ec","name":"replace me with a file out node to save settings","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":920,"y":1680,"wires":[["c98025ff.ed40e8"]]},{"id":"93673240.88549","type":"change","z":"553814a2.1248ec","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.code","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":1680,"wires":[["cc743046.c87b4","52e16f44.3fd56"]]},{"id":"52e16f44.3fd56","type":"debug","z":"553814a2.1248ec","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":850,"y":1720,"wires":[]},{"id":"c98025ff.ed40e8","type":"change","z":"553814a2.1248ec","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":1200,"y":1680,"wires":[["d26fc95.3c58d38"]]}]
NOTES
- Dont leave this code running once you have this set
- Any mistakes will cause node-red to not start
- Assumes settings.js is writable and persisted between reboots
- The editing browser needs internet access (for the editor CDN)
- I have deliberately NOT put the
file
out node in (for safety purposes) I'll leave that to you Mr Future Reader