Hi, would it be possible to configure scittle to resolve external libraries imported via <script> tags, like so?
<script src="" type="application/javascript"></script>
<script src="" type="application/javascript"></script>
<script type="application/x-scittle">
(ns my-ns
(:require [clojure.string :as str]
["@codemirror/state" :refer [EditorState]]))
...
</script>
would that require a custom build of scittle, like you do with plugins? I mean to tell scittle to use the :async-load-fn option...
yeah, it would require some (breaking) changes, but I wonder if I can accomodate both ways in one build, both have their trade-offs. Perhaps it's possible to include scittle in a second way that does it the ESM + async way
amazing this already works:
(ns scittle-build
(:require [sci.core :as sci]
[sci.async :as scia]
[scittle.core :as scit]
[shadow.esm :refer [dynamic-import]]
[scittle.impl.error :as error]))
(swap! scit/!sci-ctx
sci/merge-opts {:async-load-fn (fn [{:keys [ctx libname]}]
(.then (dynamic-import libname)
(fn [mod]
(js/console.log :require libname
:mod mod)))
{:handled true})})
(set! scit/eval-string (fn [txt]
(try
(scia/eval-string* @scit/!sci-ctx txt)
(catch :default e
(error/error-handler e (:src @scit/!sci-ctx))
(throw e)))))with the import mapping eg. “@codemirror/state”: “https://cdn.jsdelivr.net/npm/@codemirror/state/dist/index.js”, then it can eval
(ns foo
(:require ["@codemirror/state"])
nice!
note that scia/eval-string* returns a promise, so you should handle the promise error probably
now I guess I’ll go find the 1000 implementation of the async-load-fn we did already 🙂
well not 1000 probably...
1000 + 1 Promise pending
exactly!
what are you working on?
extracting with Philippa the stuff behind the split-view editor from Clerk
trying to write code once but target more build envs like shadow/scittle/squint possibly 🤞
nice :)
I’m a bit confused now, it seems forms in the namespace gets evaluated before the requires are resolved (via async-load-fn), this kind of makes sense in an async setting, but how can forms refer to the required names?
you should return handled true from the promise
then the code will run after the promise, not parallel
ah, ok, I was returning it from the the load-fn body
right
I now have two tags:
<script type="application/x-scittle" src="folio.cljs"></script>
<script type="application/x-scittle" src="demo.cljs"></script>
first loads just fine, the second however doesn’t seem able to require the namespace defined by the firstbecause async
yeah
the code that loads the script tags must handle the promises in order
ok, then I also need to change eval-script-tags*
yup
or I also copy the ns defined in the first into the sci ctx
it’s not clear at this point what goes where
it's not clear to me what you mean with "or I also copy the ns defined in the first into the sci ctx"
if you change scittle.core/eval_string to be async, you also need to account for that in other places
I need to swap a bunch of nss into scittle.core/!sci-ctx in order for the example above to work at all
btw I wouldn't merge this since that is a breaking change, but for experimentation it's ok
the order will work once you fix the eval-script-tags to work with promises
sure, I can experiment with our build so far
thank you!
once you're finished, please let me know, perhaps we can find a way to make scittle1 work with scittle async so we don't have breakages and we can have both behaviors at once
ok, will do!
I think this will mean a new var scittle.core/eval-string-async and perhaps a new attribute on the script tags to indicate that it's ES6 code
but we can figure that out later
cool, yes
I think we can make eval-script-tags work with both sync and async code by just using Promise.resolve on the return value and always work in a promise-like fashion
then we'll just leave eval-string synchronous for people who already used it and introduce a new var for async evaluation
Got the sequential eval working 🙂
but still cannot demo the editor because of a react mismatch error when using hooks
oh yeah, that again
perhaps you can pin the react version using import-maps
could it be react version shipped with reagent the problem
I do pin them to 18.2.0
no, react isn't shipped with reagent, with scittle you provide your own react version
in the script tag
I’m adding reagent to the sci context
and reagent requires react from cljcljs
scittle already has a reagent module
this means that react isn't packaged along with scittle, you need to provide your own (global) version
hmm, but I’m using my own build
are you using target esm?
yes
in our code I expect requires ["react" :as react] to be picked by the import map now
ok, you can check nbb which also packages reagent without react with esm
I've made a specific version of reagent there to work around some of the issues
yeah, I was thinking of forking it with the string requires
I already did that :)
cool, under which repo?
but it’s based on reagent 1.1.1 which expects react 17 I think?
I didn't even use string requires there, I think I ran into specific issues so I just made it depend on a global being defined
could be, it's been a while. I don't follow the react trends
I just did this: https://github.com/borkdude/nbb-reagent/blob/315d702436719ea3a9a356773d6a10038ce9ea75/src/reagent/dom.cljs#L9C1-L9C41
yeah, I’m seeing that, I’ll try with the string require I’m not super keen on this global stuff
Is there any specific reason to prefer sci.configs for reagent than to use sci.core/copy-ns? I see e.g. set-default-compiler! is missing in sci.configs ?
just try it and you will find out
the string require didn’t fix my issue, and also if I’m providing reagent through :namespaces in the sci context, it will pick the one compiled by shadow right? so string requires will be sourced from npm_modules right?
yes, but just look at nbb for how to configure so that it won't pull in react from your project
then I have to setup the goog/global thing
no, I mean the shadow config
ok I see
or wait, :keep-as-import as we did before
you need both the string require + keep-as-import
yeah, trying that
I don't think this is possible since "@codemirror/state" refers to something external which is not known by scittle or the JS environment, right?
should work with cherry though if you stick the complete CDN url in there: https://dev.livecodes.io/?template=clojurescript
but usually when you use a script tag in this way, the script defines a global which you can then use
An example of codemirror with scittle: https://babashka.org/scittle/codemirror.html
oh, would squint-js + an import map, more appropriate?
oh, your example has na import map
scittle will work, but you need to access the codemirror stuff via the globals it defines (see example)
or if it only defines modules, you even need to define globals yourself:
<script type="importmap">
{
"imports": {
"codemirror": "",
"@codemirror/commands": "",
"@codemirror/search": "",
"@codemirror/autocomplete": "",
"@codemirror/lint": "",
"crelt": "",
"@nextjournal/lang-clojure": "",
"@nextjournal/lezer-clojure": "",
"@lezer/highlight": "",
"@lezer/lr": "",
"@lezer/common": "",
"@codemirror/language": "",
"@codemirror/state": "",
"@codemirror/view": "",
"style-mod": "",
"w3c-keyname": ""
}
}
</script>
<script type="module" type="application/javascript">
import * as cm from 'codemirror';
import * as lc from '@nextjournal/lang-clojure'
import * as cv from '@codemirror/view';
import * as cs from '@codemirror/state';
= cm;
= lc;
= cv;
globalThis.cs = cs;
scittle.core.eval_script_tags();
</script> yeah I saw that... I was thinking more of keeping the cljs code as is to suit different targets (e.g. shadow)
squint or cherry should work I think
this is a minimal example of how to compile and run: https://squint-cljs.github.io/squint/
nice thank you!
I see, the eval part is done via an import of url encoded data
indeed
I think you could theoretically use eval if you would wrap it in a self-executing async function
hmm, but then import doesn't work as is
so yeah, that's why it's done this way
I’ll check it out
thank you!
I'm contemplating an output that is more suited for hot-reloading / nREPL, then I'd have to emit import() instead and some global stuff where (defn foo []) becomes the_namespace.foo = function and then you could likely also also use eval
could sci async also support require of js modules using import maps or does it already maybe?
yes, sci async can
remember this: https://twitter.com/borkdude/status/1532281699018629121
if you insert the right import maps in that page, dynamic import using those aliases will automatically work, this is just browser behavior
👌