skip to Main Content

I’m trying to create an application following the architectural model present on the implementation of OneSignal’s Web Push applications.

Basically, OneSignal asks its user to add two JavaScript codes at the end of the page:

<script src="https://cdn.onesignal.com/sdks/web/v16/OneSignalSDK.page.js" defer></script>
<script>
  window.OneSignalDeferred = window.OneSignalDeferred || [];
  OneSignalDeferred.push(function(OneSignal) {
    OneSignal.init({
      appId: "YOUR_ONESIGNAL_APP_ID",
    });
  });
</script>

The first script refers to OneSignalSDK.page.js, which is nothing more than a simple command responsible for adding another script inside the <head> tag.

The second one, seems that he uses a existing commands within the script that was imported within the <head> tag, in order to make it global through the window variable:

window.OneSignalDeferred = window.OneSignalDeferred || [];

So that he can then use its methods and functions:

OneSignalDeferred.push(...);

To achieve this type of architectural model, I started by creating my own script that is usually added at the end of my HTML page:

<script src="./StackOverflowSDK.page.js" defer></script>
<script>
    window.StackOverflowDeferred = window.StackOverflowDeferred || [];
    console.log('StackOverflowDeferred: ', StackOverflowDeferred);
</script>

The code below is my StackOverflowSDK.page.js, which is responsible for loading another JavaScript file within the <head> tag:

(() => {
    "use strict";
    function importSDK(numberVersion){
        var s = document.createElement('script');
        s.defer = true;
        s.src = "http://localhost/StackOverflow/StackOverflowSDK.page.es6.js?v=".concat(numberVersion);
        document.head.appendChild(s);
    }
    importSDK(10001);
})();

Importing the above code works correctly, and the StackOverflowSDK.page.es6.js script is implemented inside the <head> tag perfectly.

The code below presents the StackOverflowSDK.page.es6.js file:

(() => {

    class StackClass {
        static init(e){
            //....
        }
    }

    window.StackOverflowDeferred = StackClass;
})();

The problem is that the command window.StackOverflowDeferred = window.StackOverflowDeferred || []; returns an empty array instead of a StackClass class reference.

How to solve this problem?

2

Answers


  1. It’s a pattern I personally recognize from GA or GTM, the idea is to have an array-like interface (usually just the push method) and to default back to an array before the script is loaded. Once the script is fully loaded, you initialize the actual instance with what was in that variable if it exists.

    Essentially, you don’t know whether you have the fully-loaded version or not, but it doesn’t matter.

    <script src="./SomeSDK.page.js" defer></script>
    <script>
        window.SomeSDKDeferred = window.SomeSDKDeferred || [];
    </script>
    

    // SomeSDK.page.js

    (() => {
    
        class SDK {
            constructor(values) {
                values.forEach(value => this.push(value));
            }
    
            // [...]
    
            push(/* [...] */) {
                // [...]
            }
    
            // [...]
        }
    
        window.SomeSDKDeferred = new SDK(window.SomeSDKDeferred || []);
    })();
    

    If you absolutely need to have the actual variable, then just load your script using defer and position it in the DOM after the SDK.

    <script src="./SomeSDK.page.js" defer></script>
    <script src="./someThing/thatDependsOn/SomeSDK.js" defer></script>
    
    Login or Signup to reply.
  2. use the DOMContentLoaded event, which stipulates:

    The DOMContentLoaded event fires when the HTML document has been
    completely parsed, and all deferred scripts… have downloaded and executed.

    <script>
    document.addEventListener("DOMContentLoaded", () => {
      // your code here
    });
    </script>
    

    The old-school way, used by jQuery and libraries like it (which should not be necessary nowadays) can be found here:

    https://www.npmjs.com/package/domready

    or here:

    https://gist.github.com/nathankleyn/613221

    which essentially boils down to looping until a variable becomes available:

    while ( window.someGlobalVar === undefined ) {
        // blocks
    }
    
    console.log(window.someGlobalVar)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search