Fork me on GitHub
#clojurescript
<
2018-12-16
>
WhoNeedszZz03:12:30

Hey, folks. I've been away from ClojureScript for a while and wanted to use it in a simple re-frame app. Before the time away I used Atom with Proto-Repl and with the nrepl middleware was able to make it work with ClojureScript. I can get Proto-Repl to connect to an nrepl session that is connected to the browser, but various basic editor features like autocompletion do not work for ClojureScript symbols, only Clojure symbols. Am I missing some simple configuration step or is this a known issue?

WhoNeedszZz03:12:34

As an alternate question: what do you guys currently use for ClojureScript development as interactive as it was intended?

WhoNeedszZz03:12:10

The Atom section of the editor configurations on the ClojureScript website seem to be outdated

kwladyka10:12:50

I was trying Atom editor a few times. My conclusion is: it is not worth time to work with Clojure(Script) with Atom.

kwladyka10:12:23

Better alternative is Visual Studio Code, but half a year ago it was still not enough good integrated.

kwladyka10:12:51

So… on the end we can use Cursive (Intellij) or Cider (Emacs)

kwladyka10:12:14

In other words I am saying don’t lose your time with Atom editor

WhoNeedszZz10:12:22

Well the thing is that it was working just fine not that long ago so it's frustrating to see it in a broken state currently. I had the same problems on VS Code and ended up forking the cash for the Cursive license.

WhoNeedszZz10:12:58

Then again I could be misremembering and perhaps could only get Clojure to work in those editors.

WhoNeedszZz10:12:16

I tried Emacs and just am not comfortable without the conveniences of modern editors.

kwladyka10:12:01

Yeah that is why I am using Curisve 🙂

kwladyka10:12:18

But I wish to use VS Code because it is not such heavy as Intellij

kwladyka10:12:48

Finally I consider 2 solutions to configure how to create atom in module: 1) :closure-defines like :closure-defines {form-validator.core/framework "reagent"} 2) (form-validator.core/init {:atom ragent.core/atom}) as optional init to set another fn to create atom. I will appreciate feedback how would you like to use module and what we can consider as best practice. *What is it about? Reagent needs to use ragent.core/atom instead of native Clojure atom to update UI in right moment.

kwladyka13:12:45

@thheller I am sorry I am asking you directly, but you are very clever guy and your opinion matter for me. What do you think about my issue?

thheller13:12:12

no idea what you are trying to do?

kwladyka13:12:10

oh that is more serious issue then I thought haha, let me explain more clearly:

kwladyka13:12:11

*code below is under heavy development https://github.com/kwladyka/form-validator-cljs/blob/master/src/form_validator/core.cljs#L108 I make atom here. But when project use reagent, atom should by created by reagent.core/atom. If there is no reagent, then normal atom.

kwladyka13:12:30

Because reagent doesn’t work with atom (not update UI after atom change)

kwladyka13:12:34

So developer has to decide in some way how module will create atom.

kwladyka13:12:54

At least I don’t have any better idea how to make modules compatible with reagent

thheller14:12:44

you could just make a separate ns for reagent sutff. form-validator.reagent and delegate all methods to the .core stuff?

WhoNeedszZz16:12:11

Have you considered re-frame as that is handled by the framework?

kwladyka16:12:20

@thheller ok then it is 3rd option. Not sure if my module will include reagent then even if project don’t have it as dependency. In another words finally I don’t want to have reagent in my deps. Module should use reagent from project deps.

kwladyka16:12:29

@whoneedszzz not sure what do you mean

kwladyka17:12:44

How exactly do you see delegation to core?

WhoNeedszZz17:12:53

Perhaps I'm misunderstanding your question, but I was saying that re-frame creates a ratom for you and updates it internally as a result of an event rather than manually managing it.

kwladyka17:12:05

to use reagent (re-frame) with atom as a developer you have to use reagent.core/atom instead of atom. Otherwise reagent doesn’t fire events to update UI when atom value changes

WhoNeedszZz17:12:37

Right, which re-frame creates and maintains for you

kwladyka17:12:08

It is fine when you do project. Then you can just use r/atom, but if you write module and you want this module work with reagent and all others solution, then things start to be more complicated.

kwladyka17:12:00

re-frame is reagent under the hood

