This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-12-16
Channels
- # adventofcode (76)
- # aleph (1)
- # aws (2)
- # beginners (101)
- # boot (1)
- # boot-dev (1)
- # calva (25)
- # cider (12)
- # cljs-dev (29)
- # clojure (214)
- # clojure-europe (1)
- # clojure-nl (5)
- # clojure-spec (1)
- # clojure-uk (6)
- # clojurescript (155)
- # data-science (1)
- # datomic (48)
- # figwheel-main (5)
- # immutant (1)
- # leiningen (11)
- # nrepl (2)
- # off-topic (24)
- # pathom (2)
- # pedestal (2)
- # portkey (8)
- # protorepl (5)
- # re-frame (2)
- # rum (4)
- # shadow-cljs (21)
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?
As an alternate question: what do you guys currently use for ClojureScript development as interactive as it was intended?
The Atom section of the editor configurations on the ClojureScript website seem to be outdated
I was trying Atom editor a few times. My conclusion is: it is not worth time to work with Clojure(Script) with Atom.
Better alternative is Visual Studio Code, but half a year ago it was still not enough good integrated.
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.
Then again I could be misremembering and perhaps could only get Clojure to work in those editors.
I tried Emacs and just am not comfortable without the conveniences of modern editors.
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.
@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?
*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
.
you could just make a separate ns for reagent sutff. form-validator.reagent
and delegate all methods to the .core
stuff?
Have you considered re-frame as that is handled by the framework?
@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.
@whoneedszzz not sure what do you mean
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.
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
Right, which re-frame creates and maintains for you
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.
but the point is you don’t know if developer want to use r/atom
or atom
with your module.
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.
I guess I'm not understanding why it would be conditional. If you're targeting reagent then you have to use a ratom
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
because needs to use reagent.core/atom
inside my module which is not designed for reagent only
Actually after found it is an issue in reagent architecture, reagent get -1000 points for me 🙂
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.
The reason reagent has that is perfectly valid. The problem doesn't lie with itself
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
I don't know the specific implementations of state management between the two either, but do know that they handle it differently
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 🙂
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
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.
Because this choice will affect potentially all users which will want to use this module
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?
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
- 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
but I am curious what options I have to use all form-validator.core
fn in form-validator.reagent
hmm
I was suggesting (form-validator.core/init {:ratom true})
and then in the init function create the appropriate atom based on the boolean condition.
It can’t be like that, because then module will have to require reagent as dependency even if somebody don’t use it
It could by having it in a separate namespace, as was previously suggested
What's the current best method for using npm packages in a re-frame/reagent app?
Shadow CLJS is an option as is the "Double Bundle" approach: https://github.com/pesterhazy/presumably/blob/master/posts/double-bundle.md
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
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.
@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"."
@whoneedszzz npm install react react-dom create-react-class
@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
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
@thheller Thanks. For some reason that was left out of the documentation
So I'm getting it to build with shadow-cljs, but the server reports "Not found."
@whoneedszzz do you have an index.html?
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"
try adding [com.google.javascript/closure-compiler-unshaded "v20181125"]
to your :dependencies
Had that version of cljs. It builds now, but isn't respecting my cljsbuild settings so it's not finding the index.html again
Ok so how do I reflect those settings in shadow-cljs?
So it will understand the same :compiler map?
@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?
":preloads [devtools.preload day8.re-frame-10x.preload]"
check out the example project https://github.com/jacekschae/shadow-re-frame
I really appreciate you being here to speak with you directly
Out of curiosity, what is your personal setup for editor and build tool?
Ah, cool. So the same setup 🙂
@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?
Sorry to barge in but I wrote something on this topic exactly: https://andrearichiardi.com/blog/posts/clojurescript-cursive-shadow-setup.html
Cheers
Did not read the whole history of messages of course 😉 You are welcome!
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?
Probably coming from a bad import statement in your namespace
Incorrect imports like this (:import [java.util.Date]) will cause that error, instead of (:import [java.util Date])
Might also be coming from a dependency
But for sure a malformed ns form
(:import [<ns> <class>...])
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))
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.
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?
because now you create (fn []) which wouldn’t re-render unless fn which call my-tab
re-render
@U0WL6FA77 I just forgot to add the same args to the inner fn. @lilactown made me aware of that 🙂
are you saying that if you pass in a new name-data-vector
, that it doesn’t re-render?
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
(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] ...
@lilactown You solved the issue!! I just had to put the same function args into the inner function.
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.
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?
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?
(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])
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..
(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")))
(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]
@UCSJVFV35 Thank you