Fork me on GitHub
#clojurescript
<
2016-02-03
>
jlongster00:02:22

is there an idiomatic way to get the type of a variable in CLJS?

easystreet00:02:43

jlongster: goog.typeOf

sashton02:02:44

I'm trying to define a macro and use it in cljs. I created the macro in a clj file (util.clj) in my clojurescript source directory. The compiler wasn't able to find the namespace. But when I added an empty util.cljs file in the same directory, the compiler was happy and everything worked. Is that expected, or am I missing something?

danielcompton03:02:01

I thought I understood this, but now I’ve got myself confused. If I want to access the properties of a JS event under advanced compilation, should I use (.-target evt) or (goog.object/get evt “target”) or is there no difference?

chrisoakman03:02:49

I always use aget with strings

chrisoakman03:02:02

(aget js-obj "foo" "bar")

chrisoakman03:02:30

The GClosure compiler never touches strings, so it's safe with advanced compilation

chrisoakman03:02:10

it's doubtful I will stop using it that way

sonelliot03:02:47

@sashton: Do you have two different source directories for the two languages? Like src/clj and src/cljs?

chrisoakman03:02:48

I just read that thread; I see where David is coming from

sonelliot03:02:41

@sashton: I tend to define my macros in a src/clj/app/macros.clj and require them in my CLJS code with the :require-macros ns form.

sashton04:02:20

@sonelliot I thought I read somewhere that the macro file needed to be in the clojurescript classpath, src/cljs/.../macros.clj

sonelliot04:02:09

@sashton: I haven't heard of that sorry 😕 It's my understanding that macros need to be done in a separate compilation phase. Although this may be different with self-hosted CLJS.

sashton04:02:57

Ok I'll try it again tomorrow, thanks

jaredly06:02:11

@jlongster: I think case only works w/ literals — e.g. js/ variables won’t work. It also doesn’t work with vars; it has to be ints, chars, strings, etc

tap09:02:22

Option {:keywordize-keys true} for js->clj function doesn’t seem to work as expected for me. This is an output from my repl

cljs.user=> (get (js->clj (clj->js {:a 1}) {:keywordize-keys true}) :a)
nil
cljs.user=> (get (js->clj (clj->js {:a 1}) {:keywordize-keys true}) "a")
1
cljs.user=> (get (js->clj (clj->js {:a 1}) :keywordize-keys true) :a)
1
cljs.user=> (get (js->clj (clj->js {:a 1}) :keywordize-keys true) "a")
nil
Do you spot any obvious mistake I have made? [Update] Nevermind. I saw a patch here http://dev.clojure.org/jira/browse/CLJS-1540

octahedrion09:02:56

@acron: in Garden, attributes are given in a map, but sometimes you need multiple defs of an attribute, in which case can't do that in a map because duplicate keys

acron09:02:41

@octo221: Do you mean for CSS such as "border: 1px solid red" ?

acron09:02:53

@octo221: in Garden for multiple attribute values you use a nested vector, e.g. {:border [[(px 1) :solid :red]]}

octahedrion09:02:24

@acron, no multiple definitions of the same attribute

acron09:02:36

what's the use case for that?

octahedrion09:02:09

e.g. "image-rendering=pixelated image-rendering=moz-crisp-edges ..."

octahedrion09:02:23

because different browser use different defs

acron09:02:31

@octo221: have you looked at the vendor prefix stuff?

acron09:02:47

not sure that'd help..

octahedrion09:02:58

that's for values I think

acron09:02:56

you're right 😕 in that case, no, i'm not sure how you'd do this

octahedrion09:02:29

same attribute defined multiple times, can't be expressed with a map

octahedrion09:02:57

unless maybe it can take vectors as keys as well as for values

octahedrion09:02:06

need to read the source

octahedrion10:02:02

@acron: found a workaround: add spaces like this [:.class {"attr" 7 " attr" 8 " attr" 9}]

acron10:02:36

@octo221: ouch! but nice 😛 I hope you've raised an issue in Garden

octahedrion10:02:55

oh yeh good point

gzmask15:02:03

has a complete THREE-JS extern file been written yet?

gzmask15:02:16

one on CLJSJS is half assed

gzmask15:02:30

on a second thought, one could write a JS parser to automatically generate the extern file of any library?

jaen15:02:09

Theoretically, possibly not super easy though, or we would have one already.

gzmask15:02:37

I think that is the only missing link to bridge JS and CLJS now.

gzmask15:02:16

without extern files, the advanced optimization won't work

juhoteperi15:02:55

I think existing extern generators evaluate the JS code on Node (or such) and check the created JS object to create the extern

juhoteperi15:02:11

Easier than writing parser (or using one) directly

gzmask16:02:25

there is an extern generator?

dottedmag16:02:30

export['a'+(''+Math.random()).substr(2)] = function(){...};

dm316:02:59

I'm trying to create a bootstrapped browser clojurescript evaluation environment with a namespace which has some macros/fns :used available in the evaluation state. My problem is - I cannot call macros. Should it be at all possible? E.g.:

;;;;;;;;;;;;;;;;;;;;;;;;;; my-ns.cljs - the context of evaluation
(ns my-ns
   (:use-macros [javelin.core :only (cell=)]
   (:require [javelin.core :refer (cell)])))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; eval.clj - evaluator helper to preload the ns into compiler state
(ns eval
  (:require [cljs.env :as env]
                       [cljs.analyzer :as ana]))

;; ---- mimics how the cljs.core ns is loaded
(defmacro dump-my-ns []
  (let [state <@U095WMJNR>/*compiler*]
    `(quote ~(get-in state [::ana/namespaces 'my-ns]))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;; eval.cljs - provides the environment
(ns eval
   (:require [my-ns]))

(def state (empty-state (fn [state] (assoc-in state [::ana/namespaces 'my-ns] (dump-my-ns)))))

(defn eval [forms]
    (eval state forms {:eval js-eval, :ns 'my-ns, :def-emits-var true} println))


(eval '(def x (cell 1))) ;;; works
(eval '(def y (cell= x))) ;;; fails to find the "javelin.core$macros" ns when resolving the cell= macro

dm316:02:22

I see that cljs.js does a goog.require("cljs.core$macros") at the top of the file

dm316:02:27

but this doesn't magically add the mappings

mfikes16:02:20

@dm3: Have you set up a load function? (That way, :require, etc. can load the required code.)

mfikes16:02:42

@dm3: You may be able to also dump javelin.core and javelin.core$macros (it is not clear to me exactly how to do that, but I suppose you can imitate what the compiler does with core), but while that takes care of the analysis metadata, there’d be the issue of loading the actual code that implements the cell= macro.

mfikes16:02:03

@dm3: cljs.js is designed to compile macro code as a result of (dynamically) loading it via the load function. Perhaps you are wanting to AOT transpile the macro code so that its JavaScript is available.

jaredly16:02:08

tools.reader says ::ana/namespaces is not a valid token… but it’s in the cljs source https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/js.cljs#L116 — is there some extra config I need to set to make it parseable?

mfikes16:02:55

@jaredly: If you control the source you are trying to evaluate in bootstrap, you could consider working around it by using :cljs.analyzer/namespaces

jaredly16:02:43

I’m actually working on making a parser, and benchmarking it against tools.reader by reading all of the cljs source, but then I ran into something tools.reader couldn’t handle 😄 so I’m confused

mfikes16:02:19

:ana/namespaces in cljs.js would be properly resolved/expanded by the regular JVM-based ClojureScript compiler. Bit, in bootstrapped ClojureScript, there is probably a bug or shortcoming.

mfikes16:02:12

(If you aren’t in bootstrap, it is probably still just a shortcoming of that library.)

jaredly17:02:20

yeah it’s bootstrapped

mfikes17:02:32

I think that corner cases like this one, and recently syntax quoting of symbols, are just bugs being discovered and sorted.

jaredly17:02:15

cool. should I report?

mfikes17:02:59

To list them off:

`x
didn’t work until recently. But then there are issues like
`catch
inadvertently not being treated as special. Then there is
#{1 2 1}
not throwing. So, I think the inability to handle ::alias/name is likely just another of these corner cases.

mfikes17:02:16

@jaredly: If you report a bootstrapped issue against ClojureScript—I took a stab at documenting the special considerations when doing that: https://github.com/clojure/clojurescript/wiki/Reporting-Bootstrap-Issues

sooheon17:02:17

Using these instructions (https://github.com/cljsjs/packages/tree/master/nvd3), I’m trying to use nvd3 packaged by cljsjs like this (https://gist.github.com/sooheon/10a7de8ea0c8c654c2f3). With advanced compilation, the functions still get mangled. Am I doing anything obviously wrong?

rohit17:02:49

@sooheon: it shouldn’t be happening as the objects you are using have externs. could you try turning on :pseudo-names in compiler options to see which ones are getting mangled? details here: https://github.com/clojure/clojurescript/wiki/Compiler-Options#pseudo-names

sooheon17:02:07

@rohit sure. recompiling now

sooheon17:02:13

I’m seeing the same error in console, how do I see this additional information?

rohit17:02:39

@sooheon: hmm…the error should which name is missing. whats the shape of line-chart-data in your code? perhaps i can help you debug this

sooheon17:02:51

here’s the source code and main.js side by side

rohit17:02:55

@sooheon: issue seems to be useInteractiveGuideline

rohit17:02:19

…and it seems that it is missing from the extern

sooheon17:02:51

ah that’s all it is. same with axisLabel below, and so on

rohit17:02:51

looks that way

sooheon17:02:04

could you give me an example of how to add, say axisLabel to externs? Not sure of what class it belongs to and so on… do I just have to look at the nvd3 docs?

sooheon17:02:02

nv.models.lineChart().axisLabel = function(){}; would this work?

rohit17:02:18

let me see if i can generate the externs using a program which can create externs

rohit17:02:40

@sooheon: bummer. looks like externs will need to be done by hand

rohit17:02:21

you can certainly add nv.models.lineChart.axisLabel = function(){} to the bottom of the extern file

rohit17:02:54

and also nv.models.lineChart.useInteractiveGuideline = function(){}

sooheon17:02:04

yeah it’s a really one off case, so I don’t doing it by hand, just not sure of the js syntax

sooheon17:02:13

Ok, thanks. Actually, something completely different, but how would you add externs to use these dropdowns from semantic-ui? http://semantic-ui.com/modules/dropdown.html#/examples

sooheon17:02:37

The function is just .dropdown, but somehow it seems like doing .dropdown = function(){} would not work

rohit17:02:17

not sure how to handle the jQuery bit. let me have a look

sooheon17:02:25

Here’s the js file, if you need it^^

rohit17:02:37

that should be similar to your extern.

sooheon17:02:52

ok so it should all go under jQuery.prototype?

rohit17:02:05

that would make sense

sooheon17:02:12

Got it, thanks :)

rohit17:02:07

sure. best to ping in #C0E66E1H7 as well, a channel dedicated to stuff like this

dm317:02:13

@mfikes thanks - think I understand the issue now

rohit17:02:53

@gzmask: have a look at this project for generating externs automatically: https://github.com/jmmk/javascript-externs-generator

rohit17:02:44

this may generate full externs

rohit17:02:39

@gzmask: the above project will not be able to handle something like this

var Person = function(name) {
  
  this.name = name;
  this.greet = function() {
    .....
  }
}

rohit17:02:09

or rather it won’t be able to generate the full extern for Person

rohit17:02:24

i think to generate externs for this may require you to get the information from the AST. but don’t hold me to it.

sooheon17:02:32

@rohit: I think that mention was meant for me—thanks.

rohit17:02:41

actually @gzmask also raised this issue a few hours ago. but yup, (i think) this is the reason why the nvd3 externs aren’t complete

gzmask20:02:35

yea, this extern thing is starting to get out of hand when dealing with large and complicated libraries. I might just give up advanced optimization and go with simple.

jaen20:02:20

If you're doing this for browser that might not be a good idea - non-optimised Clojurescript application can be in megabytes.

jaen20:02:31

If you're doing it for node, then that's probably a good idea.

gzmask20:02:24

how large is the core lib of cljs? megabytes?

dnolen20:02:55

if you don’t use advanced optimization you don’t get fancy stuff like dead code elimination etc.

dnolen20:02:17

ClojureScript with advanced optimizations starts around 20K gzipped and goes up from there, depending on what you’re doing

gzmask20:02:47

I guess we do need perfect extern auto-generation then (AST parsing?)

dnolen20:02:57

but if you’re using Three.js you’re already OK with a fairly large dep, >100K gzipped

dnolen20:02:07

to be clear no you don’t need perfect externs

dnolen20:02:18

you can just make a file with all the bits you are actually using

dnolen20:02:37

externs aren’t related to dead code elimination - it just prevents advanced optimization renaming

gzmask20:02:54

that means I should be using advanced in development profile then?

dnolen20:02:13

you only need to identify the APIs bit you are actually using

dnolen20:02:35

you don’t need to worry about anything you don’t actually call, or property you don’t actually access

gzmask20:02:06

that's what I have been doing, everytime I do JS interop I have the extern file open for updating

dnolen20:02:04

that’s the only way then - or use something that’s Closure friendly like Toxi’s stuff

gzmask20:02:35

I guess that's the price we have to pay for using CLJS.

dnolen20:02:00

right though difference in the payload is dramatic

gzmask20:02:06

wait, if every time we do (js/sth) an extern sth should be generated, then extern generation could still be automated ?

dnolen20:02:44

was slated to be part of the GSoC project but we didn’t get to that bit

dnolen20:02:02

anybody can work on it, though probably worth getting in touch with Maria Geller to see if she started down some particular path

gzmask20:02:04

excited! when cljs has built-in dead-code-elimination, it will just become a unicorn ; )

dnolen20:02:29

well this feature was dubbed “externs inference"

dnolen20:02:01

it’s not a particularly a hard task - if it’s going to happen somebody who cares should work on it

dnolen20:02:40

(we’re unlikely to bother with much DCE of our own, Closure Compiler is works perfectly well)

dnolen20:02:08

on the externs inference bit happy to show anyone who is serious about tackling what needs to be done

dnolen20:02:35

but yes inferring js/foo + js type hint should cover most typical non-Closure JS interop

killion23:02:23

Howdy! I had a question about bundling JS libs into my compiled Closurescript. I’ve added the libs that I want such as JSTZ to my project.clj like so…

:foreign-libs [ {:file ""
                                           :file-min ""
                                           :provides ["jstz”]}
but I don’t see any changes with my compiled code. I’ve checked in Figwheel, using lein cljsbuild once and in my compiled jars just to be safe. I’m definitely missing something, thanks!

easystreet23:02:39

you need to require it (and possibly even call it) in order for it to be prepended to your output file

killion23:02:20

Ah, I was wondering if that would be necessary. Thanks, let me try that now.

killion23:02:00

Yup, that was it exactly. Man I wish I had asked yesterday. Thanks!

maria23:02:06

@gzmask: I would say that the auto extern generation task is halfway complete. Functionality for parsing existing externs and emitting externs for simple js interop, like (.-foo bar) already works. Still need to add extern generation for more complex js interop, e.g. let bindings. I’ve pushed my progress to a separate branch here (https://github.com/mneise/clojurescript/tree/CLJS-1074). Help is always welcome simple_smile

killion23:02:57

Nice @maria, I’ll see if the externs I’m calling are missing any interop types that your branch doesn’t support.

dragoncube23:02:23

btw, when is ClojureScript 1.8 is planned?