Fork me on GitHub

Is there a way to have a source file available for (load) from a different ns, but not searched for via the clojurescript compiler directly (but only evaluated when so loaded from something else being compiled)? Context: I have a bunch of shared code which can be built against two different libraries, with two different namespaces providing the same API. My solution to this was to put this code into -shared.cljc and (load "-shared.cljc") from a different namespace requiring each upstream library. In the ClojureScript world which -- while being ugly -- works fine to be able to backend into both compatible Clojure libraries. However, cljsbuild is trying to compile the -shared.cljc on its own, which it isn't designed to do.


...a way to achieve the same end without being quite so evil would be similarly welcome.


...well. As an immediate workaround. renaming the file to, and using load-file rather than load.


...which doesn't actually work. Hrm. I'm at a bit of a loss as to how to get compile-time textual inclusions to work in ClojureScript.


@tcarls there’s no reliable way to do that - and unlikely to be


@stbgz What do you mean by "non-spa template for Luminus"? Luminus is a template 🙂 If you want to, I imagine you can use it for non-spa sites also, just don't add reagent or anything like that.


lein new luminus foobar +site maybe?


Do any of David Nolen's talks compare om/ to re-frame directly?


I suppose I could tag him.. @dnolen


I don’t think a talk like this exists @ibarrick


@ibarrick not aware of anything, but isn’t really similar to anything else I’m aware of in ClojureScript


Well from a surface level reading, and reagent are both ways to "use react" in ClojureScript. While not directly comparable, perhaps some sort of dedicated breakdown of the differences in how applications tend to be structured when approaching a problem in versus doing the same in something like re-frame/reagent might be helpful


