Fork me on GitHub
#clojurescript
<
2019-07-25
>
John Collins06:07:24

Hello, I'm reevaluating my front-end stack now that I'm a little ways in and familiar with things, curious if anyone has input. Currently I'm scrapping by with re-posh, which is kind of an undermaintained/developed lib that combines posh, datascript, and re-frame to try to expose a "materialized" datascript db. It works, but it's a bit janky and the lack of pull subscriptions is very annoying for my use case. Basically it seems to end up that creating a reactive, logic based system essentially entails implementing a rules engine. ... Which leads me to Precept. Is anyone using it? Does it work/scale well? Is the memory usage a problem? Seems quite interesting, although the lack of parameterized subscriptions is a bit hard for me to wrap my head around. There's also factui, which looks like perhaps the closest to God of all the cljs UI frameworks. But it's unfinished and also plugs into rum (I'm committed to re-com at this point). Is there anything else in this space I'm missing? I'd really love to tap into the awesomeness of datalog for ui, but there doesn't seem to be mature offering yet. Is there a practical way to write reactive views against a datascript db?

Roman Liutikov08:07:15

I’d say there all of those libraries are not popular because not much people are using them. I like the concept of a DB with a query language in web apps, but unfortunately the more interactive your app becomes the more of a perf bottleneck a DB can become. I don’t have any numbers to bake this, but that’s my general feeling from seeing and hearing how web apps with databases on the client works.

Roman Liutikov08:07:04

However it might be worth take a look at Fulcro, don’t know for what kind of apps it is suited though.

4
Roman Liutikov08:07:30

In JavaScript there’s MobX which offers push-based subscription model, but it has a drawback that state should be described in a form of a model instead of a plain data structure as in Redux/Re-frame etc

John Collins20:07:18

Thanks, unfortunately fulcro is doing far too much for my taste, plus I love re-com so much I don't think I wanna move away from ratoms. It's too bad the graph language isn't independent of the rest of the stuff. Hmm, given this is a solo side project I'm tempted to take precept for a spin..

romain08:07:00

is it possible to store a function name in a map, and get it to call the function (which is in another file)? Something like this:

(defn hello [] "hello")
(def mymap {:id 123 :func 'hello)
((resolve (:func mymap))

carkh09:07:59

use a backtick `hello

carkh09:07:33

@romain you'll get the namespaced symbol

carkh09:07:32

or directly #'hello ... and carry the var instead of a symbol

carkh09:07:34

oh we're in clojurescript ... might be different in there

romain09:07:37

@carkh I try But #'hello cannot be resolved because it is declared in another file

romain09:07:41

and yes, clojurescript 😛

carkh09:07:57

well you would take it from the original namespace

carkh09:07:14

but yeah clojurescript vars may be different

carkh09:07:26

generally speaking namespaces will end up mangled beyond recognition when doing advanced compilation, don't know if it's advisable to be smart about that

carkh09:07:59

maybe register your functions to some maps and access these via keywords

carkh09:07:03

these remain untouched

thheller09:07:40

@romain why not just put the funtion in the map directly? why do you need the name/var indirection?

romain09:07:33

@thheller I have functions in (ns app.views). I also have a generic modal reagent component where attributes are defined in app-state from (ns app.state). For example:

{:add {:msg "Add modal"
            :class "is-primary"
            :btn "Confirmer l'ajout"
            :func **ADD MODAL FUNC**}

romain09:07:40

In the modal, I have one button to perform an action. So I must set the button's function and I thought I could store the function to be called in the modal-map in app-state

thheller09:07:03

yes you can store the function

thheller09:07:18

(def mymap {:id 123 :func hello})

thheller09:07:42

((:func mymap))

romain09:07:18

but the function is in a different file

carkh09:07:27

qualify it

carkh09:07:39

mynamespace/thefunc

thheller09:07:41

its just a normal var reference so prefix it with the alias foo/hello

carkh09:07:16

nice catch thheller, never in 7 (10?) years of clojure did i need to use resolve for regular app dev, that's a code smell

romain09:07:15

So you mean something like that?

{:add {:msg "Add modal"
            :class "is-primary"
            :btn "Confirmer l'ajout"
            :func app.views/hello}

thheller09:07:51

@romain yes. assuming of course that the ns this map is created in has a (:require [app.views])

romain09:07:10

meh! I got a Circular dependency detected: app.views -> app.state -> app.views error

romain10:07:50

From what I can read, there may be also an issue with resolving and :advanced compilation. Maybe I should just change the modal's design, but I liked the idea of getting attributes and the action function from my app-state

thheller10:07:10

just restructure your namespaces to avoid that cycle

thheller10:07:13

ie. construct the map in a namespace that can depend on app.state and app.views but is not directly accessed by either of those

thheller10:07:28

resolve is indeed tricky with :advanced and should be avoided

romain10:07:46

Yes I could put that in (ns app.events). But as you mention, should I build 2 modals instead of doing this with the risk of resolving?

thheller10:07:22

you are not using resolve if you do the above?

romain10:07:12

I may spoke too fast, I try ^^'

romain11:07:38

@thheller it seems better, now I need to fix the error No protocol method IDeref.-deref defined for type undefined:

Lu11:07:42

That means you are doing @hello but hello is nil

romain11:07:09

hm... in my reagent atom, the function is set as : {... :func #object[app$events$hello]}

Lu11:07:03

Is this what you are doing?

(defn hello [] "hello")
(def mymap {:id 123 :func 'hello})
(resolve '(:func mymap))

Lu11:07:43

What's the problem with this?

(defn hello [] "hello")
(def mymap {:id 123 :func hello})
((:func mymap))

romain11:07:48

in my (ns app.state) I have

(ns app.state
  (:require [reagent.core :refer [atom]]
            [app.events]))

(defonce app-state (atom {:modal {:add {:msg "Add modal"
                                        :class "is-primary"
                                        :btn "Confirm"
                                        :func app.events/add-modal}}}))
And in my (ns app.views)
[:a.button {:type "button"
                  :on-click (:func (:add (:modal @app-state)))}
                  "Confirm"]]]]]]]]))

romain12:07:19

And when I deref app-state I have {... :func #object[app$events$hello]}

Lu12:07:05

you are forgetting that # to your on-click function.. you need to pass an anonymous function

Lu12:07:00

[:a.button {:type "button"
                  :on-click #(-> @app-state :modal :add :func)}
                  "Confirm"]

Lu12:07:36

Oh I see you're not calling a function in there so it's fine.. what's app.events/add-modal ?

romain12:07:08

I forgot in the snippet above, I also pass app-state to add-modal

(defn add-modal [db]
  (do
    (add-request (:add-email @db)) ;; Perform a POST request and update db (app-state)
    (toggle-modal db ""))) ;; just a function to set class to "" to close the modal

Lu12:07:57

[:a.button {:type "button"
                  :on-click #((-> @app-state :modal :add :func) app-state)}
                  "Confirm"]

Lu12:07:59

there you go

romain12:07:20

I just tried it. I don't have the error anymore, but I have another one Error: No protocol method ISwap.-swap! defined for type undefined: . The swap is done in another function called in :finallyrequest, but I think I can debug that 🙂

romain12:07:24

Thanks for your help

Lu12:07:23

It's very similar.. you are not passing the db 🙂

romain12:07:56

yep, you're right 😉

✔️ 4
romain12:07:31

@lucio I confirm, it works well now... I thought a modal will be cool and simple, finally it adds a lot of complexity and code 😄

Lu12:07:38

Yeah there's a bit of logic to add 🙂

Sam Ferrell15:07:08

Anyone have any experience using React context with Rum?

David Pham17:07:27

Is there any reason to use core.async when using re-frame?

johanatan17:07:26

does anyone know why :npm-deps is a per-profile setting in leiningen?

johanatan17:07:57

i assume because it's an argument to cljsbuild?

johanatan18:07:47

[as an npm module]

johanatan18:07:57

would it be more advisable to use the cljsjs wrapper?

johanatan18:07:09

i'm running in to this error with my attempted npm setup:

johanatan18:07:21

Uncaught Error: Undefined nameToPath for react_chartjs_2
    at visitNode (base.js:1357)
    at Object.goog.writeScripts_ (base.js:1369)
    at Object.goog.require [as require_figwheel_backup_] (base.js:706)
    at figwheel$client$file_reloading$figwheel_require (file_reloading.js:576)
    at figwheel$client$file_reloading$require_with_callback (file_reloading.js:1154)
    at figwheel$client$file_reloading$js_reload (file_reloading.js:1204)
    at figwheel$client$file_reloading$reload_js_file (file_reloading.js:1213)
    at file_reloading.js:1290
    at file_reloading.js:1360
    at figwheel$client$file_reloading$load_all_js_files_$_state_machine__31867__auto____1 (file_reloading.js:1381)

johanatan18:07:05

this is my relevant project.clj section:

:npm-deps {:react-chartjs-2 "2.7.6"
                                                  :chart.js "2.5.0"}
                                       :install-deps true

dnolen18:07:14

@johanatan :npm-deps is not recommended unless you're using Node.js

dnolen18:07:42

it's an alpha feature and getting all the various libraries to work is unlikley in the near future

johanatan18:07:47

ah, i guess i overestimated the magic involved here. 🙂

dnolen18:07:50

if you want to use something from NPM just use Webpack

dnolen18:07:53

there's a guide now

dnolen18:07:58

it always works

johanatan18:07:25

well, there happens to be a cljsjs for this one. would that be ok too? https://github.com/cljsjs/packages/tree/master/react-chartjs-2

johanatan18:07:37

is the longer term vision for these that they would work tho? what are some of the hurdles to making that happen? i could potentially help out ...

dnolen18:07:55

it's not a priority

dnolen18:07:06

and a lot of people have worked on it to get it to where it is

dnolen18:07:28

unless you're ready sink 3-6 months of full time work - I'd put your energies elsewhere

johanatan18:07:37

haha, fair enough

dnolen18:07:56

also too many JS libraries are really broken wrt. advanced compilation

dnolen18:07:10

so the benefit would likely be quite minor

👍 4
David Pham18:07:47

@dnolen where are the effort concentrated on cljs at the moment?

dnolen18:07:04

there's nothing major going on

dnolen18:07:07

just lots of little stuff

dnolen18:07:31

one medium sized thing on the horizon is transitive support for webpack based builds

dnolen18:07:03

another thing is var data for Clousure libs - so you can query that stuff at the REPL like a CLJS lib

dnolen18:07:24

one thing to fall out of that will be type propagation for Closure stuff to eliminate unnecessary hinting