kwladyka17:12:39

but the point is you don’t know if developer want to use r/atom or atom with your module.

kwladyka17:12:37

In other words modules compatible with reagent demand special logic only for reagent. Which mean probably something goes wrong there, but it works like that.

WhoNeedszZz17:12:17

I guess I'm not understanding why it would be conditional. If you're targeting reagent then you have to use a ratom

kwladyka17:12:57

it is a module, separated repo. Developer A want to use this module with reagent (re-frame) Developer B want to use the same module with om next

kwladyka17:12:35

Developer C with fulcro Developer D with his custom solution

kwladyka17:12:26

unfortunately reagent makes an issue about compatibility in that context

kwladyka17:12:04

because needs to use reagent.core/atom inside my module which is not designed for reagent only

kwladyka17:12:29

Actually after found it is an issue in reagent architecture, reagent get -1000 points for me 🙂

WhoNeedszZz17:12:05

Here lies the issue with trying to support multiple systems that aren't compatible with each other. I would suggest having two separate implementations - one with ratom and the other with atom.

WhoNeedszZz17:12:51

The reason reagent has that is perfectly valid. The problem doesn't lie with itself

kwladyka17:12:54

too complex and hard to maintenance 2 repo, if another solutions will have this issue, then I will have to have 10 repos with almost the same code and maintenance it

kwladyka17:12:10

It is issue about reagent architecture

kwladyka17:12:38

I don’t know details, but om.next doesn’t have this issue

kwladyka17:12:34

But I didn’t use om.next too much so I don’t know how it works under the hood

WhoNeedszZz17:12:19

I don't know the specific implementations of state management between the two either, but do know that they handle it differently

kwladyka17:12:11

anyway it is even ok, but reagent should make a doc about best practice how to make modules compatible with reagent. But this topic is just silenced - that is why it get -1000 points for me 🙂

kwladyka17:12:25

besides somebody did great work of course!

WhoNeedszZz17:12:52

To be compatible with reagent you must use a ratom, as you know. It doesn't and shouldn't make any claims in how other libraries or frameworks handle state

kwladyka18:12:26

I can achieve it on 3 different ways (2 which I mentioned + 1 which thheller mentioned which I miss). I don’t feel enough experience to know which one is right one.

kwladyka18:12:51

I would like to read doc about it or listen somebody with such experience

kwladyka18:12:29

Because this choice will affect potentially all users which will want to use this module

kwladyka18:12:43

that is something different then doing closed source project

kwladyka18:12:14

of course if anybody will want to use my module trollface

WhoNeedszZz18:12:59

Could you not just add a flag to the init that is set when the user is targeting reagent/re-frame and if set use a ratom, if not use an atom?

kwladyka18:12:18

yeah, it is one of the option

kwladyka18:12:10

1) :closure-defines like :closure-defines {form-validator.core/framework "reagent"} 2) (form-validator.core/init {:atom ragent.core/atom}) as optional init to set another fn to create atom. 3) make form-validator.reagent which will delegate to all form-validator.core fn, but with r/atom

kwladyka18:12:34

- closure-defines is ok, but it can be a little harder for “junior” ClojureScript developers to set. - init sounds easy, but is is something ugly about that. I will have to write in atom how to create atom lol - creating form-validator.reagent increase complexity of module

kwladyka19:12:32

but I am curious what options I have to use all form-validator.core fn in form-validator.reagent hmm

kwladyka19:12:43

Maybe there is some automatic way to do it

WhoNeedszZz19:12:37

I was suggesting (form-validator.core/init {:ratom true}) and then in the init function create the appropriate atom based on the boolean condition.

kwladyka19:12:23

It can’t be like that, because then module will have to require reagent as dependency even if somebody don’t use it

WhoNeedszZz19:12:28

It could by having it in a separate namespace, as was previously suggested

kwladyka19:12:17

then we have solution 3) and don’t need init fn

WhoNeedszZz11:12:37

What's the current best method for using npm packages in a re-frame/reagent app?

grav12:12:11

