0
votes

I am desperately searching for a way to combine static imports (bundling) with dynamic imports (amd). As Bundler i am currently using webpack+babel-env for polyfills (btw: i am so tired of all the config, all the limitations and all the magical stuff happening i would very happily get rid of webpack).

Using webpack to create AMD modules was not satisfying because requirejs makes debugging quiet complicated and webpack just does not like the idea of a modular build/multiple entry points. To clarify: I have many entry points that will use some shared libraries. For webpack its always the concept of "one bundle", that controls everything. I read about dynamic imports and figured it to be the future-proof way to go.

So i ended up with this idea:

const library = await import("library.js");

export default function() {
    return library.foo("bar");
}

or for multiple dependencies some kind of

const depenencies = await Promise.all([
    import("library1.js"),
    import("library2.js")
]);
const library1 = dependencies[0];
const library2 = dependencies[1];

export default function() {
    return library1.foo("bar") + library2.bar("baz);
}

Of course i started implementing my own loader function to make the syntax nicer

const [library1, library2] = await load('library1.js', 'library2.js');

But all of that does not work, because the export gets defined before the import Promise is resolved. So i would need to pre-analyze the target-module to find out about the dependencies and add the special handling to my load function. And i would still be in async context, so its possible, that - even then - it would not work.

I want to achieve something very similar to AMD, where i can define a module, that has a dependency for another module, that should be loaded in async fashion by the browser.

My primary goal is an intuitive way of coding because the source is goint to be used in a medium-skilled team. I dont want to add a async init function to each module, that will load its dependencies, because that would result in code, that would be very hard to understand.

Just imagine i provide some preact-components (or whatever) and want to share common/generic components across multiple modules. Every module would need to import the preact-core, so -of course- i would want to provide that preact core as a separat module (vendor/preact.js).

But i would still want to code something like:

const Preact = await import("vendor/preact");

export default class StatefulComponent extends Preact.Component {
    render() {
        return "hello world";
    }
}

Using ES6 i would need to do something like:

export default async function init() {
    return new Promise(resolve => {
        const Preact = await import("vendor/preact.js");
        class StatefulComponent extends Preact.Component {
            render();
        }
        resolve(StatefulComponent);
    });
}

That is just silly and ugly...

Is it correct, that the import() api is in no way suited for dependency management? Is my only option AMD/requirejs and removing webpack?

If the solution is super-easy and i am just to stupid to see it, its because i tortured my brain with AMD/UMD/CommonJS/ES6/andsoonandsoforth the last days and am pretty pissed at javascript in general at the moment.

1

1 Answers

0
votes

There's no need to get THAT messy but if you do have exports that depend on import then they will need to be async (promise based).

What I would do is something like this:

//mylibrary.js
export default (async function(){
    let dep1 = await import('1');
    let dep2 = await import('2');
    //so on and so on...

    return {
        myClassThatDependsOnDep1,
        myFunctionThatDependsOnDep2,
    }
})();

Which you would could then use it on a similar fashion:

(async function(){
   let myLibrary = await import('mylibrary.js')
                   .then(m => m.default);

   //You use `myLibrary` here
   //                      v
   
})();

With TLA it's possible to forgo the async IIFE here.