Fork me on GitHub
#clojurescript
<
2016-01-01
>
drusellers00:01:00

Are people sharing the “markup” between hiccup and sablono?

Tim00:01:28

what do you mean?

drusellers01:01:59

so, Hiccup and Sablono use the same data structures

drusellers01:01:10

i have a server page that generates the html via hiccup

drusellers01:01:33

and i’m building out a React component is the data structure is the same

drusellers01:01:46

granted there is no functionality in the React one yet

drusellers01:01:04

and I was struck that they were the same (so far) and it made me wonder if people are sharing them

drusellers01:01:24

my guess is no, because as i dig deeper into this the React one will diverge

crocket07:01:15

https://clojars.org/cljs-npm/lein-template has been refined to the point where I don't have to think much about tooling when I just want to do some nodejs programming in clojurescript.

blissdev07:01:23

is there a built in way to do UUID generation in clojurescript? or do I need to require a closure lib?

domkm07:01:29

@blissdev: (random-uuid)

blissdev07:01:40

domkm: ooh thanks!

crocket08:01:15

Is there an edn processor for clojurescript? Oh, there is https://github.com/cognitect/transit-cljs

jaen08:01:37

That's not EDN, that's transit. It's different. If you explicitly need to read EDN then use this - https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/reader.cljs#L460-L466

jaen08:01:08

Otherwise transit is probably a better choice - it's faster in the browser due to using a compact JSON encoding.

crocket08:01:41

cljs.reader/read-string reads a clojurescript object which is a superset of EDN. If I wanted to stick to strict EDN, it might cause a problem. transit-cljs looks like a better alternative although I don't know if it's good on nodejs.

crocket09:01:13

@jaen: Do you know how to prevent javascript programs from calling a two argument cljs function with one argument? npm modules written in clojurescript exposes cljs functions to plain javascript.

jaen09:01:57

IIRC cljs.reader/read-string reads just EDN as opposed to it Clojure counterpart, which can read a superset. Take a look at the dosctring for the read function above: Only supports edn (similar to clojure.edn/read).

jaen09:01:59

So no, this is EDN.

crocket09:01:18

cljs.reader/read : Reads the first object from a PushbackReader. Returns the object read. If EOF, throws if eof-is-error is true. Otherwise returns sentinel.

crocket09:01:28

cljs.reader/read-string : Reads one object from the string s

jaen09:01:44

Yes, and?

jaen09:01:58

You also omitted part of cljs.reader/read docstring.

jaen09:01:05

The one I quoted it states it reads just EDN.

jaen09:01:17

Also, if you look at cljs.reader/read-string source it just uses cljs.reader/read.

jaen09:01:26

So this is still true

jaen09:01:35

That it reads EDN, not Clojure source.

crocket09:01:06

Ok, I think clojurescript dash docset is invalid.

jaen09:01:18

Could be

jaen09:01:46

Maybe the regex they use to extract the documentation got tripped up by a double newline in it?

crocket09:01:54

What's the difference between clojure object and edn, anyway?

jaen09:01:57

In the source the line I quoted is there.

crocket09:01:39

Is there any syntactic difference?

jaen09:01:14

I don't think there is a syntactic difference, but Clojure can be made to write out EDN Clojurescript won't understand - for example

jaen09:01:36

boot.user=> (defrecord Test [a b])
boot.user.Test
boot.user=> (pr-str (Test. 1 2))
"#boot.user.Test{:a 1, :b 2}"
boot.user=> (read-string (pr-str (Test. 1 2)))
<#C053K90BR>.user.Test{:a 1, :b 2}

jaen09:01:51

Clojurescript wouldn't be able to understand such tag IIRC.

crocket09:01:53

@jaen : Have you checked out my cljs-npm template? It is a fast way to develop nodejs application and launch a cljs REPL. If you know a faster way to launch a CLJS Repl, let me know.

jaen09:01:23

I think you are able to register custom tags though - so you would be able to extend the EDN reader to read types you need, it's just not in the basic feature set (since there's now way for the library to know which types in your Clojure code would correspond to which types in your Clojurescript code).

jaen09:01:57

