<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Development on Much Ado About IT</title><link>https://it.knightnet.org.uk/categories/development/</link><description>
Recent content about Development from Much Ado About IT |
Ramblings and rantings from IT Architect &amp; Designer, Julian Knight</description><generator>Hugo | gohugo.io | Theme twenty-sixteen</generator><language>en-gb</language><copyright>This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.</copyright><lastBuildDate>Mon, 24 Apr 2023 21:27:28 +0000</lastBuildDate><atom:link href="https://it.knightnet.org.uk/categories/development/feed.xml" rel="self" type="application/rss+xml"/><item><title>Node-RED communications protocols</title><link>https://it.knightnet.org.uk/kb/nr-qa/nr-comms/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/nr-comms/</guid><pubDate>Thu, 20 Aug 2020 17:53:20 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/nr-comms/</guid><description><div>Node-RED has an excellent choice of communications protocols available to it. This article looks at the main options and their strengths and weaknesses. It also gives suggestions as to when you may wish to use them.</div><div>&lt;p>Node-RED is renown for its MQTT support since that is where it started - as an IBM demonstrator for their experteese on IoT.&lt;/p>
&lt;p>However, this is only one of many ways to send/receive data between Node-RED and other systems or services. Each of tese protocols has its own advantages and disadvantages.&lt;/p>
&lt;h2 id="the-protocols">The protocols&lt;/h2>
&lt;p>In rough order of descending order of ease of use (very rough!):&lt;/p>
&lt;ul>
&lt;li>MQTT&lt;/li>
&lt;li>Websocket&lt;/li>
&lt;li>HTTP&lt;/li>
&lt;li>TCP&lt;/li>
&lt;li>UDP&lt;/li>
&lt;li>UNIX Pipes&lt;/li>
&lt;/ul>
&lt;h3 id="mqtt">MQTT&lt;/h3>
&lt;p>This is likely to be the easiest to use even though it requires an extra service to be running, a &amp;ldquo;Broker&amp;rdquo;.&lt;/p>
&lt;p>There is even a custom node available that lets you run a broker from within Node-RED itself. However, I don&amp;rsquo;t recommend doing that because it adds significant overheads that are easily avoided. The most commonly used broker is &amp;ldquo;Mosquito&amp;rdquo; which has low resource overheads, is fast, secure and capable. It is easily installed and configured.&lt;/p>
&lt;p>While MQTT data payloads are just strings, Node-RED lets you send and receive more complex data structures (JSON).&lt;/p>
&lt;p>The things that put MQTT at the top of the list are:&lt;/p>
&lt;ul>
&lt;li>The ability to easily handle more complex data&lt;/li>
&lt;li>The availability of MQTT libraries and clients for many platforms&lt;/li>
&lt;/ul>
&lt;h3 id="websocket">Websocket&lt;/h3>
&lt;h3 id="http">HTTP&lt;/h3>
&lt;h3 id="tcp">TCP&lt;/h3>
&lt;h3 id="udp">UDP&lt;/h3>
&lt;h3 id="unix-pipes">UNIX Pipes&lt;/h3></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/communications">Communications</category><category domain="https://it.knightnet.org.uk/tags/protocols">Protocols</category><category domain="https://it.knightnet.org.uk/tags/mqtt">MQTT</category><category domain="https://it.knightnet.org.uk/tags/websockets">Websockets</category><category domain="https://it.knightnet.org.uk/tags/tcp">TCP</category><category domain="https://it.knightnet.org.uk/tags/udp">UDP</category></item><item><title>How to reliably detect the object type of a JavaScript variable?</title><link>https://it.knightnet.org.uk/kb/node-js/object-type-detection/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/node-js/object-type-detection/</guid><pubDate>Sun, 07 Jun 2020 14:30:54 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/node-js/object-type-detection/</guid><description><div>The nature of JavaScript means that everything is treated as an object (sort of). It can be remarkably hard to reliably detect what type of object something is and there isn't a single function in JavaScript that can be used in all cases. So how do we do it? Here are some options</div><div>&lt;p>The &amp;ldquo;official&amp;rdquo; way is to use &lt;code>Object.prototype.toString.call(objectToTest)&lt;/code>. This will work no matter what the object is, even &lt;code>null&lt;/code> or &lt;code>undefined&lt;/code>. However, it is relatively quite slow.&lt;/p>
&lt;p>A &lt;a href="https://stackoverflow.com/a/49506047/1309986">quicker way&lt;/a> is probably to use &lt;code>objectToTest.__proto__.constructor.name&lt;/code>. However, note that this will fail (as do many other methods) if the object is &lt;code>null&lt;/code> or &lt;code>undefined&lt;/code>.&lt;/p>
&lt;h2 id="simple-function">Simple function&lt;/h2>
&lt;p>This simple function provides an easy to use way to return the object type and a list of simple type ENUM&amp;rsquo;s to compare against.&lt;/p>
&lt;p>Note that using &lt;code>Object.prototype.toString.call(prop)&lt;/code> is a fairly slow operation and therefore this should be avoided when maximum performance is required.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">types&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;get&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">prop&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">Object&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">prototype&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">toString&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">call&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">prop&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;null&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;[object Null]&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;object&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;[object Object]&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;array&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;[object Array]&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;string&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;[object String]&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;boolean&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;[object Boolean]&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;number&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;[object Number]&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;[object Date]&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Used as:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">types&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">prop&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nx">types&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">number&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It can, of course, be extended with your own bespoke object types.&lt;/p>
&lt;p>This is taken from an &lt;a href="https://stackoverflow.com/a/32297474/1309986">answer&lt;/a> to the StackOverflow Question: &lt;a href="https://stackoverflow.com/questions/7893776/the-most-accurate-way-to-check-js-objects-type">The most accurate way to check JS object&amp;rsquo;s type?&lt;/a>.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/ecmascript">ECMAscript</category></item><item><title>FAQ 4: How do I see the Node-RED log?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq4-show-node-red-log/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq4-show-node-red-log/</guid><pubDate>Tue, 17 Mar 2020 16:28:07 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq4-show-node-red-log/</guid><description><div>Just as there are several possible ways to run Node-RED, there are several ways to access the log.</div><div>&lt;p>In line with most server type applications, Node-RED outputs all sorts of operational and error information to a log. In addition to Node-RED&amp;rsquo;s own logging, each node that you use may also add to the log.&lt;/p>
&lt;p>You can also output your own information to the log from your flows, those methods are shown at the end of this article.&lt;/p>
&lt;p>There are three categories of ways to actually run Node-RED and each will require you to access the log in a slightly different way.&lt;/p>
&lt;h2 id="running-node-red-as-a-service">Running Node-RED as a &amp;ldquo;Service&amp;rdquo;&lt;/h2>
&lt;p>If you install Node-RED using the script supplied for installation on a Raspberry Pi (or any other Debian-like host), Node-RED will be run as a system service. That is to say that it will be started up when the system boots. You can also do this on other platforms including Windows.&lt;/p>
&lt;h3 id="linux">Linux&lt;/h3>
&lt;p>In these cases, typically system log output goes to a standard service such as &lt;code>syslog&lt;/code>. Typically, the syslog output is found in a file at &lt;code>/var/log/syslog&lt;/code> and you can use the &lt;code>tail&lt;/code> command from a terminal command prompt to view it.&lt;/p>
&lt;p>On most modern versions of Linux though, the syslog is being overtaken by logging built into the &lt;code>systemd&lt;/code> service. In these cases, it is better to use the &lt;code>journalctl&lt;/code> command to show the log output. This has the advantage that you only need to know the service name (&lt;code>node-red&lt;/code> on a standard Pi install) and you don&amp;rsquo;t need to worry about where the actual data is stored. You can also use the more advanced features of that command to output logs in different formats.&lt;/p>
&lt;p>The following command will show you the last 50 lines of the log, jumps to the last output and &amp;ldquo;follows&amp;rdquo; any further output.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">journalctl -u node-red -e -f -n &lt;span class="m">50&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="windows">Windows&lt;/h3>
&lt;p>Windows does not use log output in the same way that Linux does as it has the &amp;ldquo;Event Logs&amp;rdquo;. Typically, log output is redirected to a file and you will need to look at the startup command for Node-RED to see where the logs are being written to.&lt;/p>
&lt;h2 id="running-node-red-manually">Running Node-RED manually&lt;/h2>
&lt;p>On all platforms, if you run Node-RED manually from the command line, the log output is shown in the same terminal. Using the keyboard command &lt;!-- raw HTML omitted -->ctrl&lt;!-- raw HTML omitted -->-&lt;!-- raw HTML omitted -->c&lt;!-- raw HTML omitted --> will both stop Node-RED and close the log.&lt;/p>
&lt;h2 id="using-a-runner-to-run-node-red">Using a &amp;ldquo;runner&amp;rdquo; to run Node-RED&lt;/h2>
&lt;p>Sometimes, especially during development, it is helpful to use a &amp;ldquo;runner&amp;rdquo; application such as &lt;code>PM2&lt;/code> or &lt;code>nodemon&lt;/code> to start Node-RED. These will recover from failures and can be made to &amp;ldquo;watch&amp;rdquo; for changes to files and restart automatically.&lt;/p>
&lt;p>Each of these tools may have their own ways of viewing log output. For example, when using the popular pm2 runnner, the command is &lt;code>pm2 logs&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="changing-log-output-levels">Changing log output levels&lt;/h2>
&lt;p>By default, Node-RED will show the following types of output from both Node-RED and any installed nodes:&lt;/p>
&lt;ul>
&lt;li>&lt;code>fatal&lt;/code> - only those errors which make the application unusable should be recorded&lt;/li>
&lt;li>&lt;code>error&lt;/code> - record errors which are deemed fatal for a particular request + fatal errors&lt;/li>
&lt;li>&lt;code>warn&lt;/code> - record problems which are non fatal + errors + fatal errors&lt;/li>
&lt;li>&lt;code>info&lt;/code> - record information about the general running of the application + warn + error + fatal errors&lt;/li>
&lt;/ul>
&lt;p>You can change the logging levels to also show:&lt;/p>
&lt;ul>
&lt;li>&lt;code>debug&lt;/code> - record information which is more verbose than info + info + warn + error + fatal errors&lt;/li>
&lt;li>&lt;code>trace&lt;/code> - record very detailed logging + debug + info + warn + error + fatal errors&lt;/li>
&lt;/ul>
&lt;p>Or you can remove levels or turn off logging alltogether (using the &lt;code>off&lt;/code> setting).&lt;/p>
&lt;p>In addition, there are 2 other settings that impact logs:&lt;/p>
&lt;ul>
&lt;li>&lt;code>metrics&lt;/code> - Whether or not to include metric events in the log output&lt;/li>
&lt;li>&lt;code>audit&lt;/code> - Whether or not to include audit events in the log output&lt;/li>
&lt;/ul>
&lt;p>All of these settings are found (complete with instructions) in the &lt;code>settings.js&lt;/code> file typically found in the &lt;code>userDir&lt;/code> folder (normally &lt;code>~/.node-red/settings.js&lt;/code>).&lt;/p>
&lt;h2 id="outputting-your-own-information-to-the-log">Outputting your own information to the log&lt;/h2>
&lt;p>When writing flows in Node-RED, you will normally use the &lt;code>debug&lt;/code> node that, by default, outputs to the debug sidebar in the Node-RED Editor (admin UI). However, you can change the settings in the debug node to also (or instead) output to the log.&lt;/p>
&lt;p>&lt;img src="https://it.knightnet.org.uk/static/uploads/2020/node-red-debug-node-settings.jpg" alt="node-red debug node settings">&lt;/p>
&lt;p>In addition, you can also output to the log from a &lt;code>function&lt;/code> node using the code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">node&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">warn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;some useful text&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">Mar &lt;span class="m">17&lt;/span> 17:12:48 pi node-red&lt;span class="o">[&lt;/span>18577&lt;span class="o">]&lt;/span>: &lt;span class="m">17&lt;/span> Mar 17:12:48 - &lt;span class="o">[&lt;/span>warn&lt;span class="o">]&lt;/span> &lt;span class="o">[&lt;/span>&lt;span class="k">function&lt;/span>:My useful fn node&lt;span class="o">]&lt;/span> some useful text
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you give your function node a reasonably name, you will see that in the output as shown. If the node doesn&amp;rsquo;t have a name, the id will be shown, you can use that in the Editor&amp;rsquo;s search feature to find the node.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>FAQ 3: What different ways are there to install Node-RED and which is best?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq3-types-of-installation/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq3-types-of-installation/</guid><pubDate>Tue, 10 Mar 2020 09:26:00 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq3-types-of-installation/</guid><description><div>There are several possible ways to install Node-RED, this post provides an overview and some thoughts about when you might want to use which approach.</div><div>&lt;p>There are three basic approaches to installing Node-RED. Which of these is &amp;ldquo;best&amp;rdquo; for you will depend on your knowledge, willingness to learn, desire or need to gain maximum flexibility and so on. Only you can work that out. It should also be noted that you should be able to mix and max these approaches if you really want to (though I can&amp;rsquo;t say that I would personally recommend that).&lt;/p>
&lt;h2 id="global-install">Global Install&lt;/h2>
&lt;ul>
&lt;li>This is the standard and therefore arguably by far the easiest installation.&lt;/li>
&lt;li>It is good for people who are not overly familiar with their OS&amp;rsquo;s filing system or how node.js and npm work and who don&amp;rsquo;t want to be bothered to find out (that is not a criticism by the way).&lt;/li>
&lt;li>It allows for multiple instances to be run if needed but all instances must use the same version of Node-RED.&lt;/li>
&lt;li>It doesn&amp;rsquo;t &amp;ldquo;pollute&amp;rdquo; your home folder with the node-red and many other required node.js modules.&lt;/li>
&lt;li>It is standard and most tutorials and explanations assume that this is the way it is installed.&lt;/li>
&lt;li>It makes the node-red command global so you can run it from anywhere.&lt;/li>
&lt;/ul>
&lt;h3 id="advantages">Advantages&lt;/h3>
&lt;p>Best for beginners unless you are prepared to learn about Node.js.&lt;/p>
&lt;h3 id="disadvantages">Disadvantages&lt;/h3>
&lt;p>Less flexible and possibly a little less secure. Not the best for &amp;ldquo;production&amp;rdquo; installations. Can confuse beginners into installing other Nodes and packages into global when they shouldn&amp;rsquo;t. Hard to work out where the global files are.&lt;/p>
&lt;h2 id="local-install">Local Install&lt;/h2>
&lt;ul>
&lt;li>This is a more &amp;ldquo;node.js way&amp;rdquo; of installing - global installations being good for exposing global commands but may sometimes be less secure.&lt;/li>
&lt;li>It is a more self-contained installation. Everything can be in 1 place under a single folder structure. This makes it easier to back-up everything together. But it doesn&amp;rsquo;t force you to work this way, you can keep your userDir folder separate if you like.&lt;/li>
&lt;li>It allows you to run different instances of Node-RED using different versions. Good for testing major Node-RED upgrades and for testing custom nodes or flows against different versions.&lt;/li>
&lt;li>You are in control. You know where everything is because you chose to put it there.&lt;/li>
&lt;li>You control access to all files and folders and so this can be a more flexible installation. You could also have different instances of node-red on the same device with different folder/file access levels. Possible development and test instances on the same device.&lt;/li>
&lt;li>A good way to create a more portable installation of Node-RED since the whole folder structure can be easily copied/archived, etc.&lt;/li>
&lt;li>It is my personal belief that this is also the best approach for people who want to learn how Node.js and/or Node-RED works. But then again, maybe that&amp;rsquo;s just my warped mind!&lt;/li>
&lt;/ul>
&lt;h3 id="advantages-1">Advantages&lt;/h3>
&lt;p>Best for flexibility and control. Good for control of security. Best for running different versions of Node-RED in parallel on one device. Good for ease of backup/recovery and for creating distributable copies of a Node-RED application. Best for embedding Node-RED into an existing or new Node.js app.&lt;/p>
&lt;h3 id="disadvantages-1">Disadvantages&lt;/h3>
&lt;p>Requires some knowledge of how Node.js and npm work.&lt;/p>
&lt;h2 id="containerised-install">Containerised Install&lt;/h2>
&lt;ul>
&lt;li>Uses either Docker or snap to containerise the installation.&lt;/li>
&lt;li>Isolates Node-RED from the host OS.&lt;/li>
&lt;li>Allow running multiple, independent instances of Node-RED, possible using different versions.&lt;/li>
&lt;/ul>
&lt;h3 id="advantages-2">Advantages&lt;/h3>
&lt;p>Best for enterprise use where containerisation is already well supported.&lt;/p>
&lt;h3 id="disadvantages-2">Disadvantages&lt;/h3>
&lt;p>Adds significant hidden complexity and requires good knowledge of the container technology to isolate and fix issues. Also likely to have higher resource requirements than running separate instances in other ways. Experience from the Node-RED forum suggests that a decent knowledge of Docker/snap is recommended.&lt;/p>
&lt;hr>
&lt;p>There is some additional information that I wrote in a recent blog post:&lt;/p>
&lt;p>&lt;a href="https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/">https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/&lt;/a>&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>Rules for working with dates and times</title><link>https://it.knightnet.org.uk/blog/rules-for-working-with-dates-and-times/</link><guid isPermaLink="true">https://it.knightnet.org.uk/blog/rules-for-working-with-dates-and-times/</guid><pubDate>Sat, 07 Mar 2020 15:35:49 +0000</pubDate><guid>https://it.knightnet.org.uk/blog/rules-for-working-with-dates-and-times/</guid><description><div>Dates and times are incredibly complex. They can be different in different countries, languages. They are often inconsistent and have weird edge-cases. These are some basic rules I apply when working with dates and times.</div><div>&lt;p>when handling dates and timestamps, here are the foundation rules that I work to:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Always use ISO date format where possible&lt;/strong> (YYYY-MM-DD)&lt;/p>
&lt;p>So that there can be no ambiguity and so that date strings will naturally sort&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Always work in UTC&lt;/strong> (Aka Zulu time or GMT) except when displaying to the user&lt;/p>
&lt;p>To avoid weird errors, especially with timezone and daylight savings transitions. It also makes date/time calculations a LOT easier.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>When needing a string format for timestamps, always use ISO format&lt;/strong>&lt;/p>
&lt;p>e.g. &lt;code>2020-03-07T15:27:46.123Z&lt;/code>&lt;/p>
&lt;p>These are always unambiguous and easily machine parsed.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>When specifying decimal seconds in a timestamp, avoid more than 3 decimal places&lt;/strong>&lt;/p>
&lt;p>The &lt;a href="https://github.com/gr2m/moment-parseformat">parsing tool&lt;/a> used in &lt;a href="">node-red-contrib-moment&lt;/a> to parse input dates in different formats cannot cope with more than 3dp and may return strange dates, a problem that I reported in May 2019 but hasn&amp;rsquo;t been resolved.&lt;/p>
&lt;p>It should also be noted that I&amp;rsquo;m not sure that MomentJS can cope with more than 9dp.&lt;/p>
&lt;p>Also worth noting that JavaScript&amp;rsquo;s &lt;code>Date&lt;/code> native object only supports up to 3dp anyway and will turn anything beyond that into zero&amp;rsquo;s.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://github.com/gr2m/moment-parseformat/issues/96">parseFormat function issue for &amp;gt;3dp seconds resolution&lt;/a>&lt;/p>
&lt;p>The worst thing about this issue is that it can result in an incorrect date being returned but does not give a warning.&lt;/p>
&lt;/li>
&lt;/ul></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/information-management">Information Management</category><category domain="https://it.knightnet.org.uk/categories/data">Data</category><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/categories/software">Software</category><category domain="https://it.knightnet.org.uk/tags/databases">Databases</category><category domain="https://it.knightnet.org.uk/tags/dates">Dates</category><category domain="https://it.knightnet.org.uk/tags/dba">DBA</category><category domain="https://it.knightnet.org.uk/tags/debugging">Debugging</category><category domain="https://it.knightnet.org.uk/tags/development">Development</category><category domain="https://it.knightnet.org.uk/tags/software">Software</category><category domain="https://it.knightnet.org.uk/tags/solutions-architecture">Solutions Architecture</category><category domain="https://it.knightnet.org.uk/tags/standards">Standards</category><category domain="https://it.knightnet.org.uk/tags/timestamps">Timestamps</category></item><item><title>FAQ 2: How can I run multiple instances of Node-RED on the same server device?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/</guid><pubDate>Fri, 06 Mar 2020 01:21:33 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq2-multiple-instances/</guid><description><div>There are all sorts of reasons to want to run more than a single instance of Node-RED and several ways to do it.</div><div>&lt;ol>
&lt;li>
&lt;p>Use the command line settings to point to a different userDir folder.&lt;/p>
&lt;p>&lt;code>node-red -u /data/userDirectory&lt;/code>&lt;/p>
&lt;p>That lets you use different flows and configuration settings but only allows a single version of Node-RED.&lt;/p>
&lt;p>You still install Node-RED in the &amp;ldquo;standard&amp;rdquo; way, globally. While this is generally simpler for complete beginners,
it can lead to complexities later on. You should understand the strengths and weaknesses of npm global installs.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Install the Node-RED npm package locally rather than globally.&lt;/p>
&lt;p>This gives you not only the features from 1 but also allows you to run different versions of Node-RED in parallel. The &lt;a href="https://github.com/TotallyInformation/alternate-node-red-installer">alternate-node-red-installer&lt;/a> shows you how to do that.&lt;/p>
&lt;p>It also removes the need to install Node-RED globally which can lead to unexpected security issues.&lt;/p>
&lt;p>This is also the &amp;ldquo;Node.JS way&amp;rdquo; and likely to be a more welcome approach for organisations and teams that run other Node.JS services and systems.&lt;/p>
&lt;p>While slightly more complex to think about initially, especially for Node.JS beginners, it helps you understand how Node.js works, is easier
to work out where everything is kept and is likely to be easier to maintain in the longer term.&lt;/p>
&lt;p>I use npm&amp;rsquo;s script capability to make things really easy to start manually. Here are some examples. Note that I always make the &lt;code>userDir&lt;/code> folder a sub-folder of the master project folder (where Node-RED itself is installed). Keeps things neat and makes it trivial to backup the whole thing.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;scripts&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;start&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;node node_modules/node-red/red.js --userDir ./data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;start2&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;set DEBUG=express:* &amp;amp; nodemon node_modules/node-red/red.js --userDir ./data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;inspect&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;node --inspect node_modules/node-red/red.js --userDir ./data&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;log&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;sudo journalctl -u node-red -f -n 0 -o cat&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;update&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;npm install --unsafe-perm --production node-red&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>So you can start manually using &lt;code>npm start&lt;/code> and start with debugging port active using &lt;code>npm run inspect&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Run Node-RED in a container such as the &lt;a href="https://github.com/node-red/node-red-docker">Docker container&lt;/a>.&lt;/p>
&lt;p>Allows multiple versions of Node-RED along with different configurations and supporting software and services.&lt;/p>
&lt;p>However, this comes at the cost of significantly greater complexity and resource overheads.
Unlikely to be worth doing except in specific circumstances &amp;amp; needs a reasonable level of understanding
of how Docker works.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>You will realise that I much prefer method 2 for all of my own installations. That&amp;rsquo;s why I wrote the alternate installer which
goes some way towards making installations easier and more consistent.&lt;/p>
&lt;p>For running Node-RED on system startup, please see the &lt;a href="https://nodered.org/docs/faq/starting-node-red-on-boot"> Starting Node-RED on boot&lt;/a> page in the docs.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>FAQ 1: Should I use a function node or a flow of core nodes?</title><link>https://it.knightnet.org.uk/kb/nr-qa/faq1-flow-vs-function/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/faq1-flow-vs-function/</guid><pubDate>Fri, 06 Mar 2020 01:16:35 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/faq1-flow-vs-function/</guid><description><div>There are usually many ways to achieve something in Node-RED. A common question is whether or when to use a function node or a collection of core nodes to achieve an outcome.</div><div>&lt;p>Whether I use one approach or the other depends on the complexity of the input vs the complexity of the output.
It really doesn&amp;rsquo;t matter except that it is often easier to read a single function node that several complex change nodes as an example.&lt;/p>
&lt;p>So my general rules of thumb for whether to replace a collection of nodes with a function node are:&lt;/p>
&lt;ul>
&lt;li>How difficult would this be to do in a pure flow? If it is just a couple of nodes, that&amp;rsquo;s fine, if it is 10 nodes then probably not fine.&lt;/li>
&lt;li>If I am using JSONata, how long is it taking me to puzzle over the JSONata code? If it is a few minutes then fine, otherwise use a function node!&lt;/li>
&lt;li>Did someone already write some JavaScript that I can purloin? If so then use it!&lt;/li>
&lt;/ul>
&lt;p>Of course, I know JavaScript reasonably well and if you don&amp;rsquo;t then your own rules might look a little different.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/faq">FAQ</category></item><item><title>A Glossary of Node-RED terms</title><link>https://it.knightnet.org.uk/kb/nr-qa/node-red-glossary/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/node-red-glossary/</guid><pubDate>Fri, 21 Jun 2019 17:40:30 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/node-red-glossary/</guid><description><div>For those not used to it, the terminology used in Node-RED can occasionally be confusing. Due in part to the overloading of some terms.
So I've come up with this glossary to help keep myself from getting confused.</div><div>&lt;p>A draft set of terminology for Node-RED, the flow-based visual programming tool.&lt;/p>
&lt;h1 id="glossary">Glossary&lt;/h1>
&lt;ul>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Editor&lt;!-- raw HTML omitted -->&lt;/strong>: The Node-RED admin UI. Where you edit and deploy flows.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Flows&lt;!-- raw HTML omitted -->&lt;/strong>: The collection of node instances and wires defined by the &lt;em>Flows file&lt;/em> loaded by Node-RED at run time.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Flow&lt;!-- raw HTML omitted -->&lt;/strong>: A tab in the Node-RED admin UI used to break Flows into more manageable chunks.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->flow&lt;!-- raw HTML omitted -->&lt;/strong>: A set of node instances and wires with in a Flow tab.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Package&lt;!-- raw HTML omitted -->&lt;/strong>: An npm package used, amongst other things, to install Node-RED Nodes.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Node&lt;!-- raw HTML omitted -->&lt;/strong>: The source definition for nodes that can be used in Node-RED Flows. Defined normally by an npm Package (though actually defined by 3 files: package.json, an html file for the admin UI and a JavaScript file for the server process).&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Node Instance&lt;!-- raw HTML omitted -->&lt;/strong>: An instance of a Node added to a flow. A Node (definition) may have many instances in Flows.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->node(s)&lt;!-- raw HTML omitted -->&lt;/strong>: same as Node Instance(s).&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->wire(s&lt;!-- raw HTML omitted -->)&lt;/strong>: The logical connectors between nodes. Conceptually, messages &amp;ldquo;travel&amp;rdquo; between nodes. In reality, they don&amp;rsquo;t, data is simply passed by reference (except for the edge cases where a message copy is forced).&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->message(s)&lt;!-- raw HTML omitted -->&lt;/strong>: Often referred to by the short name &lt;code>msg&lt;/code> which is the variable name generally used to reference the message. This is the data object used to communicate between nodes. Typically, it has the minimal definition: &lt;code>{{_msgid: uid, topic: undefined|string, payload: Object|Array|string|number}}&lt;/code> but other than requiring &lt;code>_msgid&lt;/code> (which is added by Node-RED), it may contain any valid, serialisable JavaScript.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->userDir&lt;!-- raw HTML omitted -->&lt;/strong>: The server folder that contains the &lt;em>Flows file&lt;/em>, &lt;code>settings.js&lt;/code> and other Node-RED configuration information. Typically residing at &lt;code>~/.node-red&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;!-- raw HTML omitted -->Project&lt;!-- raw HTML omitted -->&lt;/strong>: a &lt;em>Flows file&lt;/em> and other configuration files that allow rapid switching between Flows. Note that a project shares the same set of Packages (and therefore Nodes) and global Node-RED settings as all other projects. Only the &lt;em>Flows file&lt;/em>, matching credentials, a README and a minimalist package.json are part of a project. Projects are designed to enable teams to work together and can use GIT to manage the data collaboration.&lt;/li>
&lt;/ul></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category></item><item><title>Creating a notification in the Admin UI</title><link>https://it.knightnet.org.uk/kb/nr-qa/notifying-admin/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/notifying-admin/</guid><pubDate>Sun, 16 Jun 2019 19:22:16 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/notifying-admin/</guid><description><div>Node-RED's admin UI has a built-in notification (toast) pop-up message feature.
This article explains how to use it when creating custom nodes as it isn't currently well documented.</div><div>&lt;p>&lt;code>RED.notify('Your message here', options)&lt;/code>&lt;/p>
&lt;p>This can be called from the script in your admin ui code &lt;code>&amp;lt;nodeName&amp;gt;.html&lt;/code>.&lt;/p>
&lt;p>By default, the notification will disappear after a few seconds.&lt;/p>
&lt;h1 id="options">Options&lt;/h1>
&lt;ul>
&lt;li>&lt;code>type&lt;/code>: {success|warning|error=} Adds style to the message box.&lt;/li>
&lt;li>&lt;code>fixed&lt;/code>: {boolean=false} Defaults to false, the notification will auto-remove after a few seconds.&lt;/li>
&lt;li>&lt;code>modal&lt;/code>: {boolean=false} If true, no other user interactions are allowed until the notification has cleared.&lt;/li>
&lt;li>&lt;code>timeout&lt;/code>: {ms=5000}: Specify the time in milliseconds a non-fixed notification will be displayed for.&lt;/li>
&lt;li>&lt;code>id&lt;/code>: {string=} Allows a notification to be updated.&lt;/li>
&lt;li>&lt;code>width&lt;/code>: {px=} Desired width in pixels. (Will be limited to the parent width)&lt;/li>
&lt;/ul>
&lt;h1 id="methods">Methods&lt;/h1>
&lt;ul>
&lt;li>&lt;code>.close()&lt;/code>: Close the notification (useful if &lt;code>fixed&lt;/code> option is &lt;code>true&lt;/code>).&lt;/li>
&lt;li>&lt;code>update&lt;/code>&lt;/li>
&lt;li>&lt;code>hideNotification&lt;/code>&lt;/li>
&lt;li>&lt;code>showNotification&lt;/code>&lt;/li>
&lt;/ul>
&lt;h1 id="example">Example&lt;/h1>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">let&lt;/span> &lt;span class="nx">myNotification&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">RED&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">notify&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;My message in a box&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">modal&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">fixed&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;warning&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">buttons&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;text&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;cancel&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;click&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">myNotification&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;text&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;okay&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;class&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;primary&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s1">&amp;#39;click&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">e&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">myNotification&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">close&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h1 id="references">References&lt;/h1>
&lt;ul>
&lt;li>&lt;a href="https://discourse.nodered.org/t/node-red-admin-ui-display-message-to-user/12290">https://discourse.nodered.org/t/node-red-admin-ui-display-message-to-user/12290&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/node-red/node-red/blob/ccc3809daa3b03e7171cb6f4ccf4d6e0f1188bef/packages/node_modules/%40node-red/editor-client/src/js/ui/notifications.js#L16">https://github.com/node-red/node-red/blob/ccc3809daa3b03e7171cb6f4ccf4d6e0f1188bef/packages/node_modules/%40node-red/editor-client/src/js/ui/notifications.js#L16&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/node-red/node-red/wiki/API-Reference">https://github.com/node-red/node-red/wiki/API-Reference&lt;/a> (old but has some things not documented elsewhere)&lt;/li>
&lt;/ul></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/node.js">Node.JS</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category></item><item><title>Cleaning up npm package install problems</title><link>https://it.knightnet.org.uk/kb/nr-qa/clean-up-npm/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/clean-up-npm/</guid><pubDate>Wed, 05 Jun 2019 07:05:39 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/clean-up-npm/</guid><description><div>Node-RED uses npm to manage package installations such as its nodes.
Sometimes, you can get into a situation where you start getting lots of npm installation or removal issues and it feels like you are going round in circles trying to fix things. If so, time to call it a day and to get drastic! Here, I try to explain an easy way to fix things quickly and completely without side effects.</div><div>&lt;p>Node-RED is built over Node.js which uses &lt;code>npm&lt;/code> as its library (AKA package) manager. It is great to have a standard mechanism to manage libraries but the complexities of managing JavaScript based packages sometimes trips things up.&lt;/p>
&lt;p>Once you&amp;rsquo;ve tried for a bit to understand what the issues are, it may be time to call time and get drastic.&lt;/p>
&lt;p>The following commmands will clean out the packages installed for your live instance of Node-RED - assuming you have it installed via the &amp;ldquo;standard&amp;rdquo; default method. If not, you will need to adjust the folder you operate in.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/.node-red
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm package-lock.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">rm -R node_modules
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That will cleanly reinstall all of the packages marked in your &lt;code>package.json&lt;/code> file. So make sure that is correct first. Every time you install a package (as long as you have reasonably up-to-date versions of Node.js and npm) whether from the NR admin ui or command line, it gets added to package.json.&lt;/p>
&lt;p>I now always remove the lock file as well if I&amp;rsquo;m having issues as that can be the cause of some issues. The lock file isn&amp;rsquo;t generally needed in NR installations.&lt;/p>
&lt;p>Note, as always, I&amp;rsquo;ve assumed you have a &amp;ldquo;standard&amp;rdquo; install of Node-RED which puts your userDir as &lt;code>~/.node-red&lt;/code> (and the equivalent on Windows). If you use an installation scheme like mine, it will be in a different place as noted by the command used to start NR.&lt;/p></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/npm">npm</category><category domain="https://it.knightnet.org.uk/tags/node.js">Node.JS</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/debugging">Debugging</category></item><item><title>Analysing the Performance of Node-RED</title><link>https://it.knightnet.org.uk/kb/nr-qa/analysing-performance/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/analysing-performance/</guid><pubDate>Fri, 19 Apr 2019 13:23:06 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/analysing-performance/</guid><description><div>Node-RED is a powerful platform for prototyping and rapid development but it is complex. It has a lot of moving parts and it can be hard to know what might be causing performance bottlenecks.
This article tries to give some hints and tips about analysing those bottlenecks and how to resolve them.</div><div>&lt;p>Sorry, this is draft and far from complete. Please leave comments if you have something useful to add. Thought I would publish anyway in case anyone finds it useful. I will try to come back to it in the future. If you leave a comment, it will remind me. :-)&lt;/p>
&lt;h1 id="platform">Platform&lt;/h1>
&lt;p>Before starting more detailed analysis, the first thing to do is to look at the platform being used to run Node-RED.&lt;/p>
&lt;p>Often, something like a Raspberry Pi or other single-board computer (SBC) is being used. They have very limited resources and often slow storage (e.g. SD-Cards). So it is very easy to overload them and kill performance.&lt;/p>
&lt;p>To analyse this, you need to use a tool such as &lt;code>top&lt;/code>. Better still, get something a bit more comprehensive such as &lt;code>glances&lt;/code>. Either way, these will tell you how much CPU and memory (RAM) is being used and by what. Start by looking at the three &amp;rsquo;load&amp;rsquo; values, these should all be fairly low, if they are going over about 2-3 regularly then you have an issue.&lt;/p>
&lt;p>Next look at the &amp;lsquo;swap&amp;rsquo;. If this is being used regularly, you will have a performance bottleneck because memory (RAM) is being overused. To fix this, you have to unload some services. If using the &lt;code>glances&lt;/code> tool, it will show a warning if the memory is swapping.&lt;/p>
&lt;p>The easiest way to remove load is likely to be turning off the &amp;lsquo;desktop&amp;rsquo;. This gives you a GUI that you directly interact with via keyboard and monitor. Removing this will remove lots of load on memory and CPU. Have a look at articles that explain how to run your device &amp;lsquo;headless&amp;rsquo;. You will need to be able to connect to your device over the network from another device.&lt;/p>
&lt;p>After that, if there are still issues, you need to look at taking off services that you don&amp;rsquo;t actually need running.&lt;/p>
&lt;p>Finally, if you still have issues, you will need to think about splitting services between multiple devices or using a more powerful device.&lt;/p>
&lt;h1 id="back-end-server">Back End (server)&lt;/h1>
&lt;h2 id="using-nodejs---inspect-option">Using Node.JS &lt;code>--inspect&lt;/code> option&lt;/h2>
&lt;h1 id="front-end-browser-node-red-admin-ui">Front End Browser (Node-RED Admin UI)&lt;/h1>
&lt;p>For any browser performance issues, you firstly need to ensure that the problem is actually coming from something related to Node-RED. So you should turn off any browser extensions before continuing. An extension such as SimpleExtManager for Chromium browsers will assist with easily turning on/off extensions.&lt;/p>
&lt;h2 id="browser-performance-profiling">Browser Performance Profiling&lt;/h2>
&lt;p>Using your browser&amp;rsquo;s developer tools, you are able to record and analyse a performance analysis. The Chromium developer tools have three tabs to help with this. Performance, Memory and Application.&lt;/p>
&lt;p>The Performance tab is perhaps the easiest to get going with. Click on that tab and then start profiling. Leave that for an amount of time that you estimate will let you see any ongoing performance issues. That might be just a few seconds or a few minutes. You will want to tick the &amp;ldquo;memory&amp;rdquo; option and probably don&amp;rsquo;t need the &amp;ldquo;Screenshots&amp;rdquo; option.&lt;/p>
&lt;p>The thing to look at first is likely to be the memory utilisation. There is a graph 1/2 way down the display that shows you some important metrics including the &amp;ldquo;JS Heap&amp;rdquo;. See how big that is getting by hovering over the line. Also look at how fast it is growing. You should see that the heap reduces periodically as the JavaScript engine does a &amp;lsquo;garbage collection&amp;rsquo;.&lt;/p>
&lt;p>You can also do multiple recordings and compare the heap over a longer period.&lt;/p>
&lt;h1 id="front-end-dashboard-uibuilder-http-in-out-nodes-etc">Front End (Dashboard, uibuilder, http-in/-out nodes, etc.)&lt;/h1></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category><category domain="https://it.knightnet.org.uk/tags/node.js">Node.JS</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/debugging">Debugging</category><category domain="https://it.knightnet.org.uk/tags/performance">Performance</category></item><item><title>A more comfortable way to edit the code for creating custom nodes</title><link>https://it.knightnet.org.uk/kb/nr-qa/easier-writing-custom-node/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/nr-qa/easier-writing-custom-node/</guid><pubDate>Mon, 18 Mar 2019 17:38:40 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/nr-qa/easier-writing-custom-node/</guid><description><div>Node-RED allows us to create custom nodes to extend the features. While this is a great feature, actually writing the code can be tricky. In part because the code for the admin configuration panel is contained in an html file containing 3 script entries that are Node-RED specific. This post shows you a relatively easy way to split that into 3 files and combine them with a build step using an npm cross-platform script.</div><div>&lt;p>When defining a new node in Node-RED, the code is contained in two files. An html file and a
JavaScript file.&lt;/p>
&lt;p>The JavaScript file contains the core code that is loaded into the server and does most of the
hard work. As this is a standard js file, nothing special is needed to edit it, your favourite
code editor or IDE will do the job nicely. My preference is VScode from Microsoft.&lt;/p>
&lt;p>However, the html file isn&amp;rsquo;t very comfortable to edit because any HTML it actually contains is
wrapped in some special &lt;code>&amp;lt;script&amp;gt;&lt;/code> tags that are only recognised by Node-RED and they throw out
your code editor making things really hard to read and process.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/javascript&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span> &lt;span class="nx">js&lt;/span> &lt;span class="nx">that&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">run&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">admin&lt;/span> &lt;span class="nx">ui&lt;/span> &lt;span class="nx">when&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">configuration&lt;/span> &lt;span class="nx">panel&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">opened&lt;/span> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-template-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span> &lt;span class="nx">html&lt;/span> &lt;span class="nx">that&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">used&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">admin&lt;/span> &lt;span class="nx">node&lt;/span> &lt;span class="nx">configuration&lt;/span> &lt;span class="nx">panel&lt;/span> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-help-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">...&lt;/span> &lt;span class="nx">html&lt;/span> &lt;span class="nx">that&lt;/span> &lt;span class="nx">is&lt;/span> &lt;span class="nx">used&lt;/span> &lt;span class="k">in&lt;/span> &lt;span class="nx">the&lt;/span> &lt;span class="nx">information&lt;/span> &lt;span class="nx">sidebar&lt;/span> &lt;span class="p">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To get round this, I&amp;rsquo;ve started creating a separate &lt;code>./node-src&lt;/code> folder and splitting the
content for this file into three source files: &lt;code>script.js&lt;/code>, &lt;code>template.html&lt;/code> and &lt;code>help.html&lt;/code>.&lt;/p>
&lt;p>Of course, you can call them whatever you like &amp;amp; will probably want to include the node-name
if you are creating multiple nodes.&lt;/p>
&lt;p>There is then a cross-platform executable that replaces the empty master with the contents of
the three files.&lt;/p>
&lt;p>Now all you have to do is to remember to run the build before pushing your changes to your repo and before publishing a new version to npm. That can also be automated as long as you are using npm to manage git. Look at the &lt;code>prepublishOnly&lt;/code> script which will automatically allow you to run the build before publishing. You can do similar things with git by &lt;a href="https://docs.npmjs.com/misc/scripts">setting up the appropriate scripts&lt;/a>.&lt;/p>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;p>To get this all working, you will need to firstly install a package called &lt;code>replace-in-file&lt;/code>.
Install this to the root of the folder holding you node.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npm install replace-in-file -D
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Note that I install it as a devDependency because it is only needed for the node&amp;rsquo;s editors and
not for end users.&lt;/p>
&lt;p>Next, add the following to the &lt;code>package.json&lt;/code> file, also in the root folder of your node.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;scripts&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;build&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;node ./bin/mergehtml&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;prepublishOnly&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;npm run build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>&lt;span class="err">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;bin&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;mergehtml&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;./bin/mergehtml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This lets you run the build on any platform supported by npm, including Windows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">npm run build
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, create folders &lt;code>./bin&lt;/code> and &lt;code>./node-src&lt;/code>. Into &lt;code>node-src&lt;/code>, put the three files and your master template. Into &lt;code>bin&lt;/code> put the &lt;code>mergehtml.js&lt;/code> file shown below.&lt;/p>
&lt;h2 id="binmergehtmljs">./bin/mergehtml.js&lt;/h2>
&lt;p>This is the code that does the magic. I overwrites the nodes html file (&lt;code>./nodes/node.html&lt;/code> in this example) with the blank template then replaces the three &lt;code>&amp;lt;script&amp;gt;&lt;/code> tags with the contents of the files from &lt;code>node-src&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="ch">#!/usr/bin/env node
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="ch">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/** Merge the various sections of nodes/uibuilder.html from the files in node-src/
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * Note that this is run from `npm run mergehtml` which puts the working directory
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * to the root, not `./bin`
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm">*/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">replace&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;replace-in-file&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">fs&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">require&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;fs&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//const path = require(&amp;#39;path&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// nodes\lib\uibuilder-help.html
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">myhelp&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/help.html&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">mytemplate&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/template.html&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">myscript&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">readFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/script.js&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Copy template - overwrite the nodes html file
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">fs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">copyFileSync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;./node-src/node.html&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;./nodes/node.html&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">options&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">files&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s1">&amp;#39;./nodes/uibuilder.html&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">from&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sr">/(&amp;lt;script type=&amp;#34;text\/javascript&amp;#34;&amp;gt;)(.|\n)*?(&amp;lt;\/script&amp;gt;)/gmi&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sr">/(&amp;lt;script type=&amp;#34;text\/x-red&amp;#34; data-template-name=&amp;#34;uibuilder&amp;#34;&amp;gt;)(.|\n)*?(&amp;lt;\/script&amp;gt;)/gmi&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sr">/(&amp;lt;script type=&amp;#34;text\/x-red&amp;#34; data-help-name=&amp;#34;uibuilder&amp;#34;&amp;gt;)(.|\n)*?(&amp;lt;\/script&amp;gt;)/gmi&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">to&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sb">`$1\n&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">myscript&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">\n$3`&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sb">`$1\n&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">mytemplate&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">\n$3`&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sb">`$1\n&lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">myhelp&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">\n$3`&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">options&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="nx">then&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">changes&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;MERGEHELP: data-help-name Modified files:&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">changes&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;, &amp;#39;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">.&lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">error&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;MERGEHELP: Error occurred:&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">error&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;MERGEHELP: Completed&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="node-srcnodehtml">./node-src/node.html&lt;/h2>
&lt;p>Here is the content of the &lt;code>node.html&lt;/code> file - you can use this for any project. You can put text between the tags if you like, even change the order of them if you prefer, the code should still work just fine. Obviously, any text you put between the open/close tags will be replaced.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/javascript&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-template-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">script&lt;/span> &lt;span class="na">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;text/x-red&amp;#34;&lt;/span> &lt;span class="na">data-help-name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;uibuilder&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/node-red">Node-RED</category></item><item><title>How to take control of JavaScript console output</title><link>https://it.knightnet.org.uk/kb/node-js/smart-console-logging/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/node-js/smart-console-logging/</guid><pubDate>Sat, 02 Feb 2019 00:52:46 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/node-js/smart-console-logging/</guid><description><div>All browsers have the console object that lets you output to the developer console log. But in production, you don't want this output, only in development. So here is the easiest way I've found to take control.</div><div>&lt;p>This is a simple example and really needs expanding to be more general purpose.&lt;/p>
&lt;p>It uses a global &lt;code>debug&lt;/code> variable to control output. If &lt;code>debug&lt;/code> is false, no output will occur.&lt;/p>
&lt;p>All functions of the console object are taken over by this function.&lt;/p>
&lt;h2 id="code">Code&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="cm">/** Debugging function
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @param {string} type One of log|error|warn|info|dir, etc
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @param {...*} msg Msg(s) to send to console
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * WARNING: ...args is ES6, it doesn&amp;#39;t work on IE11
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> * @since 2019-02-01 Apply any number of args
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cm"> **/&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//myDebug = function (type, ...args) {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">myDebug&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="nx">debug&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">var&lt;/span> &lt;span class="nx">type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">arguments&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">//console[type](...args)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="nx">console&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">type&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">apply&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kc">undefined&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[].&lt;/span>&lt;span class="nx">slice&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">call&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">arguments&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="c1">// --- End of debug function --- //
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/ecmascript">ECMAscript</category></item><item><title>What JavaScript versions are there and how do they map to Node.JS versions?</title><link>https://it.knightnet.org.uk/kb/node-js/javascript-node-versions/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/node-js/javascript-node-versions/</guid><pubDate>Fri, 04 Jan 2019 20:03:59 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/node-js/javascript-node-versions/</guid><description><div>There are now far too many versions of JavaScript. Worse, there are several ways to refer to a JavaScript version. Then we have Node.JS which has its own versioning. This post tries to summarise it all.</div><div>&lt;p>This is just a summary for my own reference. See &lt;a href="#references">References&lt;/a> below for more details.&lt;/p>
&lt;p>Please let me know if there are any errors. I will update the table periodically.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>ECMA-262 Version&lt;/th>
&lt;th>ECMAScript Year Version&lt;/th>
&lt;th>Publish Date&lt;/th>
&lt;th>Node.JS Version&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>N/A&lt;/td>
&lt;td>2009-12&lt;/td>
&lt;td>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>ES2015&lt;/td>
&lt;td>2015-06&lt;/td>
&lt;td>6.5.0+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>7&lt;/td>
&lt;td>ES2016&lt;/td>
&lt;td>2016-06&lt;/td>
&lt;td>7.0.0+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>8&lt;/td>
&lt;td>ES2017&lt;/td>
&lt;td>2017-06&lt;/td>
&lt;td>8.10.0+&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>9&lt;/td>
&lt;td>ES2018&lt;/td>
&lt;td>2018-06&lt;/td>
&lt;td>10.0.0+&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Notes:&lt;/p>
&lt;ul>
&lt;li>Versions of Node.JS prior to those shown are likely to support &lt;em>some&lt;/em> features of newer JS versions. The versions shown are those that support virtually all of the features.&lt;/li>
&lt;li>Some JavaScript features may not be implemented in Node.JS.&lt;/li>
&lt;li>Node uses the V8 JavaScript engine. Also used by the chromium browser (which underpins Vivaldi, Google Chrome, Opera and many others. Soon to be used by Microsoft Edge as well).&lt;/li>
&lt;/ul>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://en.wikipedia.org/wiki/ECMAScript">Wikipedia ECMAScript Article&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://kangax.github.io/compat-table/es6/">Kangax&amp;rsquo;s JavaScript Compatability Table&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://node.green/">Node Green&lt;/a> - Maps Node versions to JavaScript versions and shows what is supported in each version. Uses Kangax&amp;rsquo;s table.&lt;/li>
&lt;li>&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript">Mozilla Developer Network (MDN)&lt;/a> - Details each aspect of JavaScript as a reference, each page has a compatibility table showing browsers support. Uses Kangax&amp;rsquo;s table.&lt;/li>
&lt;/ul></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/ecmascript">ECMAscript</category><category domain="https://it.knightnet.org.uk/tags/node.js">node.js</category><category domain="https://it.knightnet.org.uk/tags/nodejs">nodejs</category></item><item><title>How to loop over JavaScript arrays and objects</title><link>https://it.knightnet.org.uk/kb/node-js/looping/</link><guid isPermaLink="true">https://it.knightnet.org.uk/kb/node-js/looping/</guid><pubDate>Fri, 04 Jan 2019 20:00:07 +0000</pubDate><guid>https://it.knightnet.org.uk/kb/node-js/looping/</guid><description><div>JavaScript can be a pain at times. Loops are a fundamental part of all computer languages but in JavaScript, there are some oddities. This post is a summary of the different loop features and when to use them. It is likely to be updated from time-to-time as the standards are still changing.</div><div>&lt;p>This is a personal, and incomplete reminder about doing efficient loops in JavaScript.&lt;/p>
&lt;p>Of course, you should generally start with whatever is &lt;em>simplest&lt;/em>. Generally you should not attempt
to optimise too soon.&lt;/p>
&lt;h2 id="arrays">Arrays&lt;/h2>
&lt;h2 id="objects">Objects&lt;/h2>
&lt;p>The old fashioned way still works &amp;amp; is still generally the fastest.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">keys&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">keys&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">sort&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nx">keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">obj&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">keys&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">]])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Somewhat faster version of the above (the length is not calculated on each loop and prefix iterator is slightly faster than postfix).&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">keys&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">obj&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">keys&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="nx">sort&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kd">var&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">len&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">keys&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">length&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="nx">len&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">obj&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">keys&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">]])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>From JS v5, you can use a combination of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">&lt;code>Object.keys()&lt;/code>&lt;/a> and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach">&lt;code>Array.prototype.forEach()&lt;/code>&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Object&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">obj&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">forEach&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">obj&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In addition, &lt;code>Object.values(obj)&lt;/code> does what you&amp;rsquo;d expect.&lt;/p>
&lt;p>&lt;code>for ... in&lt;/code> (&lt;a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/for...in">MDN&lt;/a>) - includes non-own properties.&lt;/p>
&lt;p>From JS v6 (ES2015), you can use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of">&lt;code>for...of&lt;/code>&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">key&lt;/span> &lt;span class="k">of&lt;/span> &lt;span class="nb">Object&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">keys&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">obj&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">obj&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In JS v8 (ES2017), &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries">&lt;code>Object.entries()&lt;/code>&lt;/a> was added which avoids having to look up each value in the original object.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Object&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">entries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">obj&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="nx">forEach&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">([&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">value&lt;/span>&lt;span class="p">])&lt;/span> &lt;span class="p">=&amp;gt;&lt;/span> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">value&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>Object.keys()&lt;/code> and &lt;code>Object.entries()&lt;/code> iterate properties in the same order as a &lt;code>for...in&lt;/code> loop. However, they &lt;em>ignore the prototype chain&lt;/em>. Only the object&amp;rsquo;s own enumerable properties are iterated.&lt;/p>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://perfjs.info/test/384A61CA-DA2E-4FD2-A113-080010D4A42B">JSperf Object Iteration Comparison&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object">How do I loop through or enumerate a JavaScript object? (StackOverflow)&lt;/a>&lt;/li>
&lt;/ul></div></description><author>Julian Knight</author><category domain="https://it.knightnet.org.uk/categories/development">Development</category><category domain="https://it.knightnet.org.uk/tags/javascript">JavaScript</category><category domain="https://it.knightnet.org.uk/tags/ecmascript">ECMAscript</category></item></channel></rss>