External modules without bundling in typescript

in #development6 years ago (edited)

Last week I finished the Preact-cli template and this week I begun on a project to make use of that template. I've decided to make a new website for spelmakare.se as practice before doing an actual new project using the template.

Background for today's problem

I wanted to be able to use external modules (such as dsteem) without the need to actually bundle the whole module with my own scripts. I've made attempts at this in the past and always had issues getting it to work consistently.

When creating the production script you can define modules you do not want included, and then those modules can be added externally with <script> tags in the html. The benefit is that you get a smaller script file for your site and that the module can be loaded from a distributed network, like cdnjs. The last bit is beneficial in particular, because if you have visited one site with a lib that another site also uses, in many cases your browser can use the cached file you already have from the first site.

This whole excluding thing is what has caused me issues in the past. Possibly because of my limited knowledge, but the result none the less the same... a day spent solving a technical issue like this, instead of swiftly making an actual project. If I got one module working, then the next has had some sort of failure and so forth.

Today I decided to get this solved.

Today's solution

After doing some research I cooked up this solution that fits my needs. It is easy to use, gives you full Intellisense when writing code and seems to be consistent in functionality.

I'm using dsteem as an example.

$npm install dsteem

We will not actually use dsteem in the code, we only install it to get the declarations. There are other ways to do this, but this is quick, simple and has no impact except increasing the file size of our node_modules folder a bit.

First we create a helper function to use when loading external scripts. You give the script tag an unique ID and the url to the script file. An event listener is configured and a callback will trigger as soon as the script file has finished loading.

/**
 * Load external script files to avoid bundling.
 * 
 * @param scriptID string for tag ID.
 * @param scriptSrc url to script file.
 * @param callBack callback function to be triggered when script file loaded.
 */
export function extScriptLoader(scriptID: string, scriptSrc: string, callBack: any) {

    // Append script if none exists.
    if (document.body.querySelector("#" + scriptID) === null) {

       // Callback when script loaded.
       let finishedLoading = () => {
            callBack();
            document.getElementById(scriptID).removeEventListener("load", finishedLoading);
        }

        let script = document.createElement("script");
        script.id = scriptID;
        script.src = scriptSrc;
        document.body.appendChild(script);

        document.getElementById(scriptID).addEventListener("load", finishedLoading);
    }

    // Callback directly as script already exists.
   else {
        callBack();
    }
}

In the script file where we will use dsteem. First we declare dsteem (making use of what we installed earlier) to get Intellisense working, and then use the helper to load the script

declare const dsteem: typeof import("dsteem");

extScriptLoader("steemScript", 'https://unpkg.com/dsteem@^0.10.1/dist/dsteem.js', () => {
    this.createClient();
});

createClient is only a test function I've done to check so this works, it looks like this:

async createClient() {
    this.client = new dsteem.Client("https://api.steemit.com");

    const accounts = await this.client.database.getAccounts(["smjn"]);

    accounts.forEach(account => {
        document.getElementById("newsItem").innerHTML = account.name;
    });
}

Visiting the page it will check for the unique script ID, if none found, it will append the script tag to the body and the script file gets downloaded. When done it calls back and that triggers the fetching of my Steem account and when ready it updates the "newsItem" to contain the name of my account.

moduleloading.gif

Thanks for reading!

Sort:  

Hi @smjn!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your UA account score is currently 1.824 which ranks you at #28640 across all Steem accounts.
Your rank has dropped 154 places in the last three days (old rank 28486).

In our last Algorithmic Curation Round, consisting of 299 contributions, your post is ranked at #288.

Evaluation of your UA score:
  • Only a few people are following you, try to convince more people with good work.
  • Your contribution has not gone unnoticed, keep up the good work!
  • Try to work on user engagement: the more people that interact with you via the comments, the higher your UA score!

Feel free to join our @steem-ua Discord server

Congratulations @smjn! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You made more than 3000 upvotes. Your next target is to reach 4000 upvotes.

Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

Meet the Steemians Contest - Special attendees revealed
Meet the Steemians Contest - Intermediate results

You can upvote this notification to help all Steemit users. Learn why here!

Congratulations @smjn! You received a personal award!

1 Year on Steemit

Click here to view your Board of Honor

You can upvote this notification to help all Steemit users. Learn why here!

Coin Marketplace

STEEM 0.20
TRX 0.20
JST 0.034
BTC 89846.05
ETH 3077.33
USDT 1.00
SBD 2.96