And one remark more - if you really don't need to use EDN for some reason (as in you are already talking to a service that understands only EDN) I would prefer to use transit

jaen09:01:42

Mainly because of the performance advantage in JS environments - EDN has a parser written in Clojurescript which runs on the Javascript VM, whereas transit due to it's JSON encoding can re-use the native code of JSON.parse.

jaen09:01:18

As you can see transit can even outperform using JSON directly - http://jsperf.com/json-vs-transit/2 - since the encoding uses only arrays, no objects.

jaen09:01:54

@crocket: as for your template - I've noticed it, but didn't look into it too much, since I do Clojurescript only in the browser and not on node. I also use boot instead of leiningen. So I don't really know if you can do better with lein.

crocket09:01:45

Without my template, you're basically stranded on nodejs. Clojurescript itself doesn't have much of nodejs tooling support.

jaen09:01:41

Yeah, that is true. Most people prefer to just write JVM Clojure if they have to do the server side, so there's little interest in making that better, I suppose.

crocket09:01:18

JVM Clojure programs consume at least 165MB which is not good for small daemons. nodejs daemons can consume a lot less memory. Plus, nodejs apps launch a lot faster, so they are better as command line apps. So, nodejs runtime is better for small programs.

jaen09:01:11

Sure, I know what advantages using Clojurescript on node can have over JVM Clojure, but it just seems that is not an issue for most Clojure users.

jaen09:01:30

Otherwise someone would be probably trying to shave that yak.

jaen09:01:39

And sure, "having Clojurescript work better with existing Javascript ecosystem is a non-goal" is also vexing to me (why am I forced to incorporate webpack into my builds?) but I guess that's the reason for that.

crocket09:01:26

Since (cljs.reader/read-string "#cljs.user.Test{:a 1, :b 2}") leads to an error, it seems cljs.reader/read-string can't read a string if a tag is not separated by a space.

jaen09:01:07

Let me check, but I think it's the case of "you have to register a handler for this tag" I mentioned before.

crocket09:01:36

Is there a syntactic difference between #tag {something} and #tag{something}?

jaen09:01:34

IIRC no.

jaen09:01:11

boot.user=> (read-string "#inst \"2016-01-01T09:34:29.957-00:00\"")
#inst "2016-01-01T09:34:29.957-00:00"
boot.user=> (read-string "#inst\"2016-01-01T09:34:29.957-00:00\"")
#inst "2016-01-01T09:34:29.957-00:00"

thheller09:01:28

@crocket the tag is just invalid EDN

thheller09:01:05

you need to implement IPrintWithWriter/-pr-write for records

jaen09:01:20

Well, it is syntactically valid EDN, it's just that it's semantically invalid unless you provide your own handler for the tag.

thheller09:01:27

no it is not valid

thheller09:01:49

a tag in EDN must be a fully qualified name as soon as it contains dots

thheller09:01:16

ie. cljs.user/Test

thheller09:01:29

clojure edn cannot read cljs.core.Test either

crocket09:01:38

Is #js{:a 1 :b 2} invalid?

jaen09:01:53

@thheller: Ok, it might be so. I don't know EDN spec by heart.

crocket09:01:21

#js{:a 1 :b 2} looks like a record because #js and {:a 1 :b 2} are not separated by a space.

thheller09:01:42

TBH just use transit, it is better in every way

thheller09:01:55

@crocket: the space is irrelevant

thheller09:01:07

#js {:a 1} works too

thheller09:01:11

doesn't matter

thheller09:01:20

the issue is in the tag

crocket09:01:39

So, is a space in #js {:a 1 :b 2} just a convention?

crocket09:01:53

Does transit-json perform better than transit-messagepack?

thheller09:01:43

never tested it but I'd stick to JSON since it is available natively just about everywhere and requires less code

thheller09:01:19

ie. if you work with a browser you don't need to ship a msgpack implementation, if there even is one for js

crocket09:01:47

I'm just curious independently of practicality.

jaen09:01:40

For Clojurescript - yes.

jaen09:01:54

Even more so - msgpack isn't implemented for Clojurescript I think.

jaen09:01:37

Also, re: tags

