Fork me on GitHub
#clojurescript
<
2021-10-26
>
javi07:10:43

any cljs libraries for indexDb anyone can recommend? i will just be doing some key/val pair storage and retrieval.

mmer08:10:18

I am a fan of clojure. However, recently I became aware of Svelte as a web front end. Has anyone looked at whether there could be a similar approach taken, but using clojurescript instead of javascript?

Juλian (he/him)08:10:58

isn't Svelte compiled to JavaScript, just like ClojureScript is? do you mean using ClojureScript with some framework similar to Svelte, instead of Svelte? or do you want to have something like Svelte that compiles to ClojureScript before being compiled to JavaScript?

Juλian (he/him)08:10:29

or have Svelte call ClojureScript functions?

mmer12:10:15

STtll, not as slick as Svelte.

Ty16:10:04

All svelte does is introduce a compile step and some syntactic sugar that offers the ability to do reactive stuff without writing the boilerplate. Under the hood it's really just observables and a blow out/unrolled version of surgical DOM updates.

Ty16:10:07

I love svelte, don't get me wrong. In JS-land it's definitely the best thing. But if all you want is some nice sugar that unrolls to some reactive DOM updates, you can probably do this in CLJS using macros

Ty16:10:45

You could have the macros wrap either react components (so something like reagent or helix, or even just react), or you could probably do something with actual dom updates yourself. Your macros could even do some versioned generation for ids/tags like what svelte does.

Galaux12:10:01

Hey chan ! I'm wondering what's the activity status on Cljss https://github.com/clj-commons/cljss I don't see much commits recently so was wondering whether it was "stable so not much news" or "dead" and if "dead": then what do people use to have some sort of css-in-js (well … css-in-cljs actually).

Galaux13:10:15

I guess all you need is actually a bunch of functions and a CSS tool such as Tachyons or Garden/Herb … ?

dnolen13:10:14

@mmer Svelte has chosen a compilation strategy - and that strategy is analyzable - https://github.com/halfnelson/svelte-it-will-scale/blob/master/README.md

1
dnolen13:10:50

FWIW - I do not think it's all that interesting - if you're going to write a small amount of JS why do you even need it?

dnolen13:10:17

if you going to write a very large application - the math does not work in it's favor

mmer14:10:44

Svelte is not just about component size. It takes an approach where the code for binding for reactivity are done in a very terse and clear manner.

dnolen14:10:04

that is the subjective stuff

dnolen14:10:17

I'm just talking about all the marketing which ignores decades of compilation literature

dnolen14:10:42

Svelte is an inlining expander - they say this is for code size - but the literature says exactly the opposite

mmer14:10:14

My experience of creating an app in Svelte versus reframe were very differing. I liked reframe, but svelte really helped me do things in a very simple and direct way. I really was not trying to dis the clojure script way, but rather trying to encourage perhaps some new thought as to how clojurescript apps could be built. Having the script, html and styles all together makes a great deal of sense.

Ty16:10:50

FWIW mmer I totally get your point of view. As a long time JS dev I was enamored with svelte when I first learned it. Having what feels like very pure JS/Html/CSS is so refreshing. It's definitely the winner for me in the JS world right now, just in pure terms of expressivity. The thing is though, CLJS has all of the features of svelte just due to being a lisp. Macros are approximately equivalent to compile time expansion, they are just more powerful. And while CLJS does typically see HTML/CSS wrapped in a DSL (like what you get with reagent, the Hiccup-esque stuff), the thing is that it exposes all of these things as first-class language primitives. I won't say it's the better approach for everyone, but I will say this. I've been using JS for everything for a decade, and I absolutely love svelte and would still use it right now for a project depending on the circumstances. But CLJS is just better 😃 You get most of the same things as first class language features.

Ty16:10:14

This video encapsulates a lot of what draws me to lisp. I think it may be worth watching. https://www.youtube.com/watch?v=43XaZEn2aLc&amp;ab_channel=PapersWeLove

❤️ 1
Ty16:10:33

Svelte kit is a bit of a different story, maybe. As far as svelte components and expansion goes, I think CLJS is miles ahead. Svelte kit (or the old sapper stuff) gives you a bunch of interesting SSR/hydration stuff that I think is compelling. I'm not knowledgeable enough about the clojurescript ecosystem (yet) to know if there's an out of the box equivalent.

phronmophobic16:10:39

@mmer I definitely agree that Svelte does some things that we can learn from. When you assign a value to a variable, it works like updating a reference. To determine the reference, the compiler will analyze your code and trace where each property of a component came from. Practically speaking, that enables: 1. Updating a reference that was passed to two different components will update both components 2. A component can have instances that refer to multiple parts of the app state without any special changes or bloat Afaik, for the most popular clojurescript libraries • Fulcro can do #1, but not #2. • Re-frame/reagent can do both, but it usually requires special changes or bloat (eg. see https://github.com/day8/re-com/tree/master/src/re_com) This can be done in cljs via macros and I would love to see it happen. I know this is something @U8MJBRSR5 is working on with https://github.com/green-coder/vrac