JavaScript’s async/await gives the ability to make a simple run loop with a while(true) like this: https://gist.github.com/grav/862e8917a2f05c22831da27964c12d1f I’m wondering how to express that in ClojureScript. Currently I have something like this (using recursion): https://gist.github.com/grav/a8bb76f1a6be9566fe2cc320a3bdb2e8 but I’m not sure if it’s semantically the same? I’ve also tried using Babel to create ES 5 code from the first example, but it yields something that is too complex for me to grasp: https://goo.gl/3Zytre

thosmos04:12:41

look into core.async which gives you an equivalent to async await

grav08:12:33

That’s a possibility, but I’d like to solve it without having to use libraries, since it’s for a layer in AWS Lambda.

WhoNeedszZz13:12:13

@martinklepsch Trying out Shadow-cljs results in this error: "The required namespace "create-react-class" is not available, it was required by "reagent/impl/component.cljs"."

thheller13:12:33

@whoneedszzz npm install react react-dom create-react-class

kwladyka13:12:24

@whoneedszzz here is example with figwheel-main and deps.edn https://github.com/kwladyka/form-validator-cljs/tree/doc - repo it still in progress, but example how to use npm deps is good

kwladyka13:12:41

shadow-cljs is also good solution

kwladyka13:12:01

no other good alternatives IMO then this 2

borkdude13:12:42

I’m compiling a project that uses self-hosted CLJS with the options that are suggested here https://clojurescript.org/guides/self-hosting:

"-m" "cljs.main" "-O" "simple" "-co" "{:pretty-print,false,:optimize-constants,true,:static-fns,true}"
But with the option :optimize-constants true I’m seeing this error:
Caused by: java.lang.AssertionError: Assert failed: Circular dependency detected, cljs.core -> cljs.core

WhoNeedszZz13:12:27

@thheller Thanks. For some reason that was left out of the documentation

WhoNeedszZz14:12:44

So I'm getting it to build with shadow-cljs, but the server reports "Not found."

thheller14:12:38

@whoneedszzz do you have an index.html?

WhoNeedszZz14:12:58

Yeah, I realized I missed that bit about copying it over to target. So I got it to run that way, but when trying to set it up for lein I'm getting this: "Exception in thread "main" java.lang.NoSuchFieldError: PARSE_RESULTS"

thheller14:12:14

do you use lein/deps.edn? probably a version conflict then

thheller14:12:59

try adding [com.google.javascript/closure-compiler-unshaded "v20181125"] to your :dependencies

thheller14:12:35

[org.clojure/clojurescript "1.10.439"] as well while you are at it

WhoNeedszZz14:12:30

Had that version of cljs. It builds now, but isn't respecting my cljsbuild settings so it's not finding the index.html again

thheller14:12:12

well its not using cljsbuild so those won't have any effects

WhoNeedszZz14:12:28

Ok so how do I reflect those settings in shadow-cljs?

thheller14:12:34

in its config

thheller14:12:37

shadow-cljs.edn

WhoNeedszZz14:12:09

So it will understand the same :compiler map?

WhoNeedszZz14:12:32

@thheller Ok so I have it running, but it isn't loading the re-frame-10x panel as it needs the preload for it. How do I include those?

WhoNeedszZz14:12:48

":preloads [devtools.preload day8.re-frame-10x.preload]"

thheller15:12:11

it has all of it configured

WhoNeedszZz15:12:28

Perfect, thanks. Got it up and running!

🎉 4
WhoNeedszZz15:12:43

I really appreciate you being here to speak with you directly

WhoNeedszZz15:12:18

Out of curiosity, what is your personal setup for editor and build tool?

thheller16:12:45

Cursive, lein for clj, shadow-cljs for cljs

WhoNeedszZz16:12:32

Ah, cool. So the same setup 🙂

WhoNeedszZz18:12:44

@thheller I'm going through the documentation and I'm not sure how to connect Cursive to the repl. I followed the documentation of adding a remote repl and connecting to it, but it will only evaluate Clojure forms so how do I enable the cljs repl?

WhoNeedszZz18:12:16

All I needed from that was to call (shadow/repl :build-id), but thanks

👍 4
richiardiandrea18:12:32

Did not read the whole history of messages of course 😉 You are welcome!

achikin18:12:20

Clojurescript guides page looks a little bit inconsistent. Is that expected?

dnolen19:12:51

@achikin no, feel free to fix it up!

brown13119:12:36

