Fork me on GitHub
#squint
<
2024-01-23
>
jeroenvandijk12:01:00

Is there a recommended way to forward context to squint?

jeroenvandijk12:01:35

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

borkdude12:01:25

tell me what exactly you are trying to do

borkdude12:01:42

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

jeroenvandijk12:01:00

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

borkdude12:01:10

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

jeroenvandijk12:01:40

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

jeroenvandijk12:01:23

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)

borkdude12:01:44

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

borkdude12:01:13

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

borkdude12:01:41

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

jeroenvandijk12:01:34

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

jeroenvandijk12:01:09

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

jeroenvandijk12:01:22

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

borkdude12:01:23

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

borkdude12:01:32

and then import it from another module

borkdude12:01:47

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

šŸ‘ 1
jeroenvandijk12:01:47

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

jeroenvandijk15:01:30

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

borkdude15:01:15

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

borkdude15:01:33

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

borkdude15:01:21

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

jeroenvandijk15:01:04

Thanks. I will check what happens with :repl

borkdude15:01:34

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

jeroenvandijk15:01:22

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

jeroenvandijk15:01:42

I'll cleanup what I have first

jeroenvandijk15:01:21

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.

jeroenvandijk15:01:29

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.

borkdude15:01:48

why is dynamic import heavy?

jeroenvandijk15:01:19

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

borkdude15:01:45

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

jeroenvandijk15:01:12

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

borkdude15:01:16

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

borkdude15:01:03

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

borkdude15:01:00

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

jeroenvandijk15:01:15

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

borkdude15:01:44

perhaps you're using an ancient squint version?

jeroenvandijk15:01:58

possible šŸ™ˆ I'll check

borkdude15:01:40

also please show the invocation of compileString as code

jeroenvandijk15:01:51

yes very old version I see sorry

jeroenvandijk15:01:59

0.2.28 šŸ™ˆ

borkdude15:01:35

could be worse ;)

jeroenvandijk16:01:13

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

jeroenvandijk16:01:57

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

borkdude16:01:12

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

āœ”ļø 1
jeroenvandijk16:01:06

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

jeroenvandijk16:01:34

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

šŸ‘ 1
borkdude16:01:53

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

jeroenvandijk16:01:26

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

borkdude16:01:46

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

jeroenvandijk16:01:02

saved šŸ˜…

borkdude16:01:29

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

borkdude16:01:44

ah /16 vs /10

jeroenvandijk16:01:04

ah yeah, missed that

borkdude16:01:21

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

borkdude16:01:12

which uses eval

jeroenvandijk16:01:13

Nice! Thanks, looks better

jeroenvandijk17:01:16

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

borkdude17:01:12

you could prefix the cljs code with:

(require '["" :as htmx])

borkdude17:01:21

similar to how I did it for str

jeroenvandijk17:01:15

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)

jeroenvandijk17:01:24

Actually only

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

jeroenvandijk17:01:53

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

jeroenvandijk17:01:08

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

jeroenvandijk11:01:03

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

jeroenvandijk11:01:07

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;
})

borkdude11:01:02

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

borkdude11:01:14

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

jeroenvandijk11:01:51

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

jeroenvandijk11:01:16

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

jeroenvandijk11:01:17

> 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

borkdude11:01:41

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

jeroenvandijk11:01:01

yeah exactly, it is good enough for now

jeroenvandijk11:01:09

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

jeroenvandijk11:01:31

Ok np, happy to do it myself here hehe

borkdude11:01:42

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

jeroenvandijk11:01:51

ah yeah makes sense

borkdude11:01:58

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

jeroenvandijk11:01:09

yeah true I understand

jeroenvandijk11:01:36

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

borkdude11:01:23

I think it makes sense for little snippets like this yes

borkdude11:01:46

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

borkdude11:01:54

or :on-click

jeroenvandijk11:01:50

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

jeroenvandijk11:01:47

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