👍 1
mmer16:10:39

@UTT4YNYNS and @U7RJTCH6J thanks for you replies.

Vincent Cantin17:10:18

Vrac's approach is a step further: from the user's perspective, how the reactivity work does not matter. What matters to the user is to write down enough information that can be read by the framework to make everything work.

phronmophobic17:10:55

Agreed. The downside of svelte's approach is that it's still very procedural and components are not first class (last I checked).

Vincent Cantin17:10:45

(side note: I don't know how Svelte is working) 😅

phronmophobic17:10:51

> What matters to the user is to write down enough information that can be read by the framework to make everything work. Yea, I think they're already doing that.

phronmophobic17:10:22

You should check it out and and play with it. It is actually pretty interesting conceptually.

phronmophobic17:10:29

Svelte's compiler actually knows about user interfaces. For example, Svelte can help with UI specific features like accessibility. That would be a cool thing for cljs frameworks to improve on.

👍 1
dnolen14:10:20

the above is just my opinion about the compilation strategy that Svelte has chosen - some elements of Svelte are certainly reproducible in ClojureScript - but overall like I said I do not think it's that interesting as compilation strategy because of the inflection point problem

dnolen14:10:40

the other thing is that a trivial ClojureScript thing for the web will never be as small as Svelte no matter what you do

dnolen14:10:51

~25k gzipped

dnolen14:10:59

so if you want Svelte - just use Svelte

dnolen14:10:56

if you like ClojureScript and you're ok w/ the minimum size - then you could do a Svelte thing pretty easily w/ Google Closure Library as the target

mmer14:10:31

@dnolen I was not commenting on the bundle size, as I know the clojurescript way of doing things had this covered a long time ago. It was more the way that the components are expressed and in particular the way the reactivity components work and are expressed. There is no need to explicitly pub/sub it works that out. The thing that phased me about Svelte is the javascript side, when I find clojure more natural.

dnolen14:10:16

ok so you're interest is more specific, hard to infer that from the above 🙂

mmer14:10:16

@borkdude that is heading in the right direction. One aspect of svelte that I really like is the component level scope for css.

mmer14:10:22

@dnolen sorry, perhaps I raised this in the wrong group - was not sure where to ask a general question about web frameworks in clojurescript.

dnolen14:10:46

fwiw, long ago on my blog I never bothered w/ React or other dependencies

mmer14:10:05

Thanks for replying, one thing that the Svelte guys have done very well is the only svelte.repl as a way to show how to build apps. It is a very easy way to learn.

dnolen14:10:19

and I always thought ClojureScript was quite competitive if you just rely on the simple GCL pieces - the size grows pretty slowly

dnolen14:10:10

so there's certainly room for a lighter thing when that's desirable

mikerod14:10:57

When type hinting a var in CLJS: (1) Is it used for :infer-externs? (2) Do you need to fully-qualify it or can it be from a shorthand :import declaration? eg.:

(:import [some.pkg Thing])
;;= ...
;;= Choice 1
(def ^js/Thing x <something>)
;;= Choice 2
(def ^js/some.pkg.Thing x <something>)
(3) Does it even matter what the ^js/<symbol> is under <symbol>?

dnolen14:10:56

it used because we look up the type to narrow the extern rather than dropping it on Object

dnolen14:10:40

(:import ...) is mostly for Google Closure compatible libs - so you don't need hints for this

dnolen14:10:15

so based on what you've said - I don't think you need to be hinting at all

dnolen14:10:53

^js means something global - so yes it must be fully qualified

Joe14:10:45

I have the following input element that takes a CSV file and uploads it:

[:input {:type "file"
         :id upload-button-id
         :on-change #(let [file (-> % .-target .-files (aget 0))]
                        (upload-file-fn file))}]
However when I attempt to upload the same file twice in a row (after fixing errors for example), the on-change event doesn't trigger as the file is the same one. My question is how do I 'reset' this value of the file before checking on-change?

dnolen15:10:08

hrm haven't seen this before - https://lit.dev

dnolen15:10:41

React semantics - but much smaller payload

Ty16:10:13

Thought this was preact before I saw the above message.

lilactown16:10:01

I stay far away from custom elements/web components at this point. not worth my time

☝️ 2
mikerod15:10:16

@dnolen I believe you are correct there. I was using it for hinting a goog.* ns that was :import’ed. So it does seem the type hint isn’t useful at all. > ^js means something global - so yes it must be fully qualified Would a non-closure global thing never have a reason to use :import? If :import was used would the ^js/Type hint automatically be qualified with an :import package name on it, or would it be needed to explicitly type out the fully-qualified symbol within the hint? I know that in Clojure, there were old issues around type hints not being qualified automatically in certain contexts and resulting in unqualified hints later used in the compiler that were broken. So this seemed a similar situation to me in cljs and I was not clear on the expectation.