I’m trying to update my dependencies from 1.9.09 to 1.10.439 (with no code changes yet) and I am getting one of the most infuriatingly worthless compiler errors that I’ve ever seen. Lots of noise with no useful information. Can anyone tell me what the error actually is here?

chrisulloa19:12:19

Probably coming from a bad import statement in your namespace

chrisulloa19:12:37

Incorrect imports like this (:import [java.util.Date]) will cause that error, instead of (:import [java.util Date])

chrisulloa19:12:18

Might also be coming from a dependency

chrisulloa19:12:33

But for sure a malformed ns form

chrisulloa19:12:51

(:import [<ns> <class>...])

lilactown19:12:28

it has the offending value in there I think:

(cljsbuild.crossover (:use [ :only [as-url resource]]) (:require [cljsbuild.util :as util] [clojure.string :as string] [fs.core :as fs]) (import java.io.File java.net.URLDecoder)), :clojure.spec.alpha/args (cljsbuild.crossover (:use [ :only [as-url resource]]) (:require [cljsbuild.util :as util] [clojure.string :as string] [fs.core :as fs]) (import java.io.File java.net.URLDecoder))

lilactown19:12:03

I haven’t ever used it, and not sure exactly what’s going on, but googling cljsbuild.crossover took me to https://github.com/emezeske/lein-cljsbuild which has this: > Note that cljsbuild crossovers are deprecated, and will be removed eventually. You should never use them. Please use either reader conditionals (available in Clojure >= 1.7.0-beta2 and ClojureScript >= 0.0-3255), or cljx to target both Clojure and ClojureScript from the same codebase. > If you are using ClojureScript >= 1.7.170 you need to use a lein-cljsbuild version >= 1.1.1.

lilactown19:12:29

@brown131 ☝️ any of that point you in a direction?

awb9920:12:30

I frequently need just a tab control, that I can add to a reagent page without too much thinking to separate content into tabs. The code attached does that. But it has a bug, namely if the tab pages are re-rendered, then they are not updated in the tab. I thought since I have them in the parameter, that reagent should update it all… But it seems not.. Any ideas?

kwladyka20:12:17

Hmm it looks ok. Maybe bug is in fn level higher? There where you call my-tab?

kwladyka20:12:38

try println in a few places to be sure where is the issue

awb9920:12:54

the tab is working.

awb9920:12:30

[mytab/my-tab "a" [:h1 "A rocks"] "b" [:h2 "b is also not so bad!"] ]

awb9920:12:39

so this above expression works perfectly,

kwladyka20:12:46

not in the context of re-rendering

awb9920:12:56

re-rendering does not work

kwladyka20:12:08

But on first look my-tab is ok, try to find bug on fn lvl higher

kwladyka20:12:14

maybe this fn is not rerender

kwladyka20:12:12

