Fork me on GitHub
#clojurescript
<
2017-03-30
>
sneakypeet04:03:32

Hi all, I have an existing node/babel project that I have to add some new functionality to. If it was practical I would just rewrite the app in clj, but thats not really an option. I am wondering if there is an easy way to combine cljs in a node/babel app? Or should I not even bother? Thanks

rmuslimov04:03:35

@sneakypeet We actually spend sometime trying to implement part of js app (webpack/babel), however, practically it became a nightmare. Of course, may be our qualification just is not enough, but I decided that implementing from the scratch would be a better solution next time.

sneakypeet04:03:53

I'm also thinking that the management around it might become hairy

sneakypeet04:03:08

clj/cljs has ruined other languages for me 😄

thinhptran08:03:08

Hi all, I currently using Om.Next to render my Highchart. It works but it looks ugly so I would like to know if anyone has a better way for it.

rauh08:03:06

@thinhptran Don't use dom/node ever. Just use :ref with a function. React will pass the dom node and nil on unmount.

thinhptran08:03:23

Many thanks, rauh. I will read it.

hulunote09:03:17

I can’t use echarts 3 in ClojureScript, because cljsjs not support echarts 3. How can i do?

danielstockton09:03:06

There is already an echarts package: http://cljsjs.github.io/

thinhptran10:03:53