(defrecord Test [a b])
=> nil
(cljs.reader/register-tag-parser! "cljs.user.Test" map->Test)
=> nil
(cljs.reader/read-string "#cljs.user.Test{:a 1, :b 2}")
=> #cljs.user.Test{:a 1, :b 2}

jaen09:01:40

So like I said

jaen09:01:53

cljs.reader/read-string can parse it if you provide a proper handler.

jaen09:01:16

It just won't do it by default, since it can't know the semantics of your tags automagically.

jaen09:01:41

@thheller: so it seems it's a valid tag after all.

jaen09:01:19

I suppose msgpack transit could be more performant in JVM Clojure than JSON transit though, since it's a binary encoding, but I haven't done any benchmarks.

thheller09:01:18

@jaen you are correct, thought the tag was a bit more strict

crocket10:01:01

@jaen : If I imported an npm module via :foreign-lib, why would it still need to be on :externs?

jaen10:01:23

@crocket: I don't think it will work as you expect it to.

crocket10:01:18

I think it needs more compiler support from google closure.

crocket10:01:29

Or clojurescript compiler support.

jaen10:01:31

Yes. But there's no interest in it, sadly.

jaen10:01:53

Do you want to use it with node or the browser?

jaen10:01:13

Because if it's node, then you should just use cljs.node/require and write externs.

jaen10:01:43

:foreign-libs with :module-type won't save you from writing out externs anyway

jaen10:01:51

And will not work for npm modules as-is.

crocket10:01:52

If it's node, I can just use js/require on :simple optimization.

jaen10:01:02

Yes, exactly.

jaen10:01:30

And on the browser your best bet is to preprocess the modules out with webpack/browserify/somesuch and use as a normal, non-`:module-type` foreign lib.

crocket10:01:52

But, :advanced optimization could improve performance a lot for commonly used npm modules.

jaen10:01:20

Maybe, but GClosure can't optimise any Javascript code.

jaen10:01:25

It has to follow certain rules

crocket10:01:30

Do you use :advanced optimization on web browsers?

jaen10:01:33

Most Javascript libraries probably won't.

crocket10:01:02

If you just use :simple, you don't have to go through those hassles.

jaen10:01:03

Yeah, you basically have to - otherwise you will end up with megabytes of ouput which is prohibitive for web pages.

jaen10:01:23

With advanced optimisations you end up with hundreds of kilobytes which is acceptable.

crocket10:01:39

I think you want tighter integration with npm modules. One that doesn't require :externs or :foreign-lib.

jaen10:01:31

Preaching to the quire there, I've dabbled in that before. But like I said, there wasn't all that much interest in that.

jaen10:01:55

Using webpack/browserify/something is the current state of art.

crocket10:01:08

I made cljs-npm even if there was little to no interst because I was interested.

jaen10:01:09

And regardless of that you will have to write externs, since most Javascript libraries aren't amenable to GClosure optimisations, so you have to exclude them from that and provide externs (so the compiler knows what to not rename).

jaen10:01:02

Sure, and I made my own fork of Clojurescript compiler that could compile Clojurescript projects that included React and material-ui as they are published in npm, so?

crocket10:01:33

Publish your work and make it easy to use. Then, people will show interests.

crocket10:01:46

:extern is not easy.

jaen10:01:25

If there's no interest to mainline that, then I don't see much point in doing that to be honest '

jaen10:01:34

You can't run from externs, like I said

jaen10:01:43

If you transform the modules to GClosure code

jaen10:01:15

You won't have problems with externs

jaen10:01:43

But libraries will probably break anyway with optimisations, because Javascript world at large doesn't follow GClosure optimisation guidelines

jaen10:01:38

On the other hand you can exclude the libraries from the optimisation process by using them as foreign libraries

jaen10:01:47

But then you have to provide externs.

jaen10:01:18

There is a possibility to write some code that could analyse the foreign library and produce externs, but I don't think that avenue was explored yet.

crocket10:01:25

Is it possible for a software to analyze npm modules to extract externs?

jaen10:01:35

Sure, it could be done somehow, no idea what would be the best approach though - would parsing and analysing be good enough, or would evaluating and examining the resulting Javascript objects be required.

crocket10:01:08

