squint 2024-09-26

What do i have to provide to squint to get it working with a function like that

(defn cljs-module [filename]
  [:script {:type "module"}
   (->
    (str "cljs/" filename ".cljs")
    io/resource
    slurp
    squint/compile-string
    h/raw)])
The resulting code is the module javascript code i could generally use in a <script type="module"> tag. My question is i have following cljs code
(require '["" :as react])
(require '["" :as hooks])

(defn Counter []
  (let [[counter setCounter] (hooks/useState 0)]
    #jsx [:<>
          [:div "Counter " counter]
          [:button {:onClick #(setCounter (inc counter))} "+"]
          [:button {:onClick #(setCounter (dec counter))} "-"]]))

(defonce el (js/document.getElementById "cljs"))

(react/render #jsx [Counter] el)
and want to be able to compile it on the server and render it in my page and the preact component should show up. What am i missing? Importmaps? cause the browser tells me the generated jsx can't be understand ๐Ÿ˜•

JSX is not something that a browser understands, you need to transpile that further, unless you compile using the runtime format. Let me find this example...

thought so but would it be possible with squint compiler to get that compiled version

let me find out how to use this on the command line... there is a way

that would be awsesome

than i could extend the clj-mnl-web thing where you can even compile preact react stuff on the fly and embed it in the site ๐Ÿ˜ฎ

ah wait, you use squint/compile-string

can you feed it some options like:

{:jsx-runtime {:import-source ""}} 

if this isn't documented anywhere, we should

ok i still have issues ๐Ÿ˜„ i compile a simple gist one moment D

I have to look up how to clone a gist again...

ok first thing: upgrade squint

:git/sha "c86d83bd3741a710e2f80fecd413801ddd456e64"

then you'll encounter:

Uncaught TypeError: Failed to resolve module specifier "squint-cljs/core.js". Relative references must start with either "/", "./", or "../".

which you can fix by updating the import maps

So this whole thing works now:

(ns index
  (:require [babashka.deps :as deps]
            [hiccup2.core :as h]
            [org.httpkit.server :as srv]
            [cheshire.core :as json]))

(deps/add-deps '{:deps {io.github.squint-cljs/squint {:git/url "" :git/sha "c86d83bd3741a710e2f80fecd413801ddd456e64"}}})

(require '[squint.compiler :as squint])

(defn compile-jsx [src]
  (squint/compile-string src {:jsx-runtime {:import-source ""}}))

(defn cljs-module [filename]
  [:script {:type "module"}
   (->
    filename
    slurp
    compile-jsx
    h/raw)])

(defn page [_]
  {:body (str (h/html
               [:html
                [:head
                 [:script {:type "importmap"}
                  (h/raw
                   (json/generate-string
                    {:imports
                     {"squint-cljs/core.js" ""
                      "squint-cljs/src/squint/core.js" ""}}))]
                 ;;
                 ;; thats the module i want to compile as plain js module where the jsx is allready transpiled
                 ;;
                 (cljs-module "test.cljs")]
                [:body
                 [:div#cljs]]]))
   :status 200})

(srv/run-server #'page {:port 8888})
(println "Server started at ")
@(promise)

๐Ÿ˜ฎ exactly what i wanted ๐Ÿ˜„

this is amazing THANK YOU SOOOOO MUCH

just one more questions should i add the other deps in the import map too ?

regarding squint? or is there a bundled version

what other deps?

in the import map

"squint-cljs/core.js": "./src/squint/core.js", "squint-cljs/string.js": "./src/squint/string.js", "squint-cljs/src/squint/string.js": "./src/squint/string.js", "squint-cljs/src/squint/set.js": "./src/squint/set.js", "squint-cljs/src/squint/html.js": "./src/squint/html.js",

it depends if you use those, if so, yes

ok great thats really cool now

looking forward to your blog post on this sometime ;P

will do so sir still figuring stuff out thats why i pushed that clj-mnl thing out to see what i can do better ๐Ÿ˜„

One thing I ended up doing is the following

(def $ react/createElement)

($ :div {} "counter")
It works without any JSX transforms and the syntax is something I'm already used to from UIX

@martinklepsch all of the above works without JSX transforms

exactly and its amazing

Ah, it does the JSX stuff at runtime? Hadn't seen that before ๐Ÿ™‚ Just also wanted to share an alternative approach

also great @martinklepsch but i wanted to have all stuff happen on the server now i can write cljs without the need of node ๐Ÿ˜„

i'm also looking forward to move from compojure to ruuter so my idea also works for babashka

isn't that much of a change i guess ๐Ÿ˜„

it should be called borkweb ๐Ÿ˜„

๐Ÿ˜† 1

"dude, where did you get this stuff...." "on the borkweb"

๐Ÿคฃ 1

all you need than is babashka thats amazing

@borkdude btw the multipart thing works with httpkit BUT we need to implement the entire multipart handling on our own ๐Ÿ˜ž

thats the only part i see that would be missing except that nearly everything worked really really well

yeah that sucks

have you looked into multipart ๐Ÿ˜• it looks like not much fun ๐Ÿ˜„

I've implemented multipart requests for bb.http-client ;)

so that's the other side

I guess you could use that, but do the reverse on the receiver side ;)

or the workaround: base64 encoding

btw @mathaeus.peter.sander I noticed that the squint version in the import maps is also a bit behind, might want to update that as well

someone commented on X that preact and webcomponents go well together https://preactjs.com/guide/v10/web-components/ never tried it, but perhaps a nice experiment with squint

hi! loving squint ๐Ÿ™‚ what is the current situation wrt to being able to connect directly to the browser from the repl? this is the only thing that's stopping me from giving up "classic" cljs right now it's not so much about needing to dynamically redefine vars (hot reload with vite basically makes this redundant I guess?) but I miss being able to check the app state, test functions that call browser api's etc

๐Ÿ‘ 2

That's the major missing piece right now, but something I plan to work on

you're right that hot-reloading can be taken care of using vite

I think it's technically possible, just have to connect the dots. I've done this for #scittle as well: https://github.com/babashka/scittle/tree/main/doc/nrepl

thanks a lot, looking forward to seeing what you come up with ๐Ÿ™‚ another question: you mention pitfalls around data structures being vanilla js, do you have any examples of this in practice? like, if I create a map and treat it just like I would in regular clj/cljs and don't let it touch any third-party library functions, can I assume it won't mutate?

that's a correct assumption, the squint stdlib doesn't mutate if the corresponding function in CLJS doesn't mutate either

one difference is structural equality, e.g. (= {:a 1} {:a 1}) would return false in squint

there's deepEquals stuff for this in JS land, but squint compiles = just to ===

also be aware that JS objects only have string keys, which is another difference

often stuff "just works" but when trying out an Advent of Code puzzle which uses assoc a million times on an object, you'll notice a difference in performance. There's good ways to optimize this, but it's different from CLJS where structural sharing makes it more efficient

it's also possible to use ImmutableJS in squint of course, for parts where this is important

ok yeah those are quite annoying but workable I guess ๐Ÿ˜… not writing super perf-sensitive stuff so that should be fine thanks again!

๐Ÿ‘ 1

there is a Node.js nREPL for squint, but nothing that connects to the browser. hopefully soon-ish!

๐Ÿ‘€ 1

yes I saw that re data structures: when I think about it maybe having to constantly write #js et al is equally annoying so it kind of cancels out

> squint does support compiling to a REPL format so you can then poke at global stuff.. How do I do that? I think I need some debugging in browser context

I quickly published a new squint version 0.8.115. There you can pass a --repl option to either squint compile or squint watch to compile into the REPL format

Sorry of documented elsewhere, but what does โ€œRepl Formatโ€ mean? Where does the output go?

it's not really documented as of today, but you can view the difference in the squint playground by turning "REPL mode" on and off: https://squint-cljs.github.io/squint/

@sr Poor man's browser REPL solution: squint does support compiling to a REPL format so you can then poke at global stuff like this:

I'm looking into a proper solution right now, but takes a while

nice so this is available right now?

if I merge a branch with a small change and publish that, yes, then you can run npx squint watch --repl which watches the sources directories and compiles using repl output

I could do that now if that's useful to you

I'm looking into making the nREPL server work over a websocket connection to make eval work in the browser, but this is more gnarly

ok I think I'll wait for full nREPL support

blown away by how responsive you are! ๐Ÿ™

๐Ÿ™ 1