squint icon indicating copy to clipboard operation
squint copied to clipboard

Qwik QRL

Open brandonstubbs opened this issue 1 year ago • 13 comments

In the Qwik Framework, they have a concept of QRL.

I have the following button:

(ns app
  (:require ["@builder.io/qwik" :refer [component$ useSignal]]
            ["./app.css"]))

(defn -App []
  (let [count (useSignal 0)]
    #jsx [:button {:onClick$ #(set! (.-value count) (inc (.-value count)))}
          "count is " (.-value count)]))

(def App (component$ -App))

This is the output

<button onClick$={(function () {return count1.value = (count1.value + 1);})}>count is {count1.value}</button>

This would be the ideal output:

<button onClick$={() => { return count1.value = (count1.value + 1);}}>count is {count1.value}</button>

Qwiks $ optimiser needs serializable values.

brandonstubbs avatar Mar 30 '24 15:03 brandonstubbs

Can you be more specific on what is the difference in output? Is that only the arrow function vs function function?

borkdude avatar Mar 30 '24 15:03 borkdude

Yeah seems it works better with the arrow function clojure output

brandonstubbs avatar Mar 30 '24 15:03 brandonstubbs

I don't see how function is less serialisable than () => {}

borkdude avatar Mar 30 '24 15:03 borkdude

This is the error output: image

Maybe more an issue their side

brandonstubbs avatar Mar 30 '24 15:03 brandonstubbs

So I guess we could use a syntax in squint to produce "arrow" functions instead, e.g. (fn ^:whatever []), I'm not sure. Any ideas? Also, can you try out if changing that function to () => {} in the output really fixes the issue?

borkdude avatar Mar 30 '24 15:03 borkdude

Yeah changing the output fixes the issue.

Is there a reason the function is preferred over arrow functions? I wonder if maybe this would be better to be a squint compiler flag to emit all functions as arrow functions? Or at least functions in JSX as arrow functions.

brandonstubbs avatar Mar 30 '24 15:03 brandonstubbs

I some cases function is necessary since () doesn't support this

borkdude avatar Mar 30 '24 15:03 borkdude

I think let's park this for now. I am not familiar with the framework. I was just getting the vite templates to work. I will open an issue with them first to see why the function way doesn't work, as (def App (component$ -App)) this part is also a $ optimisation and seems to work.

brandonstubbs avatar Mar 30 '24 16:03 brandonstubbs

Can function be serialized less well than arrow fns? This seems like an odd requirement on Qwiks side.

Could be useful to provide some low level syntax helpers in squint to emit the respective syntax, maybe?

martinklepsch avatar Mar 30 '24 16:03 martinklepsch

So it seems you can wrap the function in their $ function:

(ns app
  (:require ["@builder.io/qwik" :refer [component$ useSignal $]]
            ["./app.css"]))

(defn -App []
  (let [count (useSignal 0)]
    #jsx [:button {:onClick$ ($ #(set! (.-value count) (inc count)))}
          "count is " (.-value count)]))

(def App (component$ -App))

This compiles to:

<button onClick$={$((function () { return count1.value = (count1 + 1);}))}>count is {count1.value}</button>

If the extra paren wasn't added around the function this would work. It should look like this instead:

<button onClick$={$(function () { return count1.value = (count1 + 1);})}>count is {count1.value}</button>
//                 ^

brandonstubbs avatar Mar 30 '24 17:03 brandonstubbs

I some cases function is necessary since () doesn't support this

Can function be serialized less well than arrow fns?

a squint compiler flag to emit all functions as arrow functions?

Arrow functions are not just syntax sugar, they have different behavior. Though the exact description of the main difference eludes me right now (something something scoping?), here's a quick example:

$ node

> (function(){}).prototype
{}

> (()=>{}).prototype
undefined

> new (function(){})
{}

> new (()=>{})
Uncaught TypeError: (intermediate value) is not a constructor

Another difference is hoisting.

Not being able to specify the kind of function in Squint is kind of a non-starter for me.

A ^:something would be very much welcome; but since arrow functions are also a shorthand, IMHO (fn ...) should emit arrow functions by default and the longer form (fn ^:something) should be used for full functions.

egasimus avatar Mar 30 '24 20:03 egasimus

IMHO (fn ...) should emit arrow functions by default

This isn't done because of compatibility with existing CLJS code

borkdude avatar Mar 30 '24 20:03 borkdude

I created an issue but also realized that maybe we should just rename this one, then all context is in one place.

martinklepsch avatar Mar 30 '24 21:03 martinklepsch

#499 is fixed, I think this should work now

borkdude avatar Apr 05 '24 10:04 borkdude