So, google closure better extract extern so that GClosure advanced optimization guideline becomes useless.

thheller10:01:45

closure has support for generating externs

thheller10:01:52

but it requires closure compatible js 😉

crocket10:01:18

I'd be happier without 'but'.

thheller10:01:58

until the javascript world can decide on a standard there isn't much we can do

crocket10:01:17

The standard is going to be ES6 and npm largely.

thheller10:01:18

manual externs are probably going to be arround for a while

jaen10:01:41

As for the former issue - you could try my fork to see it in action - https://github.com/jaen/react-with-modular-cljs. It uses forked Clojurescript and reagent that work with npm React package as-is. It works great with no optimisations, but as soon as you try :advanced - React breaks.

jaen10:01:52

So that is a dead-end probably and foreign libs + externs is the way to go unfortunately.

crocket10:01:43

We're dealing with unmanaged technical complexities coming from js.

crocket10:01:02

The world was created in 7 days by the god. Javascript was created in 10 days by a human under deadline pressure.

jaen10:01:32

And wanting to do a lisp, but advertising wanted braces and Java in name ; d

crocket11:01:28

If the first web browser just embedded a scheme runtime for scripting, it could have been better.

crocket11:01:53

Scheme is probably a better compilation target than js for clojurescript.

jaen11:01:24

IIRC that was the original intention and Eich was hired with "you'll be implementing Scheme in browser".

jaen11:01:30

And then marketing happened.

crocket14:01:30

Just adding [cljsjs/nodejs-externs "1.0.4-1"] to :dependencies in project.clj enables me to include (def fs (js/require "fs")) in source code on :advanced optimization mode.

drusellers15:01:58

How do I run my HTTP application and have figwheel update my JS at the same time?

drusellers15:01:36

lein run to start the app then lein figwheel <build name> for the JS app - but figwheel goes to a different port

darwin15:01:27

@drusellers: I think you want to start figwheel client by hand and provide it with proper websocket url to your figwheel server: https://github.com/binaryage/cljs-devtools-sample/blob/master/src/figwheel/devtools_sample/figwheel.cljs#L9

drusellers15:01:47

@darwin: cool, i dig in - thank you

darwin15:01:27

and don’t use built-in figwheel server for serving my content: https://github.com/binaryage/cljs-devtools-sample/blob/master/project.clj#L20

drusellers15:01:12

ALL THE OPTIONS

drusellers15:01:46

@darwin so you have figwheel on port 7000 like the repl on some other port. It then compiles the JS files to the file system - which allows the proper application to read them and serve them.

drusellers15:01:39

@darwin: what is this profile :checkouts

darwin15:01:58

ignore checkouts for now, that is for consuming latest versions of libraries: https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#checkout-dependencies

drusellers15:01:34

still wrapping my head around the entirety of the lein project size. simple_smile

drusellers15:01:49

thank you for this focused sample. def going to clean somethings up in my own project.clj

darwin15:01:53

to answer your question, figwheel server runs on port 7000, --AFAIK compiled files are sent as sources over the web-socket channel and eval’d in js context, filesystem not involved— <- no this is wrong, files are reloaded via urls

drusellers15:01:24

so do you have to change the port you serve your app on? aka the HTTP backend?

drusellers15:01:28

mine is on 5000

drusellers15:01:32

and if figwheel is on 7000

drusellers15:01:45

i’ll need to then change my asset links to port 7000

darwin15:01:05

your content is served by your own HTTP server on port 5000

darwin15:01:32

figwheel’s server runs on port 7000, it serves no content, and provides /figwheel-ws end point for websocket channel

darwin15:01:48

your figwheel client should use only that websocket channel

darwin15:01:41

btw. this is recommended thing to do in long run, you should not use figwheel server for your content, that is there only for convenience, for people to have something to start with without messing with ring

drusellers15:01:46

ok, more denseness, figwheel client? I don’t see any ‘client’ type code when reading over - https://github.com/bhauman/lein-figwheel

drusellers15:01:52

let me study your repo a bit more

drusellers15:01:02

i imagine it will become clearer. simple_smile

darwin15:01:05

sidecar == server, support == client

darwin15:01:12

for historical reasons, I guess

darwin15:01:42