@rauh: many thanks. I got it. ;;; Highchart (defui MyLocalChart Object (render [this] (let [{:keys [tableconfig]} (om/props this) my-chart-config (utils/gen-chart-config-handson tableconfig)] (dom/div #js {:style {:height "100%" :width "100%" :position "relative"} :ref (fn [mydiv] (if (some? mydiv) (js/Highcharts.Chart. mydiv (clj->js @my-chart-config))))}))))

danielstockton10:03:57

I would be careful about instantiating it multiple times and also call .destroy on unmount to avoid leaking event listeners.

danielstockton10:03:59

This is mine:

(defn get-chart [component]
  (let [idx (.get goog.dom.dataset (dom/node component) "highchartsChart")]
    (aget (.. js/Highcharts -charts) idx)))

(defui Chart
  Object
  (componentDidMount [this]
    (let [{:keys [id data opts]} (om/props this)
          chart                  (get-chart this)]
      (.chart js/Highcharts id (config data (merge default-opts opts)))))
  (componentWillReceiveProps [this next-props]
    (let [{:keys [id data opts]} next-props
          chart                  (get-chart this)]
      (.destroy chart)
      (.chart js/Highcharts id (config data (merge default-opts opts)))))
  (componentWillUnmount [this]
    (.destroy (get-chart this)))
  (render [this]
    (let [id (:id (om/props this))]
      (dom/div #js {:id        id
                    :className "chart"}))))

(def chart (om/factory Chart))
The function refs is news to me.

thinhptran10:03:37

@stevechan : You can use using clojurescript javascript interop.

hulunote10:03:16

I know. but i use echarts in producion

hulunote10:03:04

I need passed compile with Google Closure Compiler.

danielstockton10:03:51

@stevechan Sorry, the existing echarts package is echarts 2. You can create your own by following: https://github.com/cljsjs/packages/wiki/Creating-Packages You just need to create the externs, perhaps it will be similar to echarts 2? https://github.com/cljsjs/packages/blob/master/echarts/resources/cljsjs/echarts/common/echarts.ext.js

thinhptran10:03:19

@danielstockton : how about this ;;; Highchart (defui MyGlobalChart Object (render [this] (let [{:keys [tableconfig]} (om/props this) my-chart-config (utils/gen-chart-config-handson tableconfig) chart (atom {:chart nil})] (dom/div #js {:style {:height "100%" :width "100%" :position "relative"} :ref (fn [mydiv] (if (some? mydiv) (swap! chart assoc :chart (js/Highcharts.Chart. mydiv (clj->js @my-chart-config))) (let [mychart (:chart @chart)] (if (some? mychart) (do (.destroy mychart) (swap! chart :chart nil))))))}))))

danielstockton10:03:22

It looks roughly the same as my version although you don't need an atom, you can use goog.dom.dataset on the div (see get-chart in my example). Also (if something (do ... should be (when something ...

danielstockton10:03:42

https://github.com/jonase/kibit is really good at catching things like (if something (do

rauh10:03:50

@thinhptran Why not, (swap! chart update :chart (fn [old] (when old (.destroy old)),,, (when mydiv (js/Highcharts....))))

rauh10:03:50

FYI, in clojure you shouldn't do that (ie: sideeffect in the swap function).

thinhptran10:03:32

@rauh: Where is the sideeffect? Please explain to me.

rauh12:03:42

@thinhptran Presumable (.destroy old) has a side effect. It's all good in cljs though.

misha15:03:52

greetings, what do I have to do, to import this in cljs ?

import { DOMProperty } from 'react-dom/lib/ReactInjection'
I tried
$ npm install react react-dom
then
:compiler {...
                           :foreign-libs [{:file "node_modules/react-dom/lib/DOMProperty.js"
                                           :provides ["DOMProperty"]
                                           :module-type :commonjs}]
...
(:require [DOMProperty])
but I get
ERROR: JSC_ES6_MODULE_LOAD_ERROR. Failed to load module "./reactProdInvariant" at node_modules/react-dom/lib/DOMProperty.js line 13 : 21
ERROR: JSC_ES6_MODULE_LOAD_ERROR. Failed to load module "fbjs/lib/invariant" at node_modules/react-dom/lib/DOMProperty.js line 15 : 16
which means I need to either list every dependency of DOMProperty.js (and deps of deps, etc.) in :foreign-libs, or do something else. is there something else?

misha15:03:26

js/ReactDOM does not expose anything from react-dom/lib as an attribute (in case of (:require [cljsjs.react-dom])), which would be nice. in project created with re-natal, js/require just works, but it is not the case with e.g. figwheel template, and I am not familiar with js-magic diff between those two.

thheller15:03:09

@misha are you using a bundled React or straight from the new :npm-deps stuff?

misha15:03:46

I tried cljsjs one first, but then just did npm install

thheller15:03:48

if cljsjs.react-dom that is an already bundled version. it does not contain individual files you can require

misha15:03:23

yeah, I assumed so, so I npm'ed react-dom. but then again, I didn't find an easy way to require the thing w/o listing all it's deps explicitly, which is harold

thheller15:03:15

I don't think you need to list every dependency, just React which then should provide the DOMProperty on its own

thheller15:03:35

not exactly sure under which name though as the name stuff is rather confusing

misha15:03:51

:foreign-libs [{:file "node_modules/react-dom/index.js" :provides ["DOMProperty"]

ERROR: JSC_ES6_MODULE_LOAD_ERROR. Failed to load module "./lib/ReactDOM" at node_modules/react-dom/index.js line 3 : 17

thheller16:03:39

AFAICT its an all or nothing deal but I might be wrong

thheller16:03:16

so you can't just cherry pick ReactDOM but also need React and everything else

misha16:03:12

I think it is related to paths, where it tries to follow dependencies, but fails due to mismatching "./lib/ReactDOM" and "./node_modules/react-dom/lib/ReactDOM"

Lone Ranger16:03:45

qq for all you fine folks: currently learning cljs, what can I look forward to for replacing ajax? Would love to just have a straight-forward way to async assign a value to a variable. What's used for this instead? Go-blocks/channels?

manutter5116:03:28

@goomba there’s a cljs-ajax lib you can use

misha16:03:38

Uncaught ReferenceError: require is not defined    at ReactDOM.js:1
goog.provide("module$node_modules$react_dom$lib$ReactDOM");var ReactDOMComponentTree$$module$node_modules$react_dom$lib$ReactDOM=require("./ReactDOMComponentTree");
I give up -_-

Lone Ranger16:03:06

@manutter51 have you used it at all? is it better than javascript?? oooo can you put the ajax call returns into channels? That would be amazing

anmonteiro16:03:12

@misha a few things: 1) ReactDOM private APIs are not really supposed to be used so you need to know you’ll be on your own if React happens to change those APIs 2) as @thheller said, it’s gonna be an all-or-nothing approach. if you wanna get at the DOMProperty module, you’ll have to consume ReactDOM from NPM. While that’s possible in ClojureScript master, the feature is still unreleased

misha16:03:30

@anmonteiro I installed react, react-dom from npm locally to my project's node-modules.

anmonteiro16:03:28

the easiest way you can get that in your project is by creating a JS file with:

var React = require(’react’);
var ReactDOM = require(’react-dom');
var ReactDOMProperty = require(’react-dom/lib/DOMProperty’);

module.exports = {
  React: React,
  ReactDOM: ReactDOM,
  ReactDOMProperty: ReactDOMProperty
};

misha16:03:45

the latest issue I get is

{:file "node_modules/react/dist/react-with-addons.js"
 :provides ["React"]
 :module-type :commonjs}
does not generate any errors on lein clean; lein cljsbuild once dev, but
{:file "node_modules/react-dom/dist/react-dom.js"
 :provides ["ReactDOM"]
 :requires ["React"]
 :module-type :commonjs}

ERROR: JSC_ES6_MODULE_LOAD_ERROR. Failed to load module "react" at node_modules/react-dom/dist/react-dom.js line 8 : 23

anmonteiro16:03:34

please read what I said, then follow that part of the JS modules guide

anmonteiro16:03:52

if you still have any questions after doing that, feel free to ask them

misha16:03:14

is [org.clojure/clojure "1.9.0-alpha14"] - (version) critical for this to work?

mikerod16:03:49

Is there something in cljs I’m not aware of involved in this example. I was reading through some reagent source, and I see this .-watchesArr field [1] being referenced on a RAtom type object in the fn notify-w, called by RAtoms impl for -reset!. I do not see a field named this in the deftype declaration [2] though. There is a field named watches, but not watchesArr. Where does this come from? [1] https://github.com/reagent-project/reagent/blob/master/src/reagent/ratom.cljs#L74 [2] https://github.com/reagent-project/reagent/blob/master/src/reagent/ratom.cljs#L121

thheller16:03:27

@mikerod this is JS, you can add properties randomly. not exactly best practice but possible

mikerod17:03:48

@thheller I know js is very flexible in the regard. however, I don’t see anywhere where it is “added"

mikerod17:03:57

and it isn’t clear to me how you could add it to a deftype

rauh17:03:58

@mikerod Just ctrl-f for "watchesarr". It's added a few lines above

mikerod17:03:49

(deftype Trial [])

(let [t (->Trial)]
  (set! (.-madeUp t) 5)
  (.-madeUp t))
;;= 5

mikerod17:03:08

so I didn’t realize you could do that in cljs. I knew js doesn’t care.

mikerod17:03:21

I guess I expected set! to reject it in some way. good to know I guess.

rauh17:03:04

@mikerod

(let [k :foo]
  (set! (.-a k) 8)
  (.-a k))
🙂

rauh17:03:22

Anything goes.

mikerod17:03:15

I haven’t been doing too much with cljs yet, this is a surprise to me

mikerod17:03:28

I’m used to clj

rauh17:03:47

Hey, at least we can specify! and clj can't 🙂

mikerod17:03:55

set! is pretty strict there. I know that Java classes don’t allow arbitrary new fields to be added etc, but I still just figure cljs-the-language would try to prevent it

mikerod17:03:07

yeah, specify! is cool

mikerod17:03:41

I’ll also note that the docs for set! in cljs aren’t really to informative to this “feature"

(clojure.repl/doc set!)

-------------------------
set!
   (set! var-symbol expr)
   (set! (.- instance-expr instanceFieldName-symbol) expr)
Special Form
  Used to set vars and JavaScript object fields

  Please see 

mikerod17:03:51

http://clojure.org/vars#set is clj docs and only discusses semantics around vars

mikerod17:03:13

I guess you can interpret instanceFieldName-symbol as meaning anything you want to add as well. 😛

selfsame17:03:27

yeah it's a special form for the = assignment operator

mikerod17:03:58

Just seems sort of “unofficially” that it is that

mikerod17:03:04

looks like it is being used that way though

selfsame17:03:48

user=> (fn [] (set! (.-a #js {}) 2))
#object[ret__6208__auto__ "function (){
return {}.a = (2);
}"]

selfsame17:03:40

but yeah special forms are a compiler thing: https://clojure.org/reference/special_forms

thheller17:03:50

@mikerod currently CLJS doesn't know enough to know whether the field you are trying to set! is actually defined

thheller17:03:08

that would probably be very hard to implement ...

thheller17:03:42

and since JS doesn't care there is no warning, different story in CLJ as you can't do that due to Java

thheller17:03:39

but you should actually never ever do this deliberately (IMHO)

mikerod17:03:09

@thheller I was actually trying to truck along through the cljs analyzer and compiler to see where this was

mikerod17:03:16

but the analyzer seems to suggest it has to be a known field or var

mikerod17:03:25

clearly this isn’t the case, but to demonstrate

mikerod17:03:15

(set! (.-x :k) 5)
;;= 5

(cljs.analyzer/parse 'set! nil nil '(set! (.-x :k) 5) nil)
;; #error {:message "set! target must be a field or a symbol naming a var", :data {:tag :cljs/analysis-error}}

mikerod17:03:27

there is a lot more going on with the repl environment etc, so I’m clearly on a different path

mikerod17:03:39

however, it is odd to me that the analyzer actually throws the sort of exception I would expect

mikerod17:03:17

the nils in the cljs.analyzer/parse may be the key, but I’m not sure how they would be

mikerod17:03:24

I would say it is just a repl thing, but you can do this in non-repl compiled code and it works, so more to it than that I believe

thheller17:03:20

well parse really is for the analyzer to call

thheller17:03:40

you can call analyze though

mikerod17:03:00

yeah… but that happens, I’m just not passing the same env (I’m passing nil)

mikerod17:03:10

also, dynamic bindings are checked during all this, and I don’t have them set the same

mikerod17:03:15

still not sure why that’d make this analyzer error go away

mikerod17:03:15

@selfsame yeah, I really was wanting to see the path to this js. note it also works on literals:

(fn [] (set! (.-a :k) 2))

#object[ret__24650__auto__ "function (){
return new cljs.core.Keyword(null,"k","k",-2146297393).a = (2);
}"]

mikerod17:03:55

I just watned to follow through that flow to see how it happens since it seems to be an undocumented ability of cljs set!

mikerod17:03:16

(also, I like seeing how compiler details work just for general understanding)

dnolen17:03:20

@mikerod I wouldn’t spend any more time on this line of thought

dnolen17:03:26

there’s no value in restricting set!

mikerod17:03:59

@dnolen I’m not really taking a side on it one way or the other

mikerod17:03:05

just wanted to better understand it

thheller17:03:09

@mikerod your call to parse is one-off

mikerod17:03:24

I get it that in js it is common to just throw new things fields on objects etc

thheller17:03:35

(cljs.analyzer/parse 'set! nil '(set! (.-x :k) 5) nil nil)

dnolen17:03:37

@mikerod this isn’t why it works the way that it does

dnolen17:03:00

in Java you can prevent this sort of thing at a low level

dnolen17:03:06

not so with JavaScript

dnolen17:03:17

but you need set! for interop

dnolen17:03:50

there’s no deeper reason for it working the way it does in ClojureScript than this

mikerod17:03:48

@thheller yeah, woops, it is a different error that way.

mikerod17:03:37

either way, it’s not a big deal. was just finding it interesting to dig in the details

paszek18:03:52

I’m going through https://github.com/clojure/clojurescript/wiki/Quick-Start and noticed that http://utopia.knoware.nl/~hlub/uck/rlwrap/ is down, so my brew install rlwrap does not work. Is it temporary problem?

Lone Ranger18:03:36

@paszek if that tutorial is confusing, try not to feel discouraged. That tutorial put me off of clojurescript for like 2 months

Lone Ranger18:03:19

I'd recommend the walkthrough at http://purelyfunctional.tv

dnolen18:03:22

@paszek: you don’t need rlwrap, you can just drop it and still make through the tutorial

paszek18:03:47

@goomba I’m familiar with clojure but wanted to know how clojure script works. And I like low level approach from github tut.

Lone Ranger18:03:21

Ok, good... just wanted to share my experience in case it was discouraging

rgdelato18:03:42

I started with lein new figwheel [directory] -- --reagent just to get something I could immediately run and mess around with, and then I eventually went back and did the quick start tutorial afterwards

Lone Ranger18:03:24

Coming from a Python/JavaScript shop learning the compilation/tooling has been the biggest hurdle

Lone Ranger18:03:29

the syntax and language is a dream

rgdelato18:03:58

to be fair, if you were coming from some other language to JS, learning the compilation/tooling would probably still be your biggest hurdle. Webpack or Gulp, then Babel/ESLint/Prettier/etc

Lone Ranger18:03:46

yeah, I can see that. And if Python wasn't my "native" language I'm sure it would confuse the hell out of me. I can understand why it's maddening to other developers

Lone Ranger18:03:14

lein is actually really really nice

Lone Ranger18:03:21

for organizing dependencies and such

dnolen18:03:26

@goomba we could probably be clearer that rlwrap isn’t a requirement

paszek18:03:54

@dnolen ok, thanks. so wouldn’t it be better if we drop rlwrap from tutorial? less confusion

Lone Ranger18:03:28

@dnolen You wrote the tutorial?? Wow, I'm really sorry if my comments seemed disparaging

dnolen18:03:36

@paszek does brew install rlwrap really not work - the website being down is not relevant

dnolen18:03:59

@goomba no offense taken 🙂

Lone Ranger18:03:34

@dnolen You're a better person than me.

paszek18:03:00

@dnolen `brew install rlwrap Warning: You are using OS X 10.12. We do not provide support for this pre-release version. You may encounter build failures or other breakages. Please create pull-requests instead of filing issues. ==> Downloading http://utopia.knoware.nl/~hlub/rlwrap/rlwrap-0.42.tar.gz curl: (7) Failed to connect to http://utopia.knoware.nl port 80: Operation timed out Error: Failed to download resource "rlwrap" Download failed: http://utopia.knoware.nl/~hlub/rlwrap/rlwrap-0.42.tar.gz`

dnolen18:03:11

this seems like a brew problem

Lone Ranger18:03:27

@dnolen If I'd read the whole tutorial in advance and then attempted it, I think it would've made more sense. But it was the "doing it the wrong way to show you how to do it the right way" that really tripped me up... I spend a LONG time trying to figure out why what I was doing wasn't working BUT if I'd read one more paragraph ahead I would've seen that you were trying to illustrate a point 😂 😂

dnolen18:03:47

but we can just leave a note on the tutorial that rlwrap is optional and that should be enough

dnolen18:03:04

if you’ve submitted your CA then send a PR to the clojurescript-site repo to fix the tutorial

Lone Ranger18:03:36

so that's really on me 😛 😛 😛 can't blame a tutorial for my reading comprehension issues

dnolen18:03:11

@goomba yes people complain about that approach in the tutoiral, but really it’s either that or people coming in and asking exactly that question

dnolen18:03:21

which they did all time

Lone Ranger18:03:25

😂 😂 😂

dnolen18:03:28

before I changed the tutorial to cover it

Lone Ranger18:03:43

Can't make anyone happy, especially programmers

Lone Ranger18:03:42

question... I have a really large existing project and I've successfully made the case to migrate from js to cljs BUT it seems like the only option right now is to scrap all the js and start over in cljs... that pitch isn't going too well. Any tips on integrating cljs into an existing js project?

jimberlage18:03:10

@goomba Are there any particularly thorny libraries which exist in their own JS namespace/function? I've had some success getting employers to let me rewrite stuff like that in clojurescript, especially if the JS is so messy that other developers are afraid to touch it

Lone Ranger18:03:22

no... the worst I'm using is jQuery

Lone Ranger18:03:42

and highcharts

jimberlage18:03:13

I guess as a general rule, maybe pick a few functions/features that are messy and simplify them with cljs? I usually ^:export a few CLJS functions and integrate them with the current codebase to demonstrate that I can do the migration incrementally

Lone Ranger19:03:37

@jimberlage cool... I'll look into that. Unfamiliar with the ^:export technique... sounds like it's a tool for cljs/js interop?

Lone Ranger19:03:11

drool that's exactly what I needed

kurt-o-sys19:03:16

Anyone got onsen UI (+react or +vue.js) running with cljs?

ballpointpenguin20:03:47

ClojureScript n00b here. I'm curious if anybody things getting ClojureScript exercises into http://exercism.io would be helpful? http://exercism.io/languages

ballpointpenguin20:03:49

or if it's enough that Clojure is there, because they are functionally identical..?

ballpointpenguin20:03:12

(I mean, they do have Common Lisp and Scheme and Emacs Lisp)

ballpointpenguin21:03:58

OK I made an official request

ballpointpenguin21:03:01

Another reason to have a distinct cljs track is because with exercism, you are running the compiler and tests on your own machine, so it is good for learning the language and testing syntax, but also for getting it running and understanding the tools, compiler, etc

vemv21:03:22

--- anyone know how to access the current cljs build from cljs code at runtime?

vemv21:03:58

i.e. I'd like to know if I'm in my dev prod or test build, so I can conditionally do stuff

vemv21:03:03

...google seems to indicate that people just don't have/do this +1'd https://github.com/emezeske/lein-cljsbuild/issues/445

jr21:03:07

I usually use a macro which omits code based on env instead of conditionally running it

jr21:03:15

environ comes in handy there

vemv21:03:52

will play with closure-defines, seems fairly classy. cheers @jr!