unless you want move nama-data-vector to (fn [name-data-vector]

kwladyka20:12:46

because now you create (fn []) which wouldn’t re-render unless fn which call my-tab re-render

awb9920:12:38

I will try to move the arguments to the inner-funciton

awb9920:12:22

@U0WL6FA77 I just forgot to add the same args to the inner fn. @lilactown made me aware of that 🙂

👍 4
lilactown20:12:20

> if the tab pages are re-rendered what do you mean by this?

lilactown20:12:34

one thing I notice: the fn you return takes no arguments

lilactown20:12:11

are you saying that if you pass in a new name-data-vector, that it doesn’t re-render?

awb9920:12:17

My idea was to make a very simple syntax to use the tab

awb9920:12:41

I pass "tab-text" [:p "tab-body] "tab-2" [:p "second body"]

awb9920:12:56

if I only put in [:p "tab-body"]

awb9920:12:00

then it renders correct

awb9920:12:08

buit if instead I pass in components that re-render

awb9920:12:17

depending on some atoms in the parent component,

awb9920:12:23

then the tab bodies do not re-render.

lilactown20:12:13

I’m still not totally sure what’s wrong without an example that doesn’t work

lilactown20:12:23

but let’s start with making sure that the fn returned by a reagent form-2 component takes the same arguments as the outer function

lilactown20:12:42

(defn my-tab [& name-data-vector]
      "makes a tab from a vector of str-name hiccup tuples that are in a vector
   example:  [tab-demo 'a' [:h1 'A'] 'b' [:h2 'b'] ]
   "
      (let [active-tab (r/atom 0)]
        (fn [& name-data-vector] ...

awb9920:12:43

@lilactown You solved the issue!! I just had to put the same function args into the inner function.

awb9920:12:52

Gents! I am still a newbie to clojurescript / Reagent / re-frame. But I think my approach to make a few components that allow one to do prototyping much faster is the right approach. I think clojurescript needs some collections of nice prototyping components.

Dante T. M.21:12:35

I see the -> macro used in the on-change examples for reagent but given all that it's doing is accessing event properties could the double-dot (..) be used instead?

avfonarev22:12:20

Has anyone used routing with re-frame? What is the state of the art? Also, what is the proper way to serve an SPA with routing included?

awb9922:12:04

(ns bongo.routes (:require-macros [secretary.core :refer [defroute]]) (:import goog.history.Html5History) (:require [secretary.core :as secretary] [goog.events :as events] [goog.history.EventType :as EventType] [reagent.core :as reagent] [http://bongo.views.menu :as menu] [http://bongo.views.help :as help] [bongo.views.contacts :as contacts] [bongo.demo.tooltip :as demo-tooltip] [bongo.seasonality.instsim :as seasonality-instsim] [bongo.seasonality.listsim :as seasonality-listsim] [bongo.seasonality.highchart :as seasonality-highchart] [bongo.financials.core :as financials] )) (defn hook-browser-navigation! [] (doto (Html5History.) (events/listen EventType/NAVIGATE (fn [event] (secretary/dispatch! (.-token event)))) (.setEnabled true))) (def app-state (reagent/atom {})) (defn app-routes [] (secretary/set-config! :prefix "#") (defroute "/" [] (swap! app-state assoc :page :home)) (defroute "/help" [] (swap! app-state assoc :page :help)) (defroute "/shit" [] (swap! app-state assoc :page :shit)) (defroute "/contacts" [] (swap! app-state assoc :page :contacts)) (defroute "/seasonal/highchart" [] (swap! app-state assoc :page :seasonal-highchart)) (defroute "/seasonal/simulate-instrument" [] (swap! app-state assoc :page :seasonal-simulate-instrument)) (defroute "/seasonal/simulate-list" [] (swap! app-state assoc :page :seasonal-simulate-list)) (defroute "/financials" [] (swap! app-state assoc :page :financials)) (hook-browser-navigation!)) (defmulti current-page #(@app-state :page)) (defn menu-page [name page] [:div [menu/menu name] [page]]) (defmethod current-page :default [] [menu-page "home" help/home]) (defmethod current-page :home [] [menu-page "home" help/home]) (defmethod current-page :help [] [menu-page "help" help/help]) (defmethod current-page :shit [] [menu-page "tooltip" demo-tooltip/tooltip]) (defmethod current-page :contacts [] [menu-page "contacts" contacts/contact-list]) (defmethod current-page :seasonal-highchart [] [menu-page "lineplot" seasonality-highchart/lineplot-demo]) (defmethod current-page :seasonal-simulate-instrument [] [menu-page "s-instsim" seasonality-instsim/simulate-instrument-app]) (defmethod current-page :seasonal-simulate-list [] [menu-page "s-instsim" seasonality-listsim/sim-app]) (defmethod current-page :financials [] [menu-page "financials" financials/financials-app])

awb9922:12:20

I use secretary

avfonarev22:12:35

Thanks! How do you serve the app preserving the url? As far as I understand, nginx won't do it, but I don't want to run an extra process for it..

awb9922:12:20

I serve it from clojure

awb9922:12:54

(defroutes app-routes ; (route/resources "/" {:root "public"}) ;; NOTE: this will deliver your index.html (GET "/" [] (-> (response/resource-response "index.html" {:root "public"}) (response/content-type "text/html")))

awb9922:12:07

(ns web.server (:require [schema.core :as s] [ring.util.response :as response] [ring.util.http-response :refer :all] [ring.middleware.defaults :refer [wrap-defaults site-defaults]] [ring.middleware.reload :refer [wrap-reload]] [compojure.core :refer :all] ; [compojure.core :refer [defroutes routes]] [compojure.route :as route] [compojure.api.sweet :as sweet] [cheshire.core :refer :all]