I know they both use react. And my understanding was that they both (re-frame and store the application state altogether in a single atom/ratom. At first glance (not having written code in either) they both use the idea of single app state that flows down into components and changes travel back up the tree somehow. I was just looking for an easy way to see what the material differences were without getting my hands dirty 😆


@ibarrick reagent uses a ratom (reactive atom) style model. It tracks when you deref an atom and will update a component when that atom changes. Om is more explicit. You send information to a component via params, if the params you send are different the component is re-rendered.


The way the "ratom" dependency tracking is done works 99% of the time, but I've hit some rather nasty bugs with it from time to time.


I aslo recommend looking at Reframe as it covers over some of the more ugly aspects of reagent.


The new version of Om.Next and Reframe are rather comparable in goals but they do have a distinct difference. Om.Next wants you to declare up-front the data your component needs. With Reframe you just take the data out of the global state and it does the tracking for you. So it's the age-old question of "do we be explicit with data deps, or implicit".


In my view, reagent is absolutely reliable, although there are a few gotchas


I also find it rather non-magical


I think I like the idea of explicit deps. I work on a very large Ember app and the pain of trying to guess why components aren't rerendering when they should and rendering when they shouldn't isn't something I want to repeat.


I suspect persistent data structures mean that even with re-frame there wouldn't be as many gotchas though


Thanks for the input!


@ibarrick, @tbaldridge, I've just published a blog post covering some of the gotchas people encounter with Reagent:


Is there any reason not to use extend-type with native JS types in library code?


something like (extend-type js/HTMLCanvasElement ....)


I’m feeling the JS fear of having library code that did things like Object.prototype.myCoolThing = …


@scaturr it’s usually ok in application code - but not something you should ever do in a library you intend to publish


Thank you! Would specify! on a specific instance be acceptable?


Or a better alternative?


still questionable in a published library


I don’t know what you mean by alternative


Likely my understanding that is flawed 🙂 - But I thought of specify! as reify but on a specific instance of something. Like I might be able to create a canvas element that supports a given protocol, and it would not affect other canvas elements.


Maybe hide behind a factory function of some sort (defn make-canvas [] (specify! (.createElement js/document “canvas”) ....)


I just don’t know what you are asking


library code or in your application?


library code


would that specify! example be bad to publish for others to use?


no not a good idea


I also don’t see what benefit you would be getting out of it anyhow over just regular functions that work on a canvas type


esp. if you just going to do deal with an individual instance - just write normal code then


Yeah 🙂 Probably going a little overboard here. Thanks a lot @dnolen - I appreciate the responses a ton


Still getting my legs here


consider protocols a special case


first write some functions, and then decide later if protocols provide some additional abstraction you might need


based on experience, usually the answer is no - you don’t need them


that is extremely helpful


for example - when I might consider protocols


if I was writing some kind of generic rendering abstraction - where canvas was only one possible type


and 3D Canvas, or SVG might be other possible implementations


if you’re not doing that then don’t bother


That makes sense. I think I was trying to mangle a protocol for use as syntactic sugar


heh, yeah not intended for that - it’s for abstraction and they aren’t free - there’s a small perf hit over regular functions


thanks again, i appreciate the help and all you’re doing here


...okay, taken as given that there isn't likely to be a reliable way to do textual inclusions into a ClojureScript file, but I'd like to understand why that's the case -- my understanding of the compilation model was that macros (evaluated as regular Clojure) could modify the source arbitrary using anything available to Clojure-on-the-JVM, so I'm unclear on why functions pulled in via a macro running something like ( (slurp "")) don't have JavaScript generated for them; it feels like my understanding of the compilation model is missing something big.


Just curious @dnolen, you’re advising against using extend-type in library code because it has global effects on the JS environment, is that right?


Cool, thanks


@tcarls it just introduces more complications than it’s worth - no deep reason


and you can write your own macro for inlining source if you really need it


real I/O ops for this don’t make sense since I/O in JS is async - not true for Clojure


...but if that slurp is done in a macro, isn't it happening at compile-time in Clojure, vs ClojureScript?


yes but I already explained why non compile time isn’t going to work in the next statement


re-reading what you wrote above you may be missing something about how ClojureScript works


which is that there is no runtime component


unless you are using optional bootstrapping - no eval


nod. I don't expect eval, so I don't expect to be able to invoke a macro from figwheel. OTOH, I do expect a function whose text was generated by a macro to be available, and I'm not even seeing that. If that expectation is a wrong one, I'm trying to fix my mental model to understand why it's wrong. (OTOH, if it's a valid assumption and my code's just broken, and the "you won't be able to make that work" was because "that" is fragile, likely to break things, and just generally bad practice... well, then understanding that would avoid the headscratching in trying to bend my mental model around observed behavior).


@tcarls I think your mental model is just a little off here


if you want to load code at runtime and expect to see generated source you necessarily require eval


if you inline code via macro, eval is not necessary


rewinding a bit - nothing about figwheel prevents invoking a macro (defining a macro is a different story since it can’t be defined in ClojureScript)


@tcarls going back to what you were saying yesterday - if you use load you have written non-portable Clojure code


load absolutely necessitates the entire compiler to be present at runtime - and it isn’t in ClojureScript


if you want to write something portable - don’t use load or any other form of runtime source inclusion


everything must be declared statically in the ns form


I think what I didn't grok is that load is always runtime, vs compile-time if invoked root-level as opposed to in a function.


Hey, anyone could suggest some book on ClojureScript ? have some travelling to do, would like to have some additional material to read on Kindle


Hi, when using transit-cljs, I noticed that a lot of things from transit-js don't get removed by the closure compiler. Are things like transitMap used by transit-cljs? If not, is there a way to get it removed by the closure compiler ?


@zilvinasu Hmm books on CLJS? I can only recommend books on Clojure (The Joy of Clojure being my favorite)... are you looking for something that assumes knowledge of clojure already, or something totally from a fresh perspective?


I only saw ClojureScript: Up and Running as the cljs book available, but I personally preferred videos (either from O'Reilly or PluralSight, both were actually good) ^ but not actually solves your concern since you said material to read on Kindle.


Clojure for the Brave and True would be my suggestion.