dnolen15:10:37

@mikerod type hints are never really need in ClojureScript - only for performance

dnolen15:10:58

but you really shouldn't use them in you own code, there's a lot of inference in place now that allows them to flow if you use the core library

dnolen15:10:19

actual externs are a case where they might be useful - but it's a minor thing really

dnolen15:10:38

:import is only for Google Closure libraries where you need to import a constructor

mikerod15:10:46

Thanks for clarifying. My main concern in this particular case was to ensure externs inference worked. However, as you said, google closure things are already covered and no manual intervention needed. I was also mistakenly thinking :import would be used more broadly than Google Closure libraries, which now that I think about that, doesn’t make sense.

dnolen15:10:48

where the namespace is the constructor

👍 1
dnolen15:10:06

@mikerod it will work regardless

dnolen15:10:17

even if you typehint ^js

dnolen15:10:31

I can't remember the last time I manually wrote an externs - it's been a couple years if not more

👍 1
dnolen15:10:21

Came across Lit reading this - https://web.dev/ps-on-the-web/ - interesting stuff

roelof18:10:30

anyone a hint why I do not see the text and input button on my webpage here

roelof18:10:55

`(ns ^:figwheel-hooks learn-cljs.weather
  (:require
   [goog.dom :as gdom]
   [reagent.dom :as rdom]
   [reagent.core :as r]
   [ajax.core :as ajax]))


(defonce app-state (r/atom {:title "WhichWeather"
                            :latitude 0
                            :longtitude 0
                            :zip-code ""
                            :temperatures {:today {:label "Today"
                                                   :value nil}
                                           :tomorrow {:label "Tomorrow"
                                                      :value nil}}}))

(defn handle-response [resp]
  (let [today (get-in resp ["hourly" 1 "temp"])
        tomorrow (get-in resp ["hourly" 5 "temp"])]
    (swap! app-state
           update-in [:temperatures :today :value] (constantly today))
    (swap! app-state
           update-in [:temperatures :tomorrow :value] (constantly tomorrow))))

(def api-key "fa9930ab5e2a87f9770d1c90d68f9da1")

(defn get-forecast! []
  (let [lat (:latitude @app-state)
        lon (:longtitude @app-state)]
    (ajax/GET ""
      {:params {"lat" lat
                "lon" lon
                "units" "metric" ;; alternatively, use "metric"
                "appid" api-key}
       :handler handle-response})))

(defn handle-response-coordinates[resp]
   (let [lat (get-in resp ["coord" "lat"])
         lon (get-in resp ["coord" "lon"])]
     (swap! app-state
          update-in [:latitude] (constantly lat))
     (swap! app-state
           update-in [:longtitude] (constantly lon))
     (get-forecast!)))


(defn get-coordinates []
  (let [zipcode (:zipcode @app-state)]
    (ajax/GET ""
     {:params {"q" zipcode
                "units"  "metric"
                "appid" api-key}
      :handler handle-response-coordinates})))


(defn title []
  [:h1 (:title @app-state)])

(defn temperature [temp]
  [:div {:class "temperature"}
   [:div {:class "value"}
    (:value temp)]
   [:h2 (:label temp)]])

(defn postal-code []
  [:div {:class "postal-code"}
   [:h3 "Enter your postal code"]
   [:input {:type "text"
            :placeholder "Postal Code"
            :value (:postal-code @app-state)
            :on-change #(swap! app-state assoc :postal-code (-> % .-target .-value))}]
   [:button {:on-click get-coordinates} "Go"]])

(defn app []
  [:div {:class "app"}
   [title]
   [:div {:class "temperatures"}
    (for [temp (vals (:temperatures @app-state))]
      [temperature temp])]
   [postal-code]])

(defn mount-app-element []
  (rdom/render [app] (gdom/getElement "app")))

(mount-app-element)

(defn ^:after-load on-reload []
  (mount-app-element))

Derek18:10:11

Try a doall around the (for [temp (vals (:temperatures @app-state))]. IIRC, laziness and reagent do not work well

p-himik18:10:37

They do work well, but that particular line will issue a warning about keys.

roelof18:10:58

oke, I must also say I see this error in the dev console of FF

goog.require could not find: learn_cljs.weather.core

p-himik18:10:47

Do you see the <div class="postal-code"> in the Elements inspector of your browser? You need to figure out what "do not see the text and input button" means exactly - whether they're not in the DOM at all or are in the DOM but hidden in one way or another.

roelof18:10:51

i had to change this line {:main learn-cljs.weather} in dec.cljs.edn

👍 1