Undefined class when using external js script

Hi folks,

I'm trying (in my node's config screen) to instantiate a class that is supplied in a third party javascript file. Summarized it contains something like this:

...
class EmbeddedSVGEdit {
   ...
}
...
export default EmbeddedSVGEdit;

Found some code snippets on the internet (for that same file!) that do it like this:

<script src="https://github.com/SVG-Edit/svgedit/blob/master/editor/embedapi.js"></script>
<script>
   ...
  oneditprepare: function() {
      new EmbeddedSVGEdit(myOwnIframe);
  }
   ...
</script>

However that results in an error "Uncaught ReferenceError: EmbeddedSVGEdit is not defined".

So I thought this might be a timing issue, i.e. my oneditprepare being executed before the embedapi.js file is being loaded. So I changed my code to load the file via jQuery and add a (success) callback handler function:

<script>
   ...
  oneditprepare: function() {
      $.getScript( "https://github.com/SVG-Edit/svgedit/blob/master/editor/embedapi.js", function( data, textStatus, jqxhr ) {
          if (jqxhr.status == 200) {
               new EmbeddedSVGEdit(myOwnIframe);
          });
  }
   ...
</script>

But then the same error :woozy_face:

Does anybody have a clue what I'm doing wrong?

Thanks !!
Bart

At a glance, the url for the script you are using is to its github page and not the raw script itself.

1 Like

Morning Nick,
OMG. This can't be true.
I wanted to add that file to my svg-node's repository later on, and publish it automatically when the config screen requested it. But I thought: let's first load it directly from the web, and if that works I can use it locally. Completely forgotten that I had to use the raw file instead ...
Thanks for that already !!!!!

So I have changed my code to use the raw file:

$.getScript( "https://raw.githubusercontent.com/SVG-Edit/svgedit/master/editor/embedapi.js", function( data, textStatus, jqxhr ) {
     if (jqxhr.status == 200) {
          node.embeddedSvgEdit = new EmbeddedSVGEdit(iFrame); 
     }
});

But still same error:

image

This is the content of the input parameters I receive in the callback function:

image

I assume that all content in the file will be loaded by the Javascript runtime, as soon as I arrive in the callback? Or is the raw file also not correct, and should I load it locally?

Unless somebody sees another problem, I will try this evening to load the file from a local location. Currently it seems to be loaded correctly, and this is confirmed by what I see in the 'network' tab of Chrome's developer tools:

However I have a warning in my Chrome console log:

vendor.js:5 Cross-Origin Read Blocking (CORB) blocked cross-origin response https://raw.githubusercontent.com/SVG-Edit/svgedit/master/editor/embedapi.js?_=1567333419781 with MIME type text/plain. See https://www.chromestatus.com/feature/5629709824032768 for more details.

Don't understand why this happens, moreover since (see screenshot) Github seems to allow cross origin usage of the files...

But perhaps this blocking issue explains why the 'data' part of my response handler is undefined??

Anyway will try it locally to make sure ...

Taking a closer look, the file you're trying to load is a javascript module. So in theory you need type="module" as an attribute of your <script> tag. Although I've not used modules in the browser before, so I could be wrong.

1 Like

Nope Nick, you are again damn right! I had never heard of those ES6 modules before, but it seems that this was the golden tip I was waiting for...

Here a summary in case anybody ever needs it:

  • Server side: this part wasn't really necessary for this problem, but I wanted to have the file locally available. So I have added the embedapi.js to my own Github repository and I created an endpoint to make this file available:

    // Make the embedapi.js file accessible for the node's config screen
    RED.httpAdmin.get('/svg_graphics/js/*', function(req, res){
         var options = {
             root: __dirname,
             dotfiles: 'deny'
         };
     
         // Send the requested file to the client
         res.sendFile(req.params[0], options)
     });
    
  • Client side: here I load the ES6 module dynamically (i.e. not via a tag) and instantiate the class specified in it.

    // Load the embedapi.js from the Node-RED server (note that this is an ES6 module!)
    import('/svg_graphics/js/embedapi.js').then((module) => {
          // The EmbeddedSVGEdit class is the default export in the SVG-Edit module
          var EmbeddedSVGEdit = module.default;
          node.embeddedSvgEdit = new EmbeddedSVGEdit(iFrame);
    })
    

    The default export contains the class I was looking for:

    image
    And after the 'new' operator, at last my instance is created:

    image
    Remark: the slash / at the start of the import URL is required, otherwise it doesn't work.

Really appreciate you did some looking up for me !!!!!!!!!!!!

1 Like