squint 2024-01-23

Is there a recommended way to forward context to squint?

Like how in Sci you have the option to add namespaces via the context: (sci/eval-string "(inc x)" {:namespaces {'user {'x 2}}})

tell me what exactly you are trying to do

I might have an idea but I'm not totally sure what you mean

I'm playing again with this idea of https://jsfiddle.net/jeroenvandijk/ygrnpx8h/8/, but it doesn't seem to work anymore. I was forwarding vars via the javascript env

This fiddle still worked: https://jsfiddle.net/jeroenvandijk/ygrnpx8h/8/ Are you suggesting something broke?

No i'm using it from a module now, that's the only difference I can think of

But the way I reference variables from the js context might not be the best way. I'm a bit surprised by the results I get (mostly nil references)

repro? still not sure what you're trying to do

the only way to bring in stuff into a module is with import or access global values using globalThis

In squint you access global values using js/whatever or js/globalThis.whatever

I'm loading the above module via [:script {:type "module" :src "/squint-script.js"}] and it mostly seems to work, but for instance _closest is not known anymore

I can try putting it in the fiddle again. Maybe I'm just misunderstanding how js modules work

I'm trying to have something like [:a {:on {:click '(-> el (htmx/addClass "is-active"))}}]

if you want _closest to be globally available you need to export it

and then import it from another module

or stick it on the global Object, like globalThis._closest = closest

👍 1

I wonder if the modules are a good fit for element event handlers. But I'll try something with export. Thanks!

Ok I found a workaround for imports. eval doesn't support import so I did something like mentioned here https://2ality.com/2019/10/eval-via-import.html

you can use the :repl true option to get JS output that you can eval in an async function

see how that works in the squint playground: https://squint-cljs.github.io/squint/

but if import() works fine and you don't need the return value, I guess that works too. the playground uses both things, depending on whether the REPL toggle is set or not

Thanks. I will check what happens with :repl

also pass context "return" and then you can wrap the stuff in a

(async function() { ... here })()
it will then be async, not sure if that's a problem

Yeah I switched from 'expr' to 'return' before. I am now trying all three values, but I don't see a difference yet. Before I did, so I must do something wrong

I'll cleanup what I have first

This is what works for me now. • It don't use eval anymore, but an import hack (https://2ality.com/2019/10/eval-via-import.html). Not sure if it can work otherwise without global references. • I'm using querySelectorAll, because I chose to go for on instead of on:click and so I don't need document.evaluate anymore. Also document.evaluate doesn't seem to like the dynamic import as it was complaining about the document that it was iterating over being changed.

I'm guessing this code is not very suitable for production environments as the dynamic imports for every event handler feel a bit heavy. But for dev envs it could work (I'm guessing). In production it could be compiled in a couple of different ways.

why is dynamic import heavy?

I'm just guessing that I could have some overhead, but I have no idea really. I'll test it a bit now

btw it seems you have to :context keys in the options map?

yeah just saw that. I cleaned this up. Although javascript doesn't seem to care much

context: repl doesn't work. it's repl: true

I think with repl: true and context: return you could still do the async handlers and you don't need to use elide-imports

as a bonus, even top level await will then work in your handlers :)

repl: true, context: return and no ellide imports. I get the following. Maybe I am misunderstanding what you have in mind. I could wrap it in an async block, but I don't think it would make a difference

perhaps you're using an ancient squint version?

possible 🙈 I'll check

also please show the invocation of compileString as code

yes very old version I see sorry

could be worse ;)

I'm not sure why the event seems to fire twice here

I don't know how to make the scenario you proposed work yet

doesn't matter, if it works it works ;)

✔️ 1

Ah it was fired because I had the javascript in two places. That is fixed now

Thanks for your help. I might experiment more and give some updates :)

👍 1

there is still an old version of squint string.js in that fiddle

ah indeed. I wasn't using the string namespace yet. I fixed it

I think I can't see the change unless you re-publish it

can you give me the url? somehow I don't see the change

ah /16 vs /10

ah yeah, missed that

here is the REPL-based version with a working string example: https://jsfiddle.net/borkdude/zbdyf2v7/7/

which uses eval

Nice! Thanks, looks better

I'm adding

var extraImports = `
globalThis.user = globalThis.user || {};
var htmx = await import('');
globalThis.user.htmx = htmx;
Above ${compiled.javascript}} to make it work with htmx. I think the import() syntax is slightly different than the static import . It doesn't give me the htmx var I need yet. I'm assuming this can be fixed and I just need to look into the how this works exactly

you could prefix the cljs code with:

(require '["" :as htmx])

similar to how I did it for str

Cool, yes that generates this code for me. I think there is something particular with htmx as only one of the three ways seem to work (not this one I guess)

https://stackoverflow.com/questions/70619055/how-to-import-htmx-variable/70622085#70622085 The first one worked in my previous approach, but in this dynamic approach it doesn't know htmx

Actually only

import "";
worked. Because it doesn't have a default export

I really have no idea what I'm doing, maybe time to read up on these modules a bit 😬

Ok found the issue with htmx, I need to wait for the ready event before I can use anything of the htmx module 😅 Then I am able to use your solution

I use something like this to do this

import ''

var htmx2;

function ready(fn) {
   if (document.readyState !== "loading") {
       setTimeout(fn);
   } else {       
       document.addEventListener("DOMContentLoaded", fn);
   }
}

ready(function() {
    htmx2 = htmx;
})

I guess this is because htmx does stuff asynchronously after it's loaded?

perhaps htmx itself has a callback that is called after it did its stuff?

yeah i suspected something like this after looking at the source code and having a vague memory https://github.com/bigskysoftware/htmx/blob/0b6769a257ac1bf50f3f7228f8a5be5964970f7e/src/htmx.js#L3824-L3832

I kept getting an empty module otherwise. I had no idea why, but now i know

> perhaps htmx itself has a callback that is called after it did its stuff? Yeah could be. I didn't find any hints yet. Didn't find many examples of using it as an javascript API either

I see htmx has an onLoad callback but I'm not sure what it's for. but you have a working solution anyway so that's good

yeah exactly, it is good enough for now

Btw, are you considering adding :refer :all to squint? I'm sort of doing something like this manually now by building a context module and adding all exports to the globalThis.user

Ok np, happy to do it myself here hehe

refer all doesn't exist in CLJS and also not in JS

ah yeah makes sense

also it messes with static analysis, clj-kondo doesn't like refer all at all

yeah true I understand

I'm playing with my own user namespace now. I can write things like this:

[:button {:on {:click '(log (confirm "hi"))}} "click me"]
Not sure yet what I think of it, but I like it's conciseness

I think it makes sense for little snippets like this yes

why not [:button {:click ...}]?

or :on-click

I guess :click and :on-click would not conflict with the native :onclick so it is possible. I have no strong reasons yet. Maybe in the future supporting other events and then you only have to search for the on attribute and not for all the different kind of events. But yeah, could definitely change this

Also maybe having multiple events on one element. Not sure if there are use cases for this

Still not sure what exactly is going on with the htmx module. I'm ignoring it for now