I’d like to implement require but lazy load a :namespace
map compiled to cljs instead of a Clojure source file, is this possible?
looking at https://github.com/borkdude/sci/blob/19242bf2cf549fd7895696e65761c04e32c61f7f/src/sci/impl/evaluator.cljc#L193 it seems it’s not but seems easy enough to add. Would a PR be welcome for it?
@mkvlr Can you sketch the scenario of what should happen on require?
As long as you return the source string using the :load-fn
it should work
@borkdude I want to load an cljs advanced compiled module, basically merge the namespaces map on load
not Clojure source
so basically load https://github.com/sicmutils/sicmutils/blob/master/src/sicmutils/env/sci.cljc#L105 lazily but having it part of my advanced compiled bundle (but as a separate module)
@mkvlr ah, yeah, I think you can mis-use :load-fn
for this by checking the namespace, then updating your ctx manually and then return an empty source string
(update ctx :env swap! assoc-in [:namespaces your-ns-name] your-ns)
something like this@borkdude thanks, will give it a try and let you know!
@borkdude returning an empty source and changing the env works. But I still need a async variant of :load-fn
. https://github.com/borkdude/sci/issues/511
@mkvlr if this is going to be async, how do you prevent using the required namespace in successive expressions?
I was thinking, maybe you can fire the async operation and then wait in some loop until the async operation has completed?
eh, this is JS async hell again
yes
I thought we can contain it but there’s not really a way, right?
it basically means sci/eval has to become async?
you are fetching the module via some http request?
yes
is something like this not possible? async operation -> marks flag when done loop { wait for flag to become true }
we need await
in CLJS ;)
I'm not sure what the consequences will be if load-fn has an async counterpart. Will then everything become async?
I think so, that’s why its called a leaky abstraction right?
https://eloquentjavascript.net/11_async.html says: > If we had used the handler’s return value as the response value, that would mean that a request handler can’t itself perform asynchronous actions. A function doing asynchronous work typically returns before the work is done, having arranged for a callback to be called when it completes. So we need some asynchronous mechanism—in this case, another callback function—to signal when a response is available.
So an alternative would be to include the module inside some dom node or JS variable as a string and load it from there maybe? Or will this have negative consequences?
Isn't is possible to get synchronous loading by creating a dom node which refers to that file and then reading the contents from that dom node?
(thinking of workarounds)
a dom node which does a GET request and gets populated with a string response from your server
and then that is fed to load-file
load-fn rather
I think it’s just not possible to do async work from a non-async function or do I have a fundamental misunderstanding?
yes, the workaround I suggest is making everything sync
yikes
it will block your UI, but for require I think it's reasonable, since this is what happens in CLJ too
will try it, thanks!
they even added serialized-require to CLJ now to make it more synchronous
yeah, but you can still have other threads running in this case?
pretty sure that @thheller made cljs_eval
return a promise for the same reason: https://github.com/thheller/shadow-cljs/blob/206d4029a80afa267835782516a9cb8eca92e8bf/src/main/shadow/cljs/devtools/client/shared.cljs#L424-L452
of course, but for loading a namespace from an external resource, I don't think it's unreasonable to show a spinner and wait for it to be loaded. it simplifies the model drastically
we can make everything async, but this will be a major change
this doesn’t sound so good either
> Just because appendChild() has returned does not in anyway guarantee that the script has finished executing He is talking about the JS eval
but the response is there. We have sync eval in sci
so this should work
no, I’m loading a js module
😱
hehe
think I need to look at how async could be supported in sci and sleep on it
so what would happen if you wrapped the sync sci API functions in your own async functions?
so any eval string you do would be async and the string could be coming from an http request?
would that be problematic when you eval code that does the require
and uses it in the same cell?
maybe it wouldn't be so bad to introduce some async API functions
don't know how deep the rabbit hole would be
but worth an experiment I'd say
probably the analyzer can stay sync
also the parser can stay sync
I mean, we would add async functions, not remove the sync ones
I’ll give it a try, probably tomorrow
thanks for your help!
:thumbsup:
@mkvlr btw, I'm not entirely sure about the comment on SO:
eval("1 + 1")
2
this is entirely sync
btw, you do need to allow this, many sites forbid itbut there might be a way to do this safely
of course this is hacky, so an async API would be the best
but in theory, I think you can do it all synchronously: the request/response + js eval