Fork me on GitHub
#clojurescript
<
2015-08-10
>
paradoxquine00:08:43

anyone here used figwheel for daily development on a 10kloc or larger application? If so, how did the process scale (still < 0.25s per change? was caching assets/sourcemaps an issue? any gotchas that came up?) thanks!

lucien.knechtli00:08:11

what do I need to do in order for (.indexOf col x) not to give me this: Uncaught TypeError: col.indexOf is not a function? I'm guessing it has something to do with name-mangling when the javascript is compiled?

lucien.knechtli00:08:26

col being normal vector

clumsyjedi00:08:36

maybe (.indexOf (clj->js col) x)

lucien.knechtli00:08:55

hm thanks. works in repl but not my code. i probably shouldn't be using a vector here anyways

dnolen01:08:18

@lucien.knechtli: indexOf isn’t a method on vectors

dnolen01:08:59

@paradoxquine: far as I know Figwheel is incremental so compile time just depends on the size of the file you are working on

lucien.knechtli01:08:58

yea, bad use of vectors anyways... What type should I be using if I want an ordered set of objects that I can insert / remove items from by index or value-match (which doesn't really matter)? sorted-map with index values as a key? The set will never be very large, and will usually be iterated over in order unless inserting/deleting.

paradoxquine01:08:58

that would be excellent. i read/saw it does minimal change calculation but don’t know enough yet to be confident in how that plays out if you have, say, an om component that depends on 20 helper files, or a helper that is used in 20 components. I recall bruce mentioned there was a core advantage in the way google closure’s dependency system works vs javascript 2015 modules/commonjs modules/etc, but not sure if that would make the aforementioned use-cases still blazingly fast

nullptr03:08:31

stumbled across this while searching for something else and smiled https://news.ycombinator.com/item?id=3639726

nullptr03:08:45

"ClojureScript compiler being written in Clojure is a huge disadvantage…”

dnolen12:08:31

@nullptr wow that’s old, nice find!

andrewboltachev12:08:25

Hi. How do I install "cljs.jar standalone jar", so that I would be able to run "java -cp cljs.jar..." ?

andrewboltachev12:08:55

ah, I just need to make it avaliable in PATH

agile_geek12:08:30

if you run java -cp <path to cljs.jar>

agile_geek12:08:56

you are explictly specifying the location of cljs.jar

agile_geek12:08:19

Obviously u need java installed and on your path

agile_geek12:08:06

-cp is classpath switch to tell java where to find archive files

rohit12:08:45

@dnolen: the work you’ve been doing is just great. clojurescript using jsdoc to be used by the closure compiler is awesome. optional type checking using a mature tool. a big win, imho. Q: what is your stance on jsdoc type documentation for the core lib?

agile_geek12:08:05

@dnolen: I love your comment about good for demo’s only…it’s like when I revisit architectures/applications I worked on 5-6 years ago, I’ve always moved on so much.

dnolen12:08:37

@rohit: if you’ve looked at core.typed at all you’ll know that Closure type annotations are far too weak to properly type many common fns. So I don’t see much value there.

dnolen12:08:31

@agile_geek: haha, I think most of my points are still somewhat valid if you’re talking about the web - ClojureScript was entirely focused on the web 3 1/2 years ago. good Node.js integration, React, React Native, JavaScriptCore integration, comprehensive source mapping support - none of these things existed then.

rohit12:08:41

@dnolen: thanks!

agile_geek12:08:18

@dnolen: agree wholeheartedly. I look at message-driven architectures i designed 10+ years ago and think about how conceptually they are still valid but tools like Kafka have moved them on so much in that time.

slipset12:08:19

So the other day, I thought about getting planck to do some of the same, but I realized that osascript and javascriptcore are not the same.

slipset12:08:03

But I still think it would be super-cool if one could hook into osacript from planck, allthough I have no idea how to achieve it.

dnolen12:08:03

@rohit: I think the type annotation support is for developers who are OK with trading less expressive variants of the core fns for compile time checking. nullability tracking is a big win in this regard. Also I think bridging pre/post conditions into type annotations would be a big win.

dnolen12:08:43

@rohit: so given we cannot capture all of ClojureScript semantics, we have to settle for simple type checking.

dnolen12:08:06

but I’m strong believer than anything that helps catches errors is always a win, regardless of the form

dnolen12:08:27

pre/post conditions, schema things, tests, generative tests, property tests, simple compile time checking

dnolen12:08:33

all these things lead to be better programs.

rohit12:08:09

@dnolen: i agree. again thanks for all your hard work!

rohit12:08:23

really enpowering clojurescript developers

andrewboltachev12:08:35

If I would need to convert .cljs to .js from Clojure, should I use https://github.com/bhauman/clojurescript-build , or there's some built-in thing?

dnolen12:08:36

@rohit: something I’ve been pondering which I think is not in the Closure Compiler authors minds yet is making Closure Compiler an extensible type checker.

dnolen12:08:12

so maybe in the long run could get custom annotations & analysis to capture more of ClojureScript’s semantics

bhauman12:08:35

@andrewboltachev: you should really look at the Quick Start for ClojureScript. https://github.com/clojure/clojurescript/wiki/Quick-Start

andrewboltachev12:08:54

thanks bhauman! simple_smile

rohit12:08:26

@dnolen: that’ll be great. i am reading through ‘closure the definitive guide’. its really illuminating.

monjohn13:08:33

I am porting a JS game to cljs and have a question. I have a vector of “bullets” and a vector of “enemies.” I need to iterate over both vectors, testing if there is an collision, if so, remove the both items from their respective vectors. The Javascript code has nested for-loops and then just mutates global state to remove the items by their indexes. What function or functions should I use to accomplish this?

profil13:08:51

@monjohn: for can take several vectors and will run with all "permutations" of the vectors

profil14:08:46

@monjohn: (for [bullet bullets enemy enemies] (check-collision bullet enemy))

angusiguess14:08:46

You could filter over the resulting tuples and then pull the 'dead' stuff out of your game state.

bensu14:08:38

@monjohn: do you have an id for the enemies and bullets? Is the order important in how you process them? It might be better to use maps to model them instead of vectors.

monjohn14:08:01

I looked at for. Since it runs over all permutations, wouldn’t that multiply the number of enemies and/or bullets?

angusiguess14:08:18

It would give you the pair of coords for each enemy and each bullet.

angusiguess14:08:22

Which you could then test.

angusiguess14:08:35

Since two for-loops nested essentially does the same thing it should perform similarly.

monjohn14:08:48

@bensu: I don’t have ids for them. And the order doesn’t matter.

angusiguess14:08:57

@monjohn: The part where you test wouldn't happen in render logic.

bensu14:08:16

@monjohn: consider using ids and maps then since there is no upside to using vectors. when removing the enemies, if you have an id you can use dissoc with it. if you have a vector, you only have the position as a reference, and with each enemy you remove, the rest of the positions change. it is now your job to track them

monjohn14:08:31

@bensu: that makes a lot of sense

bensu14:08:06

@monjohn: also, using for and expanding into enemies x bullets and then filtering it is straightforward and good advice, but not necessary. Reconsider the approach if that part seems to be a performance bottleneck

monjohn14:08:31

It took me some typing the on repl but I see how it do it now. Thanks for the input @bensu @angusiguess @profil

amacdougall14:08:51

This weekend, I realized I didn't have a good answer to a really common need. Let's say I have a fairly complex JSON-decoded object consisting of mixed vectors and maps. Something like this:

{:user "Alan"
 :library {:albums [{:name "Excellent Music"
                     :artist "Jane Smith"
                     :tracks [{:name "Intro"
                               :length 1.2}
                              {:name "First Actual Song"
                               :length 3.9}]}
                    {:name "Also Pretty Decent Music"
                     :artist "Bill Jones"
                     :tracks [{:name "I'm Sad About Love"
                               :length 4.35}
                              {:name "Love: Pretty Sad, Guys"
                               :length 5.0}]}]}}
Let's say I want to let a user look up tracks and edit their names. It's easy to walk the tree to get to a specific track node, but then I'm not sure of the best way to apply that change to the entire structure. Since there are vectors, assoc-in and update-in don't do the job. I experimented with making a custom zipper, which comes close to working, but it's a serious hassle. Is there a well-known solution for this kind of problem? You'd think it would be pretty common, especially in CLJS apps.

amacdougall14:08:22

(Obviously my first thought was cursors, since if I had an Om component representing one of those tracks, it would be obvious to say (om/transact! track #(assoc % :name new-name)). But actually generating the cursor during the lookup operation is a hassle; nice thing about a zipper, if you zip/next your way to a matching node, then zip/edit, you can theoretically zip/root to get the entire changed structure. On the other hand, that was one of the bugs I couldn't solve...)

bensu14:08:41

datascript?

dnolen14:08:57

@amacdougall: have you looked at Specter - https://github.com/nathanmarz/specter

amacdougall14:08:43

Oh whoa, that could be just what I need! I'll try it out later today. Thanks for the guidepost!

shamatov14:08:58

Hello everyone

greywolve14:08:32

@dnolen: thanks for sharing, that looks great

cfleming15:08:14

@dnolen @rohit: I’m also excited to be able to offer better completion etc in Cursive with the annotations

timgilbert15:08:22

@amacdougall: don’t know if it helps, but you can use an index into a vector as a key in (update-in) or (assoc-in): (assoc-in data [:library :albums 1 :tracks 2] :name “Title”)

darwin15:08:06

ah, now I see, you tried already, anyways the article is pretty good

dnolen15:08:41

@cfleming: cool! simple_smile

cfleming15:08:29

@bhauman: I hadn’t seen that, no, thanks

cfleming15:08:17

@bhauman: I suspect that can be more easily done with the URL handler, but I don’t know the details. How much can that be customised in figwheel?

bhauman15:08:41

@cfleming: I'm happy to add something if you need it. I'm unfamiliar with the URL handler.

cfleming15:08:27

@bhauman: How are the links generated? Can that be customised? It seems like in OSX you can use an idea:// link, but I’m not sure if that’s cross platform or not. There’s also a plugin that seems to help that can use http:// links.

bhauman15:08:14

@cfleming: I'm really not on the same page as you right now. Not understanding what you are invoking with the link. Currently figwheel is just shelling out to a script with a file and a line number.

cfleming15:08:28

Actually, recent IntelliJ versions can use http:// with no plugin, like: http://localhost:63342/api/file/relative/to/module/root/path/to/file.kt:100:34

cfleming15:08:03

@bhauman: If you can make the filenames clickable links in that format, IntelliJ will open them (it listens on an internal server)

bhauman15:08:36

@cfleming: oh yeah gotcha!

bhauman15:08:08

@cfleming: well I could make that configurable.

cfleming15:08:23

That would be great!

cfleming15:08:36

Although low priority, since it seems like there’s already a workaround.

Petrus Theron16:08:35

Having a hard time with live reloading cljs websockets: Error during WebSocket handshake: Unexpected response code: 414

Petrus Theron16:08:01

OSX Firewall is off. I tried upgrading to ClojureScript 1.7.48 and Boot 2.1.2. Same issue.

Petrus Theron16:08:09

414 Request-URI Too Long. Hmm, maybe too many cookies...

Petrus Theron16:08:54

Upgrading Chrome seems to have solved it simple_smile

amacdougall16:08:16

@darwin: the thing about zippers is that they don't natively support a mix of sequences and maps. You have to supply custom functions to them, which requires a deeper understanding of just how they do their stuff—see http://stackoverflow.com/a/12503049 for the general approach I tried, but note that I had to include a little bit of http://stackoverflow.com/questions/15013458/clojure-zipper-of-nested-maps-repressing-a-trie to get it to work on my data structure.

amacdougall16:08:19

@bhauman: I asked you about Figwheel over WSS on Twitter a while ago. I finally had time to get it working! I had to use nginx to reverse-proxy from an SSL endpoint (e.g. http://local.example.com:443) to <ws://localhost:3449>. It wasn't hard in any absolute sense; it just took a lot of fumbling around, and help from a friendly sysadmin.

jackjames16:08:54

i've also found that a bit tricky. is this a reasonable approach?: https://www.refheap.com/108050

bhauman17:08:09

@amacdougall: very cool, proxying seems like a requirement here. For local dev there is tunnels https://github.com/jugyo/tunnels

bhauman17:08:38

actually that might not work, haven't tried it.

dottedmag18:08:32

Is there any online reference for Closure library? https://google.github.io/closure-library/api/ looks broken

dottedmag18:08:30

Uhm, scratch that, broken only in Chrome for me.

dottedmag18:08:15

Weird, broken by "Nice alert" extension. How is it related at all?

nullptr18:08:06

this can also be useful depending on what you’re doing https://google.github.io/closure-library/source/closure/goog/demos/

paradoxquine18:08:38

@dottedmag: I would bet that extension injects some not-very-careful code into pages simple_smile most chrome extensions that i’ve seen do, and break on crazy things like a div with a classname they weren’t expecting

bhauman18:08:18

@dottedmag: http://www.closurecheatsheet.com/ is a great birds eye view for some important parts

bhauman18:08:11

@nullptr: those demos are great reference for the UI parts thanks for that!

dottedmag18:08:00

paradoxquine: This time it is dossier.js which chokes on the code injected by the extension

dottedmag18:08:10

bhauman: Thank you.

timgilbert19:08:48

Hi all, can someone tell me how to determine whether an object I’ve got was created by a specific (defrecord) call in ClojureScript?

timgilbert19:08:06

Was trying to use (instance?) but it doesn’t seem to be working

potetm19:08:41

@timgilbert: record?

potetm19:08:31

Ah oh wait. specific record. Retract last statement.

potetm19:08:20

instance? appears to work for me.

potetm19:08:51

(defrecord Testing [])
=> user.Testing
(instance? Testing (->Testing))
=> true
(defrecord Testing123 [])
=> user.Testing123
(instance? Testing (->Testing123))
=> false

timgilbert19:08:35

Hmm, yeah, that does seem to work, thanks

pixel19:08:50

hey, novice question: I have a reagent project where I'm using LESS as a CSS preprocessor for static styles. Currently, I'm running lein less auto in a separate process. However, I don't like this, and I don't like committing both the .less files and the .css files (for deployment).

pixel19:08:20

I can't quite figure out how to add lein less to figwheel for dev, or to uberjar for deployment..

mfikes19:08:28

@martinklepsch: Sweet! Now declare works in REPLs in master. (David took are of it here https://github.com/clojure/clojurescript/commit/5800cfba697c8c261d8a3ff4c22a49fb749a827b)

dnolen19:08:00

@mfikes: yeah I honestly couldn’t remember why we didn’t emit declares. I think I may have disabled it while figuring out how DCE worked a couple of years ago.

dnolen19:08:06

far as I can tell, declares have no effect on DCE.

mfikes19:08:32

@dnolen: I’m happy it works now simple_smile

dnolen19:08:54

yeah, it’s nice

mfikes19:08:04

@dnolen: Hey, we don’t have unit tests yet for bootstrapped, right?

dnolen19:08:33

@mfikes: we do src/test/self/self_host/test.cljs

dnolen19:08:55

there’s a separate test script runner now script/test-self-host

mfikes19:08:10

@dnolen: Cool. I’ll give it a shot and document it on the Wiki. Planck’s tests are failing with ClojureScript master, so I figure I’d start with bootstrapped unit tests.

lvh19:08:16

What does Clojurescript use to find Clojure namespaces to require macros from? E.g., if I have:

Caused by: clojure.lang.ExceptionInfo: Could not locate crunch/test_macros__init.class or crunch/test_macros.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. {:tag :cljs/analysis-error}
	at clojure.core$ex_info.invoke(core.clj:4593)
	at cljs.analyzer$error.invoke(analyzer.cljc:525)
	at cljs.analyzer$analyze.invoke(analyzer.cljc:2548)
	at cljs.compiler$compile_file_STAR_$fn__3060.invoke(compiler.cljc:1120)
	at cljs.compiler$with_core_cljs.invoke(compiler.cljc:1048)
	at cljs.compiler$compile_file_STAR_.invoke(compiler.cljc:1071)
	at cljs.compiler$compile_file$fn__3101.invoke(compiler.cljc:1232)
	... 38 more
Caused by: java.io.FileNotFoundException: Could not locate crunch/test_macros__init.class or crunch/test_macros.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.
… and I have test/crunch/test_macros.clj, which source path is missing?

mfikes19:08:35

@lvh it ultimately uses the Java classpath

lvh19:08:23

Okay, that’s what I thought. lein classpath has the absolute path for test/crunch on it first, though

dnolen19:08:19

@lvh: that won’t work

dnolen19:08:30

you need test not test/crunch

martinklepsch19:08:18

@pixel: chaining multiple build steps is generally challenging with leiningen. I'd recommend checking out boot which covers this use case better imo

pixel19:08:12

It's a one off so I'm going to just stick with current situation, but in the future I'll look into boot

martinklepsch19:08:14

@pixel: I made a template "tenzing" that could help getting started.

martinklepsch19:08:54

Yeah, I was thinking that this is probably not the answer you were looking for but well :)

pixel20:08:15

figwheel just does too much 😛

martinklepsch20:08:18

@mfikes: @dnolen nice stuff regarding the declare emit

mfikes20:08:46

@martinklepsch: And, I already checked, meta works with declare simple_smile

martinklepsch20:08:04

@pixel: boot tooling can cover most of the ground that figwheel covers (just for the record :))

martinklepsch20:08:34

@mfikes: haha yeah, I figured that out in the meantime :)

martinklepsch20:08:35

Still embarrassed by trying to get meta from the symbol, something I've been stumbling upon before 🙈

shaunlebron20:08:40

@dnolen: about to make an issue on figwheel about possibly replacing cljsbuild with the quick start’s build scripts. would you give some reasons for avoiding cljsbuild? I’ve seen you alluding to them here briefly

lvh20:08:34

@dnolen: Thanks, that fixed it. Little confused as to why the default source path would be so broken, but hey, it works simple_smile

dnolen20:08:46

@shaunlebron: the main issue is just that cljsbuild isn’t actively maintained and hasn’t kept up like other tooling has w/ the various ClojureScript changes

dnolen20:08:03

I’m a bit loathe to say not to use it for the simple fact that nearly everyone does

lvh20:08:22

shaunlebron: I think that’d be a cool contribution; I think a lot of people just use it because it’s there and that’s what the template did, so

bhauman20:08:39

@shaunlebron: fighwheel barely uses cljsbuild anymore just the config expectations, It's been on my list to remove the absolute dependency. But people still use it. And its helpful for folks getting started to say do an advanced compile.

shaunlebron20:08:50

@bhauman: oh neat, I guess the main benefit here is to have that all the build configuration in the project.clj, looks like you are also supporting builds to be under the :figwheel key in project.clj instead of :cljsbuild

shaunlebron20:08:31

alright, I’ll leave this issue alone since most of the work has been done

bhauman20:08:25

Yep I am supporting builds under the :figwheel key,

shaunlebron20:08:41

I thought there was something inherently wrong with cljsbuild since we’re basically required to use the quick start build scripts when reporting cljs bugs

bhauman20:08:02

Please go ahead and file the issue.

bhauman20:08:28

I will also take a pr for the build scripts in the template.

shaunlebron20:08:52

wonder how we could share config between the build scripts and figwheel

shaunlebron20:08:04

I’ll file the issue

afhammad21:08:33

hmm seems like you guys are discussing something related

bensu22:08:45

@shaunlebron: I've been thinking about this for a while. Even though I'm very irritated with cljsbuild I don't think that discarding lein completely is a good idea. Why add extra config edn files when we already have a project.clj?

bensu22:08:28

Your comment prompted me to write this very simple plugin (right now) https://github.com/bensu/lein-cljs

bensu22:08:27

It's an experiment to see if we can use the modern cljs compiler from lein without much indirection.

bensu22:08:31

If it turns out to be a good idea (and we find a better name!) we could use it as a starting point for new tooling.

bensu22:08:11

@dnolen: I've joked before that implementing cljsbuild would take 5 lines, well, it took 15 including with assertions simple_smile

dnolen22:08:42

@bensu: hey cool! simple_smile

bensu22:08:07

we should find a better name though.

bensu22:08:45

It claims a lot of undeserved territory.

nullptr22:08:56

cljsbuild2

bhagany23:08:02

cljsbuild-next

cfleming23:08:15

cljsbuild++

cfleming23:08:03

Or perhaps we should just start with cljsbuild+ and that way we have some room to improve.

bensu23:08:05

@cfleming: hahaha.

bensu23:08:36

it's going to be used from the command line (if used at all). we should keep it short.

bensu23:08:44

my last plugin is called doo

bensu23:08:11

@cfleming: that is brilliant

kidpollo23:08:16

cljsbuild-me

cfleming23:08:21

My work here is done

bensu23:08:40

thanks. I'm seriously going with that

cfleming23:08:05

Haha, I can’t be held responsible for the consequences

bensu23:08:07

if inspiration hits you with a tagline, please comeback and enlighten us.

cfleming23:08:51

Actually, “I can’t be held responsible for the consequences” is actually a pretty good tagline for a build tool.

bensu23:08:15

or for C++

bensu23:08:06

quick unrelated note, I'm thinking of publishing that small blogpost. where should I do that, any Clojure things besides the mailing list?

cfleming23:08:00

I’m not sure, Planet Clojure perhaps? And twitter, of course.

cfleming23:08:33

I’m not exactly Mr Social Media, so I’m probably not the best one to ask.

cfleming23:08:09

Fortunately between the ML and here, you’ll get most people in the community I think. Although I guess for an article like that you’d probably like it spread further than just people who are already converts.

bensu23:08:03

I'm not going for reach, just feedback. I didn't know about Planet Clojure (really don't understand how...)

bhauman23:08:52

@bensu I like this a lot. lein-cljs isn't a bad name at all.

bhauman23:08:11

What I would like to see is a set of example scripts and tutorials that guide people on how to create their own build tools. A cookbook of build scripts that include precompilers, less etc.

bhauman23:08:49

It's not that hard. its just opaque.

bhagany23:08:23

@bhauman: I feel like I would benefit a ton from this.

bhauman23:08:46

@bensu: the clojure reddit is good as well

bhauman23:08:30

@bhagany: I would as well. Lots of folks want a build chain that triggers reload, etc.

bhauman23:08:26

it doesn't need to be explicit. A pattern and a set of examples works fine.

bhauman23:08:57

@bensu there could be some merit in standardizing cljs build config outside of lein in a way that is universal to tooling. A clojurescript-builds.edn file could be just the ticket. A convention that everyone expects and understands.