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

Careful of security issues simple_smile And I’m not sure if it’s primetime yet.

escherize00:03:41

I see. Very useful background @smw. I'm going to see if i can copy this and make it work. https://github.com/Lambda-X/replumb/tree/master/repl-demo/browser/cljs/replumb_repl

smw00:03:22

newer versions of planck might do it out of the box?

smw00:03:29

don’t know if that meets your needs

mfikes00:03:41

@smw @escherize you can use the cljs.js namespace that ships with ClojureScript to evaluate stuff. It is not compatible with :advanced and results in a decent amount of extra code if you go that route. Using the reader, on the other hand, doesn't have those aspects.

escherize00:03:23

Yeah, I'm trying to do it in the browser, @smw

smw00:03:04

Neat. Didn’t know how far that had come.

smw00:03:22

Planck is amazing, btw, thanks Mike.

mfikes00:03:27

@escherize: give http://ClojureScript.io a spin to see its loading perf.

escherize00:03:03

right, @mfikes, for my referenece, the reader is unable to evaluate, right? and is there some function in cljs.js where

(cljs.js/magic "(def a 1) a") 
;;=> 1

escherize00:03:30

yeah, I'm currently copying the implementation of http://clojurescript.io (replumb has an example section)

mfikes00:03:09

@escherize: if you wrap that in a do you can use cljs.js/eval-str

escherize00:03:36

Hmmmm, then I might not need replumb X_X;

smw00:03:13

On a slightly related question, is there a figwheel-style workflow working with planck somewhere?

mfikes00:03:30

@escherize: right. Replumb is on top of cljs.js and adds REPL functionality.

escherize00:03:52

Here's what I'm working on btw: http://take.ms/D3VkQ

mfikes00:03:27

@smw No. Planck supports (require 'some.ns :reload). It does not have code to watch the filesystem and load code when saved. (But it theoretically could.)

mfikes00:03:29

@escherize: I suppose a fiddle is sufficiently different from a REPL where Replumb might not be as useful as just using cljs.js directly

escherize00:03:56

I agree with you there @mfikes.

richiardiandrea00:03:07

we all agree with @mfikes 😄

mfikes00:03:19

I agree with @mfikes as well :)

richiardiandrea00:03:54

when you @ your own name do you receive a notification?

mfikes00:03:42

I was wondering the same. In iOS, it is not highlighted yellow FWIW.

richiardiandrea00:03:23

but @escherize feel free to copy and paste and let me know if I can help if you are stuck ok? A lot of what you see in replumb is based from planck which was I guess based on that David project above

escherize00:03:53

I'll take you up on that offer

escherize00:03:01

trying to force eval-str to play nice now

mfikes00:03:18

@escherize: yeah, if you get stuck, just ask. One common mistake is to fail to initialize a namespace so that def forms can do their side effects. Pure expressions work without that though.

richiardiandrea00:03:21

btw we will soon open source a Code Mirror re-frame component (it will be added to http://clojurescript.io as well)

escherize00:03:34

I want that...

escherize00:03:43

will it have parinfer?

richiardiandrea00:03:06

it is actually Jared work that we are embellishing

richiardiandrea00:03:29

so it will probably have Parinfer yes, or it will be very easy peasy to add

mfikes00:03:34

@escherize: Yogthos has a lot of good stuff in that article. Wonder why he skipped using eval-str. Maybe just an oversight.

escherize00:03:08

okay, @mfikes I think I ran into that problem, where there's no ns to def into (is that the proper way to say it?)

escherize00:03:35

(defn eval-str [s]
  (eval (empty-state)
        (read-string s)
        {:eval       js-eval
         :source-map true
         :context    :expr}
        (fn [result] result)))

(defn run []
  (reagent/render-component
   (fn [] (eval-str @cljs-string))
   (.getElementById js/document "baby-dom-target")))

escherize00:03:55

maybe something like... (defn with-ns [x] (str "(ns blah) " x))

mfikes00:03:17

@escherize: Right… no need to define an eval-str that calls read-string. That’s built into cljs.js/eval-str.

yogthos00:03:30

@mfikes: definitely an oversight simple_smile

richiardiandrea00:03:38

yes that too 😉

mfikes00:03:44

@yogthos: Yeah, I figured.

mfikes00:03:55

@escherize: With respect to the namespace: If you don’t indicate which namespace to eval in, cljs.js defaults to cljs.user. But there remains the fundamental issue that there is a cljs global object with a user object, etc.

mfikes00:03:05

So, how do you create a namespace in bootstrap? In Planck, I have it evaluate an ns form if the user does in-ns and the namespace doesn’t yet exist. There are probably different ways to skin that cat.

escherize00:03:16

@richiardiandrea: so those are the options for eval-str, right?

richiardiandrea00:03:44

basically replumb options are a mix of compiler options and its own, :target :default is from the compiler but you don't need it if you are targeting the browser

richiardiandrea00:03:01

@escherize: but that code was taken from the clojurescript repl, it is basically needed to init cljs.user

escherize00:03:34

not exactly sure how to use that stuff.

richiardiandrea00:03:11

you might not need it, that is only needed if you want to have a cljs.user ns

mfikes00:03:20

I think if you use cljs.js/eval-str to evaluate "(ns cljs.user)” you are good to go.

escherize00:03:43

(eval-str (empty-state) "(ns cljs.user)" (fn [x] (js/console.log (clj->js x))))
;; prints: Error: No *eval-fn* set at cljs$js$_STAR_eval_fn_STAR_....

richiardiandrea00:03:12

@escherize: are the symbol required correctly? (no :refer [eval-str] on the top)

escherize00:03:34

Here's the ns + calling form:

(ns cljsfiddle.app
  (:require [reagent.core :as r]
            [cljs.js :refer [eval-str empty-state]]))

(let [*eval-fn* identity]
  (eval-str (empty-state) "(ns cljs.user)" (fn [x]
                                             (def *error x)
                                             (js/console.log (clj->js x)))))

escherize00:03:55

get the same error without the let

escherize00:03:06

{:error #error {:message "ERROR", :data {:tag :cljs/analysis-error}, :cause #object[Error Error: No *eval-fn* set]}}

richiardiandrea00:03:05

at some point like above you need to set :eval js/eval in the option map that you pass to cljs.js/eval-str

richiardiandrea00:03:22

same for :load-fn they are required

richiardiandrea00:03:21

so load and no load-fn

venantius00:03:54

does that suggest problem is resolved on HEAD?

venantius00:03:14

just not yet propagated to the latest Planck?

escherize00:03:24

Is all that stuff required, @richiardiandrea ?

richiardiandrea01:03:32

@escherize: no, I would say at the beginning you can just use :ns :load :eval

richiardiandrea01:03:07

:context too to :expr

richiardiandrea01:03:21

and :def-emits-var true

richiardiandrea01:03:17

they are all explained in the compiler option wiki

mfikes01:03:24

@venantius: Planck master builds against ClojureScript master (even if you brew install --HEAD planck)

venantius01:03:56

I just did straightforward brew install

venantius01:03:00

not sure the last time I did brew update

escherize01:03:42

@richiardiandrea: so, here's what I've got:

{:load :source ;; <- misread this: 
 :ns 'cljs.user
 :eval js/eval
 :dev-emits-var true}

mfikes01:03:50

@venantius: right. That fix is not in Planck 1.9, but it is in Planck 1.10 (master)

venantius01:03:15

so if I were to brew install —head I’d be good?

venantius01:03:22

or do I just need to brew update;

mfikes01:03:23

@venantius: meaning you'd have to follow the steps under Install Master here http://planck-repl.org/setup.html

escherize01:03:11

wow, huge thanks to @richiardiandrea !!!

slotkenov07:03:30

Any tips on unit testing ClojureScript code.? I see speclj (https://github.com/slagyr/speclj) is built with both Clojure and ClojureScript in mind.

delaguardo07:03:47

speclj seems outdated, and clojurescript now ships with a port of clojure.test - https://github.com/clojure/clojurescript/wiki/Testing

slotkenov07:03:07

Thank you @delaguardo . How does speclj seem outdated I wonder, not being actively developed lately?

slotkenov07:03:35

Midje doesn’t really have support for ClojureScript does it?

delaguardo07:03:25

latest commit in speclj was about 8 months ago. It makes me think that the project is abandoned

delaguardo07:03:50

know nothing about midje, sorry)

delaguardo08:03:34

in my projects i use https://github.com/bensu/doo and it works like a charm

octahedrion10:03:57

@stephenway: sadly React doesn't support (or Om doesn't support) the use element in SVG https://facebook.github.io/react/docs/tags-and-attributes.html

nidu10:03:00

@danielgrosse: isn't it just (defn get-menu [url] (parse-content (<!! (GET url))))?

dialelo11:03:13

@danielgrosse: note that go blocks are asynchronous and you can't block for a channel's result

dialelo11:03:25

so your get-menu fn can not wait for the GET request to finish

dialelo11:03:40

you will have the result available asynchronously

dialelo11:03:51

<!! and >!! are not available in CLJS @nidu

nidu11:03:01

@dialelo: oh, didn't know about that. Thanks

dialelo11:03:28

happy to help!

escherize12:03:27

So, I'm getting a :cljs/analysis-error when invoking the bootstrapped cljs compiler. But the interesting thing is if I run in development it actually works because I'm allowed to re-evaluate(?) the namespace. I'm invoking the compiler with the a namespace that's been evaluated (def'd?) Sorry my terminology is not good here.

escherize12:03:21

I want to be able to import a library for the cljs bootstrapped compiler, and use it to evaluate some string and return a result.

escherize12:03:47

(ns cljsfiddle.app
  (:require [reagent.core :as r]
            [cljsfiddle.samples-pane :refer [samples-pane]]
            [cljsfiddle.db :refer [db]]
            [cljs.js :refer [eval-str empty-state js-eval]]))
;;----snip-----
(defn my-eval [cljs-string]
  (eval-str (empty-state)
            (str
             "(ns cljsfiddle.app)
              (require '[reagent.core :as r :refer [atom]])"
             cljs-string)
            'dummy-symbol
            {:ns 'cljsfiddle.app
             :eval js-eval
             :dev-emits-var true
             :load (fn [& _] {:lang :clj :source "."})
             :context :statement}
            (fn [{:keys [error value] :as x}]
              (if error
                (do
                  (def *er x)
                  (js/console.log (str error)))
                value))))

escherize13:03:32

Okay, I've figured it out, thanks to that slack scraping bot

escherize14:03:00

Uh, hey guys. So I've gotten an early version of http://cljsfiddle.com up and running.

escherize14:03:15

Would appreciate any feedback around it!

mfikes14:03:24

@escherize: Looks cool… if you haven’t you may want to compile it with :static-fns true, otherwise I think it is going to crap out on Safari.

escherize14:03:04

let me show you what i have right now, @mfikes.

escherize14:03:44

(ns cljsfiddle.app
  (:require [reagent.core :as r]
            [cljsfiddle.samples-pane :refer [samples-pane]]
            [cljsfiddle.db :refer [db]]
            [cljs.js :refer [eval-str empty-state js-eval]]))

(defn my-eval [cljs-string]
  (eval-str (empty-state)
            (str "(ns cljs-user)
                  (def atom reagent.core/atom)"
                 cljs-string)
            'dummy-symbol
            {:ns 'cljs.user
             :eval js-eval
             :def-emits-var true
             :load (fn [& _] {:lang :clj :source "."})
             :context :statement}
            (fn [{:keys [error value] :as x}]
              (if error
                (do
                  (def *er x)
                  (js/console.log (str error)))
                value))))

escherize14:03:06

I suppose i'd pass :static-fns true into the opts map in eval-str?

mfikes14:03:26

@escherize: I’d first try with just :static-fns true in the project itself, so that the base codebase is built that way. You may not need it for user code. It is at least worth trying.

escherize14:03:17

I heard you like compilers...

anmonteiro14:03:05

does it currently only work with Reagent?

reefersleep15:03:15

@escherize: that's excellent! impressed

reefersleep15:03:50

Man, that is so handy. For when I've got an idea I want to test out without access to my normal cljs dev environment

escherize15:03:56

No problem! I really need to add parinfer or paredit or something

mfikes16:03:02

Wow, two thing on the front page of HN today related to ClojureScript simple_smile

pandeiro16:03:18

@escherize: that is absolutely fantastic, congrats

pandeiro16:03:46

defaulting to reagent is a feature IMO 😄

pandeiro16:03:39

the lack of built-in support for require in cljs.js stuff means you can't be very flexible in regard to deps, but this is a fantastic tool for introducing people to cljs nonetheless

escherize16:03:58

yeah.... i learned about that require thing the hard way

escherize16:03:34

I actually did (def atom reagent.core/atom) to simulate the :require at the top of the clojurescript column

pandeiro16:03:24

Yeah, I have done that hack too when playing around with something similar

chrisoakman16:03:15

@escherize: I added some issues to the GitLab repo

pandeiro16:03:23

But a "preset" ns form could be added for some other libs too, maybe like Om obviously, or the toxi stuff which also deserves more attention

escherize16:03:08

thanks @chrisoakman. I'm going to take you up re: parinfer btw

chrisoakman16:03:00

the Parinfer demo page I linked to in the issue is new; seems like there are some obvious synergies between those two projects (can't believe I just used the word "synergy" not in a corporate setting 😉 )

chrisoakman16:03:30

said another way: Ya'll should synergize.

escherize16:03:50

woahhh, demo page

pandeiro16:03:21

@escherize: @mfikes: would pre-compiling a minified lib that just provides cljs.js/eval-str as an exported function improve the startup time of cljsfiddle maybe?

pandeiro17:03:21

sorry, to be more clear, i'm saying you could decouple the app from the eval'ing

mfikes17:03:47

I think it is a worthwhile experiment. You’d still need things like core.js available for the compiled code to call upon. But the compiler itself might work under :advanced.

pandeiro17:03:49

like, the app could load instantly and set up a listener for the cljs.js/eval onload, disabling the run button til it gets that

richiardiandrea17:03:21

I would be of course interested too 😄 I always wondered if you could Make It Faster™

mfikes17:03:56

FWIW, there was a little experimentation on that front here https://github.com/mfikes/planck/issues/58

mfikes17:03:55

But, yeah, you can get a lot of mileage out of the simple idea of bringing up the UI immediately.

thheller17:03:18

@escherize: you should turn on gzip, that would probably half the load time 😛

richiardiandrea17:03:20

in http://clojurescript.io we start with the html with loading 😄

richiardiandrea17:03:35

and we have gzipped our main.js and deps.js

escherize17:03:47

see what happens when you use s3 for a side project?

mfikes17:03:52

(For example, Replete on older devices does just that—and the compiler can take 20 seconds to load and be ready.)

richiardiandrea17:03:13

@escherize: we use s3 as well, no complains so far

mfikes17:03:53

(Nobody notices because you cant type a form in that quickly on a mobile device simple_smile )

thheller17:03:38

@pandeiro you can't use advanced compilation if you want eval

thheller17:03:02

simple might work though

pandeiro17:03:36

i wasn't sure about that, because in cljsfiddle there aren't really any fully qualified vars I could see?

pandeiro17:03:48

but yeah I guess just the cljs.core stuff wouldn't work either?

thheller17:03:20

well since you want to eval something later

thheller17:03:30

the code you eval must be present somewhere

thheller17:03:35

advanced would have renamed things

thheller17:03:43

so the eval'd code wouldn't know it

mfikes17:03:28

But, the analyzer and compiler could be compressed, right?

thheller17:03:05

you can't do a partial :advanced

thheller17:03:12

either all or nothing

thheller17:03:34

or compressed as in gzip?

mfikes17:03:10

I was thinking of a Frankenstein build where you just build everything using :advanced but then keep that separate from :none for the standard lib and evaluating compiled results. You’d almost want two JavaScript contexts.

pandeiro17:03:33

yeah @mfikes, that was kind of what I was imagining as well

thheller17:03:44

that would probably be slower overall

pandeiro17:03:45

or some way to ^:export the entire cljs.core

thheller17:03:53

since you'd download things twice

mfikes17:03:39

@pandeiro: Yes! I had also thought of that, a massive ^:export file. simple_smile

thheller17:03:09

if you export everything you basically have :none 😉

thheller17:03:26

since the closure compiler can do non of its magic

thheller17:03:34

well only a tiny portion

mfikes17:03:00

You’d have the 1 MB core.js file

pandeiro17:03:20

is that gzipped? simple_smile

mfikes17:03:47

148 K gzipped

thheller17:03:17

you could try a :simple compilation with :modules, load the base module on page load and the compiler module later via async request

richiardiandrea17:03:32

yes this is what we do

richiardiandrea17:03:31

but simple sometimes does not behave like none in replumb, I have two issues open for instance, but for escherize it might be good

mfikes17:03:33

I’m still curious about an externs file that covers the entire standard lib, along with everything being subject to :advanced simple_smile

richiardiandrea17:03:58

basically it should not rename clojure.core.map, etc... but every local, assuming there are enough locals to optimize I guess compared to the number of core functions used

thheller17:03:19

thats called :simple

richiardiandrea17:03:20

so basically it is :simple 😄

mfikes17:03:00

Yeah, but :simple only for the standard library

mfikes17:03:36

Its unfortunate that such experiments are a bit costly to carry out.

pandeiro17:03:44

advanced compilation takes a long time?

mfikes17:03:50

Nah… I mean that it is one thing to propose a grand architectural approach, like half-advanced/half-none, or a gigantic externs file covering the standard lib, and another thing to actually execute upon it to see if it makes things faster.

thheller17:03:34

generating the externs is the hard part

thheller17:03:49

the rest should be pretty simple

mfikes17:03:28

Maybe something like (dir cljs.core) is close to what would be in an externs file. Hmm.

mfikes17:03:13

But yeah, do actually pull off one of those experiments would take hours of work.

escherize17:03:20

prs welcome ^_^

escherize17:03:38

(4:30 am here now - i am heading to bed.)

mfikes17:03:49

@escherize: Take it easy. Congrats on CLJS Fiddle!

cmcfarlen18:03:33

I'm having a performance issue with syntax quote/unquote. Any reason why something like this is slow?

(let [i 42] `[(test {:a [{:a ~i :stuck_out_tongue: 3}]})])

dnolen18:03:28

@cmcfarlen: splicing expands into a series of concatenations

dnolen18:03:45

you shouldn’t be putting that in a tight loop or anything

cmcfarlen18:03:31

But its "pinwheel the browser until it dies" slow. Context is an om next transaction.

mfikes18:03:54

@cmcfarlen: Try building with :static-fns true

dnolen18:03:21

@cmcfarlen: Safari has a known long outstanding bug with nested invokes

dnolen18:03:48

not going to do anything about it thought as there is the workaround that @mfikes has mentioned

dnolen18:03:59

it doesn’t affect production builds

cmcfarlen18:03:06

Ah, ok. That makes sense. I'll try the workaround. Thanks for the info!

cmcfarlen18:03:45

wow, its dramatically faster in chrome.

mfikes18:03:07

@cmcfarlen: Hmm. Chrome? That’s interesting. Your expression is definitely harsh in JavaScriptCore w/o :static-fns true but instant with:

$ planck
cljs.user=> (time (let [i 42] `[(test {:a [{:a ~i 1 3}]})]))
"Elapsed time: 10806.000000 msecs"
[(cljs.core/test {:a [{1 3, :a 42}]})]
$ planck -s
cljs.user=> (time (let [i 42] `[(test {:a [{:a ~i 1 3}]})]))
"Elapsed time: 1.000000 msecs"
[(cljs.core/test {:a [{1 3, :a 42}]})]

cmcfarlen18:03:42

yeah, I was just noticing the same thing. Is there a downside to just running :static-fns true? I think I'll switch to using list and '

mfikes18:03:50

David Nolen gave this explanation a while back: > It's an option mostly because of REPL development to allow for redefinition. For example if :static-fns true we statically dispatch to specific fn arities—but what if you redef to a different set of arities? What if you change the var to store a deftype instance that implements IFn. That kind of thing. > So for compilation :static-fns can nearly always be true, but for the REPL it's not desirable.

cmcfarlen18:03:55

Oh, that would def be an issue for me. thansk