Fork me on GitHub
#clojurescript
<
2017-05-04
>
souenzzo00:05:03

@danielcompton what if u r doing jit on build? For FB, performance matters, every CPU tick on client.

danielcompton00:05:00

Sure, I'm just wondering what the real world performance differences would be, given that the browsers do a lot of these optimisations already (in the background). I'm not saying it's bad or they shouldn't do it, I'm comparing it to what is already going on

darwin01:05:02

@danielcompton apples and oranges, browser’s JIT optimization happens on zillions of user machines again and again, prepack’s AOT optimization happens once during the build on developer’s machine - think of it as constants folding and loops unrolling on steroids - for the price of potentially increased javascript payload size

darwin01:05:32

I guess in the current form it is only effectively useable for init-heavy js apps, because it optimizes this init code path and not much further

darwin01:05:40

and it will be always a tradeoff between code size and speed, but it is promising, it will give us more options how small/fast apps we can ship

souenzzo02:05:14

Looking for libraries like this https://github.com/retrofox/is-array/blob/master/index.js (4k downloads in a day https://www.npmjs.com/package/is-array) Looks promising "resolve/evaluate" functions on build 😛

mikeb02:05:08

I know spec was recently split out from clojure, is the same true for cljs? Do we now need to include it explicitly in project.clj?

souenzzo02:05:59

Someone else using clojurescript + spec on front + JSON on back? I'm trying to exchange qualified name. My first try was user/name. On parse, just regular browser js -> js->clj -> :user/name But on write, :user/name -> "name". There is some default workaround?

souenzzo02:05:48

For now I'm using with-redefs to name full-name where (def full-name #(str (namespace %)"/"(name %))). Will do for now. Hope to get this fix in some short time 🙂

souenzzo03:05:54

Oh, bug was closed? Declined? 😐

tbaldridge03:05:56

@souenzzo Yes, because the solution would break existing code. The problem is that you're going form a higher fidelity source to a lower fidelity. So there's going to be some data loss.

tbaldridge03:05:33

But it's also a question of how to get types across JSON, for that sort of thing I suggest Transit: https://github.com/cognitect/transit-format

souenzzo14:05:52

tbaldridge: add :keywords-fn will break who's code? I understand that was transit, but golang/C/infra microservice environment. There no how impose a new format for every service... Anyway. I'll get around the way I can.

tbaldridge14:05:22

So in that case the keywords should be transformed to non-namespaced names. But that transformation is a business-level concern, and should not be part of the serialization system.

tbaldridge14:05:49

Personally I think having it throw an exception on getting namespaced keywords would have been a better option

dnavas11:05:44

Hi all. New to CLSC. What resources you recommend to get started?

dnavas11:05:23

Been playing with Haskell for 9 months (not sure if that helps) and use JS daily at work.

claudiu12:05:02

@dnavas really really liked Learning ClojureScript from packtpub

pesterhazy12:05:51

This one's good: https://github.com/magomimmo/modern-cljs. It gets advanced pretty fast though

ksmithbaylor13:05:21

@dnavas welcome! I'm in the same boat, I've been playing with Clojure and Haskell off and on for a while now. I finally started a side project with ClojureScript recently, though.

len13:05:39

Hi all. Can anyone help me to get a npm lib into a leinigen project with the new npm support ?

dnavas14:05:51

does CLSC have good WebGL support/bindings?

yiwan14:05:29

any one use macOS 10.12.4 with emacs 25.2 cider 0.15.0? does cider-jack-in working right?

ksmithbaylor14:05:10

@dnavas definitely! It's been a blast.

dnolen15:05:42

@dnavas interop with JS is trivial outside of concerns about advanced compilation - http://thi.ng has a ton of stuff around WebGL

john17:05:22

Okay, I've been investigating this a little bit. But just to put a button on it. There is simply no way for a function or macro to determine the namespace in which it was called, correct?

john17:05:40

I guess that doesn't even make sense to say, because there's a whole call stack involved

john17:05:13

Seems like there's no way around having the user supply my library the name of the namespace they want loaded by their web worker.

john17:05:02

Even though they might have specified it under :main in their compiler options.

jeffmad17:05:34

Hi all, I hope someone can help me think more intelligently about state in re-frame. We are building a SPA with a lot of forms and we argue about using local state in the component vs. putting it into the db. How do folks decide where to put state? Looking at the examples, the simple time color only uses db, but the todo mvc uses some local atoms. Consider a component that allows a user to page through a list of employees. The component gets the list of employees and the page size, but we keep the current page number as local state. There can be 3 instances of those components on the page at one time. Seems good. On the other hand, it seems that the whole point of re-frame is to keep all the state in one atom. What about a form to add a new record with 10-12 fields? Do you keep it in a local atom until it is validated and submitted to the server, and then put it in the DB? Thanks for any advice you may give. If this is not a good place to ask this kind of question, I apologize (also for the wall of text).

noisesmith17:05:00

@john at runtime the namespace isn’t especially interesting - usually it’s just user or something for the entire lifetime of the app

noisesmith17:05:37

maybe what you care about is the namespace in which the function that immediately calls your function was defined - which isn’t available

tbaldridge17:05:35

@jeffmad something to help think about the problem: what you are describing is a common question and I think maps closely to the MVC pattern. Some data belongs in the model (and hence the global database), and other data is purely about how the data is presented to the user, or view data.

tbaldridge17:05:14

I dislike local data as it's harder to test, and harder to debug, but I recognize that it's easier to store page offsets and the like locally and it's easier to manage.

noisesmith17:05:39

ratoms at namespace scope are great for this in reagent

tbaldridge17:05:53

Except then they're opaque and impossible to test

noisesmith17:05:56

where my page is defined in a namespace, and page view specific data goes in that ratom

noisesmith17:05:05

but I can populate the atom in my test

noisesmith17:05:07

it’s not that bad

noisesmith17:05:18

it’s not closed over, it’s namespaced

tbaldridge17:05:27

ah, I misread

tbaldridge17:05:41

but doesn't that keep you to having one global ratom for all your controls?

tbaldridge17:05:56

at namespace level = global

tbaldridge17:05:05

If I need two paging controls, what do I do?

noisesmith17:05:14

the global ratom is for my data, and then each namespace level - OK that’s global too - has things only that view cares about

noisesmith17:05:21

where the namespace defines some viewing state

noisesmith17:05:44

it’s not the only way to organize an app of course (reusable components go in another utility namespace)

noisesmith17:05:18

but the each page has a namespace, state of that page goes in ratom belonging to that namespace, that works pretty well for me

tbaldridge17:05:02

@jeffmad but I would say this: try to keep the components easy to test, easy to inspect, and easy to reuse.

plexus17:05:44

Would anyone be able to help this person out? They're trying to use cljs.spec, but somehow s/def is not defined. https://www.reddit.com/r/Clojure/comments/6939wb/looking_for_a_guide_or_tutorial_using_cljsspec/

john17:05:54

@noisesmith Well, you know, in the HTML file, you'll put <script type="text/javascript">require("my_ns.core");</script>... something to start things up. :main eliminates that boilerplate. But the webworker still needs something similar to launch.

jeffmad17:05:16

That makes sense @tbaldridge thank you so much for your thoughts, Tim and @noisesmith

noisesmith17:05:19

@john sure you require some namespace, that doesn’t put you in it

tbaldridge17:05:39

@john trying to do some sort of webworker framework?

plexus17:05:44

seems for some reason the functions from spec.cljs are there, but not the macros defined in spec.cljc. Any idea what could cause that? The code itself runs fine for me, so I'm guessing it's their tooling that's messing up. They're using boot+lighttable.

tbaldridge17:05:51

I assume your users are calling some function like (invoke-webworker foo 42) and you want to go find foo. If that's the case, make the api be (invoke-webworker qualified-symbol & args). Then users can do (invoke-webworker `foo 42).

john17:05:47

The worker must be launched, just like the main thread, right?...

john17:05:50

Sorry, I'm way confused, but... The worker needs similar accommodations as the main thread. It needs at a minimum a script file. I have that working (without user input)

john17:05:27

In compile mode :advanced everything works fine

john17:05:45

in :none, I need to create a shim that loads cljs_deps

john17:05:00

Which is always in the same place. fine

thheller17:05:43

so they behave the same in :none and :advanced but properly split the code so worker only code is only in the worker file

john17:05:47

But, in :none, I believe I must supply a require(namespace)

tbaldridge17:05:01

yeah, I worked on that sort of stuff before...it's not easy

noisesmith17:05:13

if you put functions in vanilla collections instead of namespaces, I think this stuff becomes much simpler

thheller17:05:13

it is easy ...

tbaldridge17:05:28

Best solution I could find was to say that you had to use :simple or :advanced to use webworkers

tbaldridge17:05:02

oh, but what @thheller is suggesting looks better, my work was back before modules were a thing in CLJS

noisesmith17:05:05

I know it feels weird to have a hashmap like {:f f :g g} but directly passing things like this around and using them for lookup avoids the complexities of trying to use namespaces

john17:05:28

@thheller your module solution is ultimately the way

john17:05:53

But would my whole framework have to depend on devtools?

thheller17:05:17

devtools is a build library .. no runtime dependencies

thheller17:05:36

ok while in dev the REPL etc .. but nothing for production builds

john17:05:36

But, would users of my library have to use devtools?

thheller17:05:12

uhm anyone that wants to build the worker has to yes. the library itself no

thheller17:05:20

CLJS proper doesn't support the :web-worker extension. so no other build tool supports it, only shadow-devtools (well and shadow-build which actually does this)

john17:05:10

hmmm... And your not doing any runtime jazz to solve, directly, the problem I was looking to solve. You simply solve it at runtime, where the user still supplies their desired launch namespace, just at compile time rather than run time. Yeah, that's what it looks like

thheller17:05:25

nope it just bundles up the generated js properly

john17:05:42

Cross module code motion is going to be clutch for this whole webworker thing

thheller17:05:57

basically really it just abuses :modules and then prepends importScripts(...) to load the dependencies

thheller17:05:47

with some more tricks to make :none work

john17:05:50

If we can transparently move around dependencies for webworkers, depending on what they call, it'll make workers performant and usable. Otherwise, at least in my lib as it is currently written, your whole app gets loaded up in every worker.

john17:05:29

Probably similar to all the tricks I've put in at runtime. All that's left is the namespace to launch

thheller17:05:30

this will still load all dependent code in the worker

john17:05:06

But because you're using modules, you should be able to leverage some code motion, right?

thheller17:05:30

code that is only ever called in the worker will be in the worker

thheller17:05:40

but whatever the worker depends on will also be loaded by it

john17:05:10

But it won't compile any non dependent code into the worker, correct?

john17:05:18

(in theory)

thheller17:05:20

so if you have :worker depends on :app it will contain app code

thheller17:05:45

but if you have a :worker depends on :common and :app depends on :common, no app code will be in the worker

thheller17:05:59

depends on how you structure the modules but yes

john17:05:57

I'd think the user would put react in :app

john17:05:04

I'm calling it screen in my lib. Might call it UI. I'm toying with the idea of pushing as much code as possible off the screen thread.

thheller17:05:07

yeah react would be moved to screen probably unless you use anything in the worker that requires anything screen related

john17:05:51

I like this screen / common / worker convention

john17:05:29

It'll be interesting to see if it actually works - the whole module / code motion with workers (and my lib) thing

noisesmith17:05:11

I still suspect that namespaces are useful within a single entity, while compiling code, but any solution for communication between entities should avoid indirection via namespaces and exchange data directly (perhaps I’m missing some nuance here though…)

john17:05:14

@noisesmith yeah, I'm not sure we're on the same page. I'm not using namespaces to make calls between entities. We only need the namespace at launch time of the worker

noisesmith17:05:50

oh, don’t mind me then - that’s just a configuration question, and not the kind of thing I was thinking of at all

noisesmith17:05:57

pardon my airheadedness

john17:05:57

lol I'm always grateful for your advice and thinking. This lib is brushing up against the limits of my capabilities and I'll need all the advice I can get.

john17:05:11

Hopefully it's interesting enough that others will get involved too

john17:05:46

Like, I could make the namespace declaration part of the API itself, like (def t (f/thread {:conf-map {:main "some.core"}})) Or I could have the user declare the :main once, at the top of some ns.. Which is better? Not sure

john17:05:47

Or make them use shadow-devtools and somehow tie that in

john18:05:34

I was close to releasing an alpha, but then I stumbled on a macro that makes everything way easier, obviating half my code base lol

john18:05:57

So going through a few refactors now

thheller18:05:17

@john namespaces do not exist at runtime in :advanced so not sure why you'd need them?

thheller18:05:03

but yeah bundling the worker properly is a build tool issue imho

john18:05:19

Yeah, it would be a shame to force a user to supply a launch namespace, when it's only necessary while not in :advanced mode

thheller18:05:42

oh it is just as necessary in :advanced mode, even more so

john18:05:41

In advanced mode, all I do is hand the single "your.js" to the worker and it works without a specified launch namespace. And I'm able to determine that at runtime using...

john18:05:30

well, I have two ways

thheller18:05:42

yeah I know the other "solutions" that exist today ...

thheller18:05:07

but having the worker-only code in the main app.js is not something I like

john18:05:14

one, just grab the last (.getElementsByTagName js/document "SCRIPT"), which may be too hacky

john18:05:44

eh, I guess that was my only method of grabbing the script name, atm

john18:05:29

Another thing I'm doing at the moment: dynamically generating the worker file as a blob at runtime. This is convenient because when the user launches the thing, we can supply initialization data a priori. I just figured that feature out, so I need to refactor. Right now, all workers launch with the same code. With this new feature, lots of message passing initialization code can be removed.

john18:05:23

I can send (and let the user send) any amount of custom launch code.

john18:05:49

So, I'm toying with the idea of splitting this out into multiple libraries. One that just provides a thread sort of functionality. Another that provides executor pool funcitonality. And a third that emulates agents

john18:05:51

And I can build agents on threads just by passing in custom launch code. I think the general pieces are falling into place.

john18:05:07

But for now I think I'm just going to put them in separate namespaces

john18:05:56

Actually, if I made the thread/agent constructor function itself a macro, then I could pull in the ns of the caller env, but then that'd be a macro... no mas

qqq19:05:06

what's a good way to write "rest of list" ? is & the universal symbol for that?

jr19:05:26

[x & xs]

dnavas19:05:16

does CLSC have an official router?

spinningtopsofdoom20:05:09

@john Have you looked into the :preloads compiler option to load the ClojureScript Dependencies you need?

spinningtopsofdoom20:05:10

When I was trying to get modules working for :none and :advanced optimizations that's the route I found to be the cleanest

john20:05:06

@spinningtopsofdoom interesting. I def hadn't considered that one. I'll look into it. Thanks!

mikethompson20:05:57

@jeffmad my advice: wherever possible absolutely keep data in app-db. BTW, there's a #re-frame channel which may provide more responses

isak21:05:13

i'm having a problem getting my profiles and builds respected in my build scripts with cljsbuild when running via cron. anyone ran into this?

isak21:05:37

using syntax like lein do clean, with-profile prod cljsbuild once foo

isak21:05:01

and it seems to ignore with-profile prod

curlyfry04:05:02

isak: Not 100% sure, but try lein with-profile prod do clean, cljsbuild once foo

isak13:05:04

I'll give that a try, thanks @U0J30HBRS