# Scope of variables in external JS scripts

**URL:** https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048
**Category:** Core Development
**Created:** [25 June 2018 07:23 UTC](https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048 "2018-06-25T07:23:54Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)
#### Post date: [25 June 2018 07:23 UTC](https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048/1 "2018-06-25T07:23:54Z")

</div>

Hi folks,

Wanted to start experimenting with Blockly, so I added following lines (in the html file of one of my contributions):

```auto
<script src="https://blockly-demo.appspot.com/static/blockly_compressed.js"></script>
<script src="https://blockly-demo.appspot.com/static/blocks_compressed.js"></script>
<script src="https://blockly-demo.appspot.com/static/javascript_compressed.js"></script>
<script src="https://blockly-demo.appspot.com/static/demos/code/msg/en.js"></script>

```

However this resulted in following error:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/01426da17f35a7cdcd55ed8d8a5c3acf2944c4fa.png)

**1. ANALYSIS OF NODE-RED NODE**

When I put a breakpoint at the end of the **first script** (blockly\_compressed), seems that there are **TWO** Blockly variables available:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/ae2f5c1da393a15da5db2e0544176aeccbccbca3.png)

The first one has scope empty (don't know what this means ...) and second has global scope. Only the first one has a property '_Blocks_'.

Then I arrive in the breakpoint at the start of **second script** (blocks\_compressed), where only the global variable Blockly still exists:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/3226983ebe1cad3c065facb51bc908aaa7c91d50.png)

At line 4 they want to set the 'colour' of the Blockly.Block property, however an error will occur since that property is **undefined**.

**2. ANALYSIS OF BLOCKLY DEMO**

Blockly has provided a [demo app](https://blockly-demo.appspot.com/static/demos/code/index.html), which WORKS FINE so there must be some kind of difference between the demo web app and the Node-Red flow editor.

Again added a breakpoint at the end of the **first script** , where I see that there is only a **SINGLE** Blockly variable (containing the Blocks property):  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/244160c3efc85dd65ac309c3c193db738d8e0c64.png)

So when we arrive at start of the **second script** , the Blockly.Blocks is still available as global:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/1c55d138ebabb78006f4fd43dceed7aab1656ac3.png)

So in the demo app setting the colour (on line 4) will give no error...

**3. THE DIFFERENCE ?**

I'm now at the point where I'm running out of creativity ;-(

In the first file, the Blockly variable declaration and additiion of a Blocks property seems very natural to me:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/f469ebd326f43796a2f407eb71a338741cb861a6.png)

Does anybody could point me in some direction? The problem can easily be reproduced by putting the lines into the html file of some node ...

Thanks a lot !!!!!!  
Bart

---

<div class="post-metadata">

### Author: ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)
#### Post date: [25 June 2018 21:22 UTC](https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048/2 "2018-06-25T21:22:56Z")

</div>

Did a new (desperate) attempt to figure out what is going wrong.

Both programs (demo Blockly application and my Node-Red node) have the SAME script tags:

```auto
<script src="https://blockly-demo.appspot.com/static/blockly_compressed.js"></script>
...

```

But it seems that under the hood, the script is loaded in a different way by both programs:

**1. SCRIPT LOADING IN BLOCKLY DEMO APPLICATION**

At the start of the first script, the Blockly variable is already global, which is good!  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/fdfa563727c961bfcca5e020a2caf4f1898b0ee1.png)

And the call stack is very short ...

**2. SCRIPT LOADING IN NODE-RED NODE**

At the start of the first script, the Blockly variable has an empty scope (instead of global)???:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/bff16265b09ffbcb684a1640982d2c96d145f509.png)

And there seems to be a very long - jQuery related - call stack, based on ajax and globalEval. From this [explanation](http://cwestblog.com/2013/03/08/javascript-global-eval/) I would expect that the globalEval defines all the script variables as global. Don't get it ...

A bit further the Blockly variable is defined (but scope is still empty):  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/c0a2fd3d050558a89cf9602aa5e5b1e53f993de5.png)

And then only a part of the Blockly variable properties becomes global:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/65174ca8c9407f621a630e013e6b19f26d5962d2.png)

And that 'incomplete' global Blockly variable is used by the second Blockly script, and gives error due to missing properties ...

_Does thid ring a bell to anyone, why the scope of the Blockly variable is empty (instead of global) at the start of the script when using jQuery??? Do I need to load the script another way (without jQuery)?_

Bart

---

<div class="post-metadata">

### Author: ![knolleary](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/knolleary/32/3_2.png) [@knolleary](https://discourse.nodered.org/u/knolleary)
#### Post date: [25 June 2018 22:16 UTC](https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048/3 "2018-06-25T22:16:12Z")

</div>

Hi Bart,

the issue can be reproduced on a ‘static’ page if you swap the order of the first two script tags - putting `blocks_compressed.js` ahead of `blockly_compressed.js`.

When a page is first loaded, the browser will block whenever it hits a `<script>` tag and load them in order.

But scripts added dynamically are, by default, loaded asynchronously; they don’t block.

So when the four script tags are inserted in the page, they will be run in whatever order their network requests return the content to run - causing them to run in the wrong order.

It is possible to tell the browser to load the script synchronously, but it requires some JavaScript to do it:

```auto
<script>
[
  "https://blockly-demo.appspot.com/static/blockly_compressed.js",
  "https://blockly-demo.appspot.com/static/blocks_compressed.js",
  "https://blockly-demo.appspot.com/static/javascript_compressed.js",
  "https://blockly-demo.appspot.com/static/demos/code/msg/en.js"
].forEach(function(src) {
  var script = document.createElement('script');
  script.src = src;
  // set the async flag to false to force synchronous loading
  script.async = false;
  document.head.appendChild(script);
});
</script>

```

There’s far more information than you’ll care to know about script loading in [this article](https://www.html5rocks.com/en/tutorials/speed/script-loading/).

---

<div class="post-metadata">

### Author: ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)
#### Post date: [26 June 2018 18:47 UTC](https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048/4 "2018-06-26T18:47:04Z")

</div>

Hello Nick,

thanks for helping me out !! Your code snippet seems to work fine, so case closed …

I also thought - two days ago - that the problem was related to scripts loading in the wrong order. So I tried to do it like this:

```auto
<script>
    $.getScript('https://blockly-demo.appspot.com/static/blockly_compressed.js').done(function(data, textStatus, jqxhr) {
        $.getScript('https://blockly-demo.appspot.com/static/blocks_compressed.js').done(function(data, textStatus, jqxhr){
            $.getScript('https://blockly-demo.appspot.com/static/javascript_compressed.js').done(function(data, textStatus, jqxhr){
                $.getScript('https://blockly-demo.appspot.com/static/demos/code/msg/en.js').done(function(data, textStatus, jqxhr) {
                    // All scripts are loaded succesfully, so let's display Blocky in the div element
                    var workspacePlayground = Blockly.inject('blocklyDiv', {toolbox: document.getElementById('toolbox')});
                }).fail(function(jqxhr, settings, exception ){
                    console.log("en.js failed");
                    console.log(exception);
                    console.log(exception.stack);
                });
            }).fail(function(jqxhr, settings, exception ){
                console.log("javascript_compressed.js failed");
                console.log(exception);
                console.log(exception.stack);
            });
        }).fail(function(jqxhr, settings, exception ){
            console.log("blocks_compressed.js failed");
            console.log(exception);
            console.log(exception.stack);
        });
    }).fail(function(jqxhr, settings, exception ) {
        console.log("blockly_compressed.js failed");
        console.log(exception);
        console.log(exception.stack);
    });

```

But that resulted in the **same errors**.

And afterwards I added `breakpoint;` statements in both scripts, and there were executed in the correct order. So I assumed that the sequence wasn’t the problem …

But now I can continue with Blockly. Up to the next problem 😭

Bart

---

<div class="post-metadata">

### Author: ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)
#### Post date: [15 July 2018 10:04 UTC](https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048/5 "2018-07-15T10:04:39Z")

</div>

Hi Nick (@knolleary),

I'm currently trying to make my [node-red-contrib-blockly](https://github.com/bartbutenaers/node-red-contrib-blockly) ready for NPM, but still some issues... Like this one:

When I add N of those blockly nodes to my Node-Red flow, all the **_JS scripts will be N times loaded_**. Do you know what is the best way to avoid this. By enabling '_somehow_' caching on the script tags?

Thanks !  
Bart

---

<div class="post-metadata">

### Author: ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)
#### Post date: [15 July 2018 19:02 UTC](https://discourse.nodered.org/t/scope-of-variables-in-external-js-scripts/1048/6 "2018-07-15T19:02:45Z")

</div>

**Edit:** I refactored my blockly node to match your code snippet above, and now the files are only loaded **once** from the server, undependent of the number of nodes used in the flow.

However when the flow editor page is **refreshed** , all my files are loaded again 😩

Tried to solve it by adding a **'Cache-Control'** header variable on the server side:

```auto
RED.httpAdmin.get('/blocky/js/*', function(req, res){
        var options = {
            root: __dirname + '/lib/',
            dotfiles: 'deny'
        };
        
        res.set('Cache-Control', 'public, max-age=31557600, s-maxage=31557600'); // 1 year
        res.sendFile(req.params[0], options)
});

```

But it still keeps loading the files. I installed ChromeCacheView, and it seems that the files are not available in the cache.

Do you have any advise on this ? Can I specify on the browser side that it should cache the files?  
Bart