client runs alongside your javascript in your js app, when your require figwheel.client from support project

darwin15:01:24

there is also some magic how to require and start figwheel by leiningen automatically, but I don’t follow this stuff, I prefer to do that by hand myself (to understand what it does)

drusellers15:01:00

ok, i haven’t seen the require figwheel.client thing yet

drusellers15:01:12

still just barely using figwheel as a part of getting devcards stood up

darwin15:01:24

ok, then you should remove the figwheel client config magic from your project.clj

drusellers15:01:44

also, i like the way you are merging cljbuild stuffs with profiles

darwin15:01:49

because you want to do that by hand if you want to follow cljs-devtools-sample example

drusellers15:01:34

So, remove this (https://github.com/eventgonegood/app/blob/master/project.clj#L66) magic and go for a more hand crafted approach

darwin15:01:15

yes, or alternatively leave it there and learn how to instruct figwheel client to use port 7000 in that config

drusellers15:01:37

ok, i can dig into figwheel a bit more, that seems like a good idea in general

darwin15:01:53

it should be possilbe, because that config map is just a convenient way how to setup figwheel client via project.clj and let it start automagically

glenjamin15:01:11

does anyone know where the docs for the rules around deps.cljs are? Is it just every deps.cljs file found on the classpath?

glenjamin15:01:33

oh, found them

darwin16:01:41

@drusellers: btw. I’ve learned that profile merging trick just recently and it really renders leiningen+cljsbuild pretty flexible, before I wasn’t able to express many configuration needs, here is another example for inspiration: https://github.com/binaryage/chromex-sample/blob/master/project.clj

drusellers16:01:07

yeah, that’s a neat trick. i was wondering how I could “dry” that up

darwin16:01:37

I tend to combine multiple profiles via with-profile and define common combinations using aliases for easy access from command line

darwin16:01:47

just remember, for merging to work properly, the trick is to specify :cljsbuild as map of build configs, not that alternative way using a vector

darwin16:01:53

and you should include :cljsbuild {:builds {}} in “base" profile to avoid https://github.com/emezeske/lein-cljsbuild/issues/413

darwin16:01:07

in case someone uses your project.clj as a checkouts dependency

adammiller16:01:02

it appears http://clojars.org is down….Is there any other repos that mirror what’s in clojars?

mfikes17:01:59

@adammiller: I'm not aware of mirrors, but the problem is transient. See http://status.linode.com

adammiller17:01:06

Yeah it seems to be back up now.

Alex Miller (Clojure team)17:01:35

Now is a great time to support the volunteers that run Clojars https://salt.bountysource.com/teams/clojars

jindrichm19:01:09

When you profile Clojurescript using Chrome DevTools, is it normal that the garbage collector takes more than 50 % of the profiled time?

mike_ananev19:01:27

@alexmiller: Hello, Alex! I'm very interested in the results of the survey. Can you tell when results will be ready, please?

genRaiy20:01:44

FYI I made a demo for using Datomic with Hoplon that is now part of the demos project. I have just created a PR that also shows the update round trip. Uses the in-memory database for simple provisioning. So if anybody wants to get started with Datomic on Hoplon there are now a few simple examples...

genRaiy20:01:47

They demonstrate the use of the Castra RPC library (so look for castra-datomic-*)

genRaiy20:01:40

@leolaporte: is it a fake account or are you really checking this out? What has prompted the interest?

drusellers20:01:35

How are people writing their main functions for launching CLJS/OM “apps” - for instance I have at least 3 different “root” applications - is just conditionally “launching” them based on dom nodes the current practice? ala https://gist.github.com/drusellers/27cbd0c22217930fde27

jindrichm21:01:12

I think I've just stumbled upon http://dev.clojure.org/jira/browse/CLJS-1444. Is there a work-around?

orther21:01:39

Does anyone suggest any reading on how to deal with exception in CLJS?

orther21:01:19

I see the exception handling wiki page on the clojurescript github repo but I'm curious if there is a common strategy to handling exceptions.

dnolen22:01:09

@orther try/catch is the standard way in Clojure(Script)

dnolen22:01:22

@drusellers: there’s an #C06DT2YSY channel