stealjs / steal-conditional

Conditional loading
https://stealjs.com/docs/steal-conditional.html
MIT License
6 stars 1 forks source link

Isn't This deprecated in Favor of Dynamic Import? #65

Closed frank-dspeed closed 5 years ago

frank-dspeed commented 5 years ago

i think as soon as steal supports dynamic import() this can be deprecated full

justinbmeyer commented 5 years ago

Dynamic import and conditionals have different use cases. You want static (immediate) imports for pollyfills and such.

frank-dspeed commented 5 years ago

@justinbmeyer i use it like your readme explains it.

import('check') // Check returns import('conditional/'+browser) if needed

dynamic import allows url substitution and also importing and exporting of conditional needed shims and that.

justinbmeyer commented 5 years ago

But it doesn’t happen statically right? So you have to wait for the promise to resolve. You can’t use the polyfill immoderately then.

frank-dspeed commented 5 years ago

@justinbmeyer thats true but thats also the case with the sync version the whole code gets wrapped inside a promise and is async in my case the load result is even faster with my usage.

when you load the polyfill static it will still get enterpreted in sync and used after it is loaded.

i hope that made sence you can even use syncron code if you do it like jquery for example with its onDomReady event. but thats out of scope

frank-dspeed commented 5 years ago

what i want to say here is it makes no diffrence if you do

function check(){

}

check()

or use a promise for this as the resolve time of the promise is === execution and loading time like in the code example above most times the promise method is faster combined with other tech that i should not deep drive into now.

frank-dspeed commented 5 years ago
// Basic Needed Checks and Polyfills
// module support 
// Promise + import support
// Let Assume all imported modules patch global object
Promise.all([checkThatReturnsImportIfNeeded, otherCheckThatReturnsImportIfNeeded])
.then(()=>....excute other code)
justinbmeyer commented 5 years ago

@frank-dspeed I'm not totally sure what you are saying, but exporting a promise isn't what most people would want to do in a "needs a polyfill" use case.

Lets say I wanted to use WeakSet in some code and IE doesn't fully support WeakSet. I could write code like:

// set-thing.js
import 'weak-set-shim#?conditions.needs-weak-set-shim'

var set = new WeakSet();

export default {
  add(v){
    set.add(v);
  },
  remove(v){
    set.remove(v);
  }
};

Now someone could import this module and use it like most other modules:

// my-app.js
import setThing from "./set-thing";

setThing.add( ... );

Using import forces "downstream" users of the module to account for delays in loading. For example, if you wrote set-thing to use import(), you'd have to expose this statefulness downstream somehow. One way would be to export a promise like the following:

// set-thing.js
var weakSetPromise = window.WeakSet ? 
   Promise.resolve() : import('weak-set-shim')

export weakSetPromise.then(function(){
  return {
    add(v){
      set.add(v);
    },
    remove(v){
      set.remove(v);
    }
  }
});

Now my-app.js has to deal with that:

// my-app.js
import setThingPromise from "./set-thing";

setThingPromise.then(function(){
  setThing.add( ... );
})

This problem might keep flowing downstream.

This isn't really about load times. It's really about what a module can export. Conditionals make it so you can export APIs without exposing some sort of extra statefulness to handle when the module is actually ready to be used.

frank-dspeed commented 5 years ago

Given the Fact!! That import is always async and async always returns a promise! a promise that gets imported is unwrapped easy via await

// set-thing.js
//import 'weak-set-shim#?conditions.needs-weak-set-shim'
async function checkWeakMap() {
  if(!window.WeakSet) {
    return import('weak-set-shim')
  }
}

function setThing() {
  let set = new WeakSet();
  return  {
    add(v){
      set.add(v);
    },
    remove(v){
      set.remove(v);
    },
  };
}
// we Return setThing as the shim modifys window global in this case
export default checkWeakMap().then(()=>setThing())

now my app deals with that as a async wrapped app

// my-app.js
async myApp() {
  const setThing = await import("./set-thing");
  setThing.add( ... );
}()

Promise version

// my-app.js
import("./set-thing").then((setThing){
  Object.assign(window, { setThing });
}).then(()=>{
  // Regular App Code after Init
  setThing.add( ... );
})

setThing should be generated given the set

// set-thing.js
async function getWeakSet() {
  if(!window.WeakSet) {
    await import('weak-set-shim')
  } 
  return new window.WeakSet;
}

function setThing(set) {
  return  {
    add(v){
      set.add(v);
    },
    remove(v){
      set.remove(v);
    },
  };
}

export default getWeakSet().then(setThing)

For Better Chaining and all that i suggest to work always with dynamic import but sure the normal import at top level is also async that is the ESModule Goal that fetching parsing and execution is splitted

justinbmeyer commented 5 years ago

I don’t think JS supports await top-level like you are showing in my-app

frank-dspeed commented 5 years ago

@justinbmeyer you probally saw the old example watch in this issue my app uses a IIFE

// my-app.js
async myApp() {
  const setThing = await import("./set-thing");
  setThing.add( ... );
}()