Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient dynamic import of multiple scripts in module type Web Worker

I have a web app that needs to dynamically load multiple scripts on startup. For efficiency, it needs to request all the scripts over the network in parallel. For correctness the scripts must execute in a specific order.

In the DOM this can be achieved by dynamically adding <script> tags with the async property set to false. The requests go out in parallel, and the scripts run in the order the tags are added.

In a classic type Web Worker (the default), you can use importScripts(...arr). The browser gets a list of all the scripts in one go, and so can request them all simultaneously, but guarantee the scripts run in the order specified.

In a module type Web Worker, things get trickier. importScripts is not allowed in a module type worker (Chrome throws Module scripts don't support importScripts() if you try). Workers can't add script tags. You can however use dynamic import() - but that only accepts one script. If you import scripts one at a time like this:

async LoadScripts(scriptsArr)
{
    for (const src of scriptsArr)
        await import(src);
}

This serializes the network requests to run one after another, which is inefficient.

The only thing I can think of to do is dynamically create a module that consists solely of import '...'; lines, and dynamically import that, like this:

async LoadScripts(scriptsArr)
{
    // Create a string with a module full of import statements
    const moduleStr = scriptsArr.map(src => `import '${src}';`).join("\n");

    // Create a blob from the string
    const blob = new Blob([moduleStr], { type: "application/javascript" });

    // Dynamic import the blob, which in turn loads all the import statements
    await import(URL.createObjectURL(blob));
}

This feels like a pretty ugly hack though, like a glorified eval(). Is there a better way?

like image 916
AshleysBrain Avatar asked Sep 17 '25 06:09

AshleysBrain


1 Answers

For correctness the scripts must execute in a specific order.

If the scripts do have dependencies, they should declare these explicitly with import statements.

Creating a single module that imports everything in the right order, like the one you are constructing dynamically, is also an option, probably the list of modules is pretty static actually.

If you import scripts one at a time, it serializes the network requests to run one after another, which is inefficient.

If the modules have their dependencies declared, you can load them all at once:

function loadScripts(scriptsArr) {
    return Promise.all(scriptsArr.map(src => import(src));
}
like image 111
Bergi Avatar answered Sep 19 '25 22:09

Bergi