Fork me on GitHub
Josh Horwitz00:03:21

Hey All, coming back to ClojureScript. What is the best way to get started now? Looking for good book/videos

Garrett Hopper02:03:48

When trying to use cljs.loader, the compiler knows the namespace exists, but then it starts trying to look for it in my main.out directory. Any ideas?

Compiling ClojureScript...
• main.js
         java.util.concurrent.ThreadPoolExecutor$  624
          java.util.concurrent.ThreadPoolExecutor.runWorker 1149
                        clojure.core/binding-conveyor-fn/fn                     core.clj: 2022
                              adzerk.boot-cljs/compile-1/fn                boot_cljs.clj:  160
                                   adzerk.boot-cljs/compile                boot_cljs.clj:   72
                                          boot.pod/call-in*                      pod.clj:  413
org.projectodd.shimdandy.impl.ClojureRuntimeShimImpl.invoke  102
org.projectodd.shimdandy.impl.ClojureRuntimeShimImpl.invoke  109
                                          boot.pod/call-in*                      pod.clj:  410
                                      boot.pod/eval-fn-call                      pod.clj:  359
                                         clojure.core/apply                     core.clj:  657
                         adzerk.boot-cljs.impl/compile-cljs                     impl.clj:  154
                                                   api.clj:  205
                                         cljs.closure/build                  closure.clj: 2775
                               cljs.closure/compile-sources                  closure.clj:  979
                                         clojure.core/doall                     core.clj: 3140
                                         clojure.core/dorun                     core.clj: 3134
                                          clojure.core/next                     core.clj:   64
                       cljs.closure/compile-sources/iter/fn                  closure.clj:  983
                                          cljs.closure/fn/G                  closure.clj:  511
                                            cljs.closure/fn                  closure.clj:  648
                              cljs.closure/compile-from-jar                  closure.clj:  624
                                  cljs.closure/compile-file                  closure.clj:  558
                                 cljs.compiler/compile-file                compiler.cljc: 1523
                              cljs.compiler/compile-file/fn                compiler.cljc: 1563 The file /data/prs/boot/cache/tmp/data/prs/dev/amazon/2x0/-tgmalg/main.out/cljs/loader.cljs does not exist.
   clojure.lang.ExceptionInfo: The file /data/prs/boot/cache/tmp/data/prs/dev/amazon/2x0/-tgmalg/main.out/cljs/loader.cljs does not exist.
    from: :boot-cljs
   clojure.lang.ExceptionInfo: The file /data/prs/boot/cache/tmp/data/prs/dev/amazon/2x0/-tgmalg/main.out/cljs/loader.cljs does not exist.
    line: 287

Garrett Hopper03:03:37

Hmm, it seems like it was the clojurescript version I was on (`1.10.126`). I'm back on 1.9.946 now, and that isn't the problem, though I'm running into a possible google closure bug now?

Uncaught TypeError: Cannot read property 'EvaluateCodeEvent' of undefined
    at goog.module.ModuleLoader.evaluateCode_ (:3000/main.out/goog/module/moduleloader.js:228)
    at goog.module.ModuleLoader.handleSuccess_ (:3000/main.out/goog/module/moduleloader.js:256)
    at (eventtarget.js:284)
    at (eventtarget.js:381)
    at (eventtarget.js:196)
    at (:3000/main.out/goog/net/bulkloader.js:168)
    at (:3000/main.out/goog/net/bulkloader.js:138)
    at (:3000/main.out/goog/net/bulkloader.js:118)
    at (eventtarget.js:284)
    at (eventtarget.js:381)


I need a way to turn Hiccup into HTML Dom nodes. Is reagent the way to go, or is there a separate library?


reagent will do it just fine


@qqq you can also use the html function, and use Google closure turning a string into a Dom element. No need to use reagent just for that I think.


yeah this, I think I have a vanilla javascript solution somewhere


I did it like this, using functions from goog.dom

(defn node-from-data
  (gdom/safeHtmlToNode (legacy/safeHtmlFromString (html data))))

(defn set-html
  ([data] (set-html data nil))
  ([data parent-id] (set-html data parent-id true))
  ([data parent-id remove-childs] (set-html data parent-id remove-childs nil))
  ([data parent-id remove-childs place-at]
   (let [new-node (node-from-data data)
         node-id (.-id new-node)
         current-node (if (nil? node-id) nil (ensure-element node-id))]
     (if current-node
       (gdom/replaceNode new-node current-node)
       (if-let [parent (ensure-element parent-id)]
           (if remove-childs (gdom/removeChildren parent))
           (if place-at
             (gdom/insertChildAt parent new-node place-at)
             (gdom/append parent new-node)))
         (log (str "could not place html: " data " on parent: " parent-id)))))))


first implementation of cljs (411 lines), and Rich's org-mode document rambling about motivations, state of the project, and its future


it’s a fun read


Anyone have a snippet in cljs for detecting ios version?


@danielstockton Is your code running in Safari on iOS, or is it in a React Native app?


Safari @mfikes. I've loosely translated from JavaScript in the end:

(def ios-version
  (if (.test #"iP(hone|od|ad)" js/navigator.platform)
    (let [[_ ma mi pa] (.match js/navigator.appVersion #"OS (\d+)_(\d+)_?(\d+)?")]
      [(js/parseInt ma) (js/parseInt mi) (js/parseInt (or pa 0))])))


I was reading through the cljs.analyzer ns some recently and I noticed there are 2 similar parse mutlimethod implementations to parse an ns form, one for ns and one for ns*. * * This implementation is rather lengthy and I was surprised to see it duplicated (or close?). Is one still around for historic reasons or are they both used and both have a reason to be maintained separately?


@mikerod If I understand correctly, the ns* variant was added to cater to the slightly different needs of top level (require ...) being in a ClojureScript file.


@mfikes interesting, I haven’t looked at them close enough to see the difference I guess. I was getting a bit confused doing a search earlier because I kept searching in the 2 different impl’s and the code all looked the same, but line numbers were diff (of course). hah


Perhaps a refactoring could share the common aspects.


yeah, it’d seem so


Hi guys; I’m on a mission to convince some engineers to consider clojurescript as their front-end mainstay for complex apps. I’ve been using it for >2 years and have most certainly sipped the coolaid. I’m having a hard time looking back at the Triassic period and making reasonable, non-arrogant-sounding arguments against other solutions. Has anyone successfully convinced an org to consider the cljs ecosystem? If so, how? Could you link to any discussions, blogs, presentations, etc. that proved helpful? I’ve done about a week of digging and have found a few good pieces that really help prove my point, but the more the merrier.


with es6/7/8 and the typescript stuff is a hard sell these days 😉


if you are already using clojure in the backend I guess it will be a lot easier


JS/ES6/ES20** and some framework like meteor/angular/ember/vue feels so archaic. If you move up to a react/mithril approach, you get slightly better with something like flux/redux, except now you also want an immutable js implementation, which in my own head is basically writing in a new language that kind of looks like js. perhaps the most valid counterpoint is something like typescript, but even here you’re only introducing types… which (without getting into a huge type debate) isn’t really solving the real problem in client-side js (immutability/state management).


I think the primary users of cljs are clojure users (duh?)


@lwhorton yeah, clojurescript is like immutablejs with lodash and much more but in a more consistent and idiomatic package


that might be a pitch 😉, why use lodash and immutablejs when there is cljs?


i’ve considered re-implementing the excellent re-frame library in js, which is a very well thought out flavor of redux-- minus the boilerplate, explosion of nouns, performance problems, and constant churn. but that comes with a whole lot of baggage as well… like the fact that you still need immutability in a language that doesn’t support immutability.


lodash and immutablejs don't even play well together


@devicesfor good point. at one point I was looking at modi, which is an exposed js API to cljs’s immutable structures… it more or less exactly matches the cljs api wrt conj assoc merge map/filter/reduce etc. But if you’re going so far as to commit 100% to an api that is non native JS, why not just use a proper transpiled language?


My main arguments would be: 1) Google Closure - code splitting and dead code elimination are still ahead of webpack (don't know about typescript) 2) I get a lot done with just the core language (rich functional primitives, immutable data structures, core.async...). I'd have to pull in a load of dependencies in js land.


it seems silly in the end to say: lets use babel, webpack, some es6 transpilation, es2017 future-feature transpilation, plugins for live reloading, tree-shaking, n-number of necessary libraries (promises, async/await, collection mutators), an immutability library, maybe a reactive programming plug like rxjs/cyclejs, and a cumbersome/heavy rendering framework, some boilerplate-ridden state management framework, etc. all of that just to get to “the state of usable javascript”


where as @danielstockton mentions; lein, fig, google closure, an http client library, maybe re-frame, and everything else is native to the language.


Exactly. lein new figwheel myproject and you're done with live reloading


^ this is the problem I’m bumping into over and over when trying to argue against the latest and greatest in the JS world: none of it makes any sense compared to cljs (at least in my head).


cljs is also more concise though, less lines of code


@lwhorton performance might be an issue, for ex: code size


well not an issue, something they can use against you


performance from a kb-down-the-wire standpoint?


yes, and execution


the other issue might interop, writing extern files


I wonder- does anyone have a real-world example where the cljs runtime is meaningfully harmful to performance?


extern inference is not mature enought yet I hear


in my experience, when you’re in the browser the only place performance matters is touching the dom while rendering… everything else is an order of magnitude faster


if you need external libs that is


I think the code size argument only works for non-complex, tiny apps. Code size is likely smaller for complex apps, where you can take advantage of dead code elimination and minimal dependencies.


@lwhorton on mobile, network and size matters


I also consider om/fulcro/qlkit to be state of the art frameworks for complex apps. I wouldn't know how to easily recreate that in js. Graphql/relay isn't really it.


how important that is to your app its another matter


I agree with @danielstockton wrt code size: jquery alone is 29k gzipped, and a minimal cljs app is 23k.. but once you start adding libraries cljs scales much better than linearly, while a js impl scales at-least linearly.


for example, immutable js is 16k… so just to have a bare-bones usable environment with native JS + immutable, you’re only 7k more than the fully feature cljs language


@lwhorton ok, what about using third party libs?


i think the biggest pain point is external integration with js libs.


you have to be ready to maintain extern files, ex: keep them update with upstream


that being said, you can completely avoid the issue of externs or cljsjs by using this macro library… (looking for it on gh)


If you want to convince a javascript team to use clojurescript, you really should set up a shadow-cljs project and forget about cljsjs and externs and all that.


@lwhorton I think you are thinking of cljs-oops


i only cursorily looked into shadow-cljs, given my preference to boot/lein. do you have experience with it?


It’s what I use. I don’t like lein because it is too magic and when something goes wrong it is hard to fix. shadow-cljs is more explicit. But if you need to use a lein plugin--and you probably will--shadow-cljs plays nice with lein too. The biggest thing for me is that shadow-cljs lets you resolve npm modules exactly like you would if you were writing javascript, including modular libraries like material-ui that allow you to include parts of the library independently. It also has a bunch of fixes to externs inference and just seems to work most of the time.


I’ve seen reports of teams switching to shadow and seeing significantly smaller code size, though it wasn’t clear why.


thanks for this. i’ll have to give it a more detailed investigation.


be sure to hop into #shadow-cljs if you have issues


or questions for that matter. @U05224H0W can probably do a more comprehensive job of explaining all the optimizations he’s put in and he’s very interested and responsive in understanding how and why people use it. my biggest point is that shadow feels much more sane and much lower friction for the javascript->clojurescript transition


have you used boot at all? how does it compare in your opinion?


When I first started, I used boot. I stopped because people were basically like, “use figwheel” and it was easier to get going with lein. Boot is a little confusing because it’s not only a replacement for lein, but it is also a replacement for certain lein plugins. I didn’t really give it a fair shot. I highly suspect that if you have complex builds and need to do a bunch of custom stuff, boot is more robust and easier to understand.


i used boot for quite some time and I think ultimately they missed the mark


they wrote an immutable abstraction layer on top of a mutable file system, which in practice is great for a single self contained jvm… but in reality there is a very high cognitive overhead. while you are allowed to “write your build system as a program, not a config file”, doing so is a struggle


if i haven’t touched the build process for a couple weeks, then need to go make a change, it takes me a good while to jump back into how the whole immutable system works


what was wrong with makefiles anyway 🙂


from a client-side perspective, the whole ecosystem is what’s wrong with old build systems. transpile *-> javascript, transpile style->css, template->html, assets->optimized


I do still use make as essentially a CLI tool, though


externs is the most mature way


manual externs


externs is going to scare the crap out of javascript people. “I mean have to mess with this janky poorly documented header file to import a js library?”


I wonder why no one has created something to convert typescript externs to for clojurescript, they have a big active community

Josh Horwitz17:03:59

Is anyone using Fulcro at all? The documentation is one of the best I have ever seen, but I don't know much more than that


I looked at fulcro from a distance a little while ago. the problem for me is that I don’t want a full-stack front client and server solution


i think it’s much more reasonable to have a consistent cljs client from project to project, but server side requirements change too frequently for me to buy into a whole ecosystem like that.

Josh Horwitz17:03:21

I can see that, I wasn't aware it was full stack


yea.. for example if I wanted to write a fault tolerant distributed system in elixir… i’m no longer in the safe-confines of fulcro but have to come up with two new systems to use

Josh Horwitz17:03:43

what would you use for the frontend?


if I were a dictator it would be cljs + re-frame + reagent


by far the most well-thought out front end “framework”: extremely performant, declarative via data, extensible, middleware layer, single source of truth, easily coordinate complex workflows

Josh Horwitz22:03:01

I couldn't find any good walkthrough tutorials for reframe


honestly the best resource is the README, and if you use github’s history I think the original readme’s were even better (but more opinionated and “sassy”, so they changed them)


but eric normand has a whole series on learning it: (paid and unpaid stuff in there)

Josh Horwitz01:03:00

Great, thanks alot


like a way to get leverage all those ts externs, that way cljs would get all that work for free


I've created quite a few cljsjs packages, and i found it pretty easy. That being said, there are only a handful of libs i use regularly (charts, google maps). I find it doesn't take too long to write my own libraries for other things (e.g. datepickers) in cljs, and I end up with something better than combining 100 badly written js libraries and trying to customize them to my needs.


having worked on a 2+ year project in cljs with quite a few cljsjs dependencies… it just stinks all around


Just use shadow-cljs, you can use any NPM dep with it, no externs necessary. And thheller is super responsive


^ exactly that @danielstockton… give me a day to rewrite some half-working js library in cljs, and in the end it will save time and integration pain


There’s just no reason to use them. With shadow-cljs you just install stuff with npm and maintain a package.json. Externs inference works well or you can use cljs-oops.


oh, just saw you already mentioned shadow-cljs


Great minds. 🙂


I feel like shadow-cljs doesn’t get enough credit so I’m happy when other people recommend it.


FWIW, I moved to a new position and talked about CLJS, Dead Code Elimination, sane tooling etc. to my CTO — but before that, I shared a few Rich’s talks, and he caught the bug from those — he justs wants a system that is easy to reason about, and the current Node codebase is a huge ball of mud. So if we end up picking up CLJS, it is going to be for the systemic effects it has, rather than the syntax/libraries etc.


^ which talks did you show her? most definitely “simple made easy”, but was there anything else in particular that got you buy-in?


Simple made easy — and I think he went on a binge 🙂


He also finds Lisp beautiful, which is not a common think — we will have to do a lot of pursuading within the team about this 🙂


It’s hard to describe how messy can a “simple” web app written in Node/Express/Mongo can be.


(I went to this company partly to help them untangle the mess)


i’m in a similar situation-- not a product company but a consulting service that is looking for help standardizing on an effective, useful front-end stack


I’m mostly talking about back-end so far — which is quite easier to sell as you have a lot of ways to gradually convert, whereas frontend will have to be a major rewrite.


true.. client side apps are quite painful to split and bridge because they’re essentially one system not separated by network boundaries or queues


A problem I've seen against adoption is getting people to change their editing habits. They instinctively want to open a file in their usual editor and start editing in their normal way. It can really pay off to introduce the advantages of structural editing, CIDER, etc..


When they're inserting parens by hand and spacing to indent things, it's harder to get them to see the real benefits.


100% ACK. I've been wanting to do an intro video about this... With Cursive


Wait, I’m inserting parens by hand, and correct indentation by spaces a lot of times — I don’t find it that cumbersome…


that’s another good point, i’ll add it to my list


I've seen people really struggle with the editing, and I'm watching them get frustrated before I've had chance to show them anything.


ok, so the biggest blocker is interop


Perhaps that's an overstatement, but I've definitely had cases where I can totally see why they don't consider the syntax an advantage, rather than just different - and i think it is.


To convince people to learn an unfamiliar sytax, convincing them of the advantages of said syntax can be important.


i agree. I think “its homoiconic, how cool!” is not a really compelling argument.


and the intricacies of lisp-1 vs lisp-2, macros, structural editing, etc. are really only things you appreciate after quite some familiarity.


I think those are the two main fears: 1) less widespread adoption (hiring, help, libraries) and 2) weird syntax and editing experience


In my opinion, using words like homoiconic and talking about macros misses the point. The uniform syntax of lisp means that you can always refactor code in a way that is not really possible in a language like javascript.


I don't have a really convincing argument to 1), other than that I think most libraries are overated and clojure hires are smarter 😛


It's easy to dismiss though


For me, that’s why I like clojurescript. When you start to have hundreds of lines of ugly repetitive crap, you know that you can fix it in any lisp-based langauge.

Jacob Haag17:03:52

Hello everyone, quick question, does anybody have any recommendation as to how to use the 'fs' phantomjs module in a cljsfile? I have been looking into the :foreign-libs option in cljsbuild but to no avail


^^ example 😉


perfect timing


Meta: perhaps there should be an “evangelism” channel? I’m sure a lot of people would like to bounce around ideas on this…


Who must we ping? @seancorfield?


@orestis You rang, sir? 🙂


appears in a puff of smoke 🙂


We have #community-development which is probably appropriate for that.


(it was originally created to discuss what we should all do in the case of the Slack shutting down large communities but it really is broader than that)


OK, your call — I’d think that #evangelism would be a more apt title for this discussion FWIW 🙂 It might help with discoverability a bit more.


As in, you might want to sell Clojure to your company but it will take some time until your coworkers become a proper member of the community.


The "channel details" for #community-development say "community growth & support" and evangelism fits into that...


it will get delete anyway 😛


One interesting datapoint is that I believe that the second most popular language that people are coming from is JavaScript


Even a couple of years ago that wasn’t close to being true


So I think the JS fatigue effect is quite real


Which is the first one? Just curious.


Oh, cool. Then I'm part of the stereotype, makes sense.


I’ve long believed that we don’t need to cater to JS beyond exposing the ecosystem


And I believe that’s a big value proposition given how complex JS is now


I thought the first one would be clojure


Clojure people use ClojureScript it’s not an interesting datapoint


Hasn’t been for a few years now


If including jQuery + a JS file in your page was 1x, using CLJS was 2x. But these days, even with helpers like create-react-app, yarn, etc, using JS is about 4x, while CLJS has remained at 2x.


All those JS state-management strategies are reduced to just using an atom (for example).


And immutable by default erases all that confusion between normal JS and Immutable JS (etc).


I also think the modular thing only sounds good in theory


For most users, monolith a la Closure is just less hassle


Core.async erases all that promise complexity.


except that core.async also eats your exceptions… it’s almost great 🙂


check out fullcontact/full.async


Yea. Not helpful unless libraries use it unfortunately.


But yes, that’s what I’m talking about.


With CLJS, you learn about four things, and then you watch the JS world re-invent them every other month.


@dnolen what modular thing? code splitting?


is core.async with a react wrapper even a good idea?


No I mean JS unhealthy obsession with modularity / pluggabilty


It doesn’t actually add up to gain


Just a lot of pain


@lee.justin.m Maybe so, but my use is so lightweight I just don’t have the issue anymore.


@devicesfor I use it as an event loop. Components take a channel, send events on it. The events are processed, returning a new state.


@devicesfor No “wrapping” if I understand you correctly.


I mean using both core.async and something like reagent at the same time


Oh. I don’t know. I use a single atom for state and a multi-method to process events. Rum (and Quiescent before that).


A long time ago I didn’t like the fact that you could have State all over the place in reagent and never looked back. I’m sure I don’t have a fair view of it.


maybe you mean something else, but it is really nice to be able to download high quality react libraries and have them work. given that there are about 6 flavors of javascript in the wild, it is kind of incredible that it does work. i’d say that’s a big gain


Regardless, for me, anyway, the more I can get away with just the base language, the better. (Well, + core.async.)


what promise complexity were you talking about @zentrope? callback-hell?


we're erasing that with a promise-monad which works out very nicely... and is another argument in support of a lisp - the "do" transformation used to give a clean syntax is a macro


I think I know what he means, promise rejections do not compose well because they are not data. IMHO that is the main reason for using channels for async (sorry if I misunderstood, just wanted to vent this out 😄)


@mccraigmccraig I’ve not spent enough time with them, but I’ve used “fetch”, say, and it’s hard to just get a value out of it in a synchronous way. Hard to debug.


@lee.justin.m pluggability is different from writing a la carte useful things


React just demonstrates that functional programming is a good idea - but we already know that


@mccraigmccraig I also get the impression that promises are just an attempt to paste-over the need for actual threads. do.this().then().then().then().


@zentrope if you were using a thread for that then you would be blocking, which would be rather a waste


if you are actually using the .then() methods on promises though then that's certainly not a very nice way to program with them


promises are an attempt to paste over the need for callbacks. callbacks are an attempt to paste over the need for threads


Weren’t threads invented to solve the issues related to kpoll eventing style stuff?


The biggest problem I’ve seen in threads aren’t blocking, but shared-state.


Not every app is a 10k web server.




well, it's true promises paste over callbacks, but they also give you a value to pass around, which is very powerful - it enables promise composition


and once you realise that promises form a monad then you are laughing


All that aside, a pattern I’ve noticed over the years, esp. in Java Culture, is that practically every new thing is an antidote to the previous poison: but it’s rare that folks think about maybe not taking poison in the first place.


you can have your async code, with error handling, short-circuit evaluation and composition in a sync-link syntax


@mccraigmccraig It might be I’ve just never had the need for it in my super-simple get-data-put-in-database apps.


on the backend that's true (although my current app is all async on the backend too and it's working out very nicely)... but in js you are forced to do everything async, so it's worth figuring out reasonable ways to deal with it


clojure and clojurescript have the tools for it though


This may give you a hints as to why: It sure is nice never to have to think about concurrency in javascript.


have a look at this for an example of a nice way of programming with promises in clojure/script


I’d love to try to use that library but man the docs are dense. I don’t give a s** about category theory and I suspect most working programmers don’t either.


That article confirms that it’s shared, mutable state that’s the issue, not threads, no?


that article may provide insight as to why eich kept it simple


Oh, I don’t challenge his choices.


But I do think there’s a bit of religion about “async all the things” that is kinda fundamentalist.


maybe i miss the point: browsers implement the model and it’s not going to change anytime soon so how do i write code today to deal with that


Wouldn’t it be cool if you could just write your code with one step after another, then let the runtime figure out how to execute it in chunks?


people have been working on that research project longer than i’ve been alive


Ah, I get you.


So, to summarize, for the browser apps I write, just about every action (coming from the server or initiated by the user) results in an update to “State”, which then causes a re-render. With core.async, there is no callback issue (all callbacks just drop an event in a channel), so the need for promises isn’t there for me. Thus, to me, promises seem complex in the amount of ceremony.


For error handling:


(when-let [event (<! ch)] (try (process event) (catch :default e (process {:event :error :e e})))


Throw in some more data in the error case (such as the original message), and … praps I’m naive. :)


i'm an "async all the blocking things" fundamentalist @zentrope 🙉


Heh. Well, enjoy!


@dnolen Ah ok. I don’t just quite get what you mean by pluggability.


@richiardiandrea That’s interesting: I’d love to understand what you mean. The one thing I miss about javascript is a language-level promises because they have a clearly defined error channel and work as expected with uncaught exceptions.


then-chaining can be annoying but async/await is the same syntax as go blocks, but with the caveat that exception have better behavior in js


I personally prefer to compose data and identify errors with functions, like passing back error maps like:

{:error {:msg "message"}}
It gives me more flexibility and I am not tied to a mechanism that may or may not suit me. Also promises can pass back any data for errors but it is not considered good practice. Having said it is always case by case and I try to understand first if it's worth adding the channel complication or not to my code path. Sometimes it does sometimes I use promises. It depends.


Okay I think I understand your point. I think mine is slightly different: I’m coming at this from a debugging and tooling perspective. If you or a library writer screw something up and fail to catch an exception or miss an error condition, you are likely at least get something with promises. Not necessarily so with channels, which require careful error handling on the “put” side and an ad hoc convention (e.g. dnolan’s <? operator) for error channels.


Maybe libraries shouldn’t use channels?


or maybe the go macro could catch exceptions and the <? semantics are the default take behavior. i know this isn’t going to happen but it seems to me that it would make channels behave more congruently with exceptions


Hm. I see that you can create a channel with an exception handler.


My point is exactly the opposite of that, I rarely want to throw exceptions except at the very boundaries


so I try to avoid Promises as much as possible in the "business logic" part, if complicated enough to justify channels


“want” isn’t the point. if you fail to realize that, say, json.parse throws an exception, the resulting behavior is bad. see e.g.


(and sorry if that sounds aggressive or pokey. i didn’t mean it that way)


and to be clear: I LOVE channels, I’m just annoyed that the way to use them seems to be “just always write correct code or else you’ll get a severed stacktrace in the middle of a blizzard of gensyms”. i want them to be great and also easy for dumb programmers like me to use


I’m bolting a cljs project onto a javascript codebase. Can I setup the cljs compiler to access the npm dependencies in the javascript project? would symlinking their package.json and copying the deps i need (and versions ) into the :npm-deps key be a good way to go?


@escherize if I understand the problem correctly, you'd just need to duplicate the :npm-deps from the ones in package.json and add :install-deps false


@escherize my opinion is that shadow-cljs will be better for this. it already uses the package.json to do npm resolution


@richiardiandrea thanks for a quick response — but will those deps be loaded twice? (the js app loads the cljs code from the index.html, so i’m afraid would they both package their own (identical) deps?


@escherize isn't require idempotent?


@lee.justin.m thanks for responding too! I’ll take a closer look at shadow-cljs.


sorry for answering with a question 😄 I think you should not have that problem


@escherize I think the way to do what you want is to use the :npm-module target with shadow and then just use it as a library. You should hop into #shadow-cljs if you have issues.

Garrett Hopper19:03:17

Does it make sense to use code-splits with html5 async script tags? I'm not sure if it provides any benefit, and it doesn't work without :optimizations :advanced, since document.write can't be used in async scripts.


:advanced doesn't use document.write, only :none does.

Garrett Hopper19:03:48

Yeah, it doesn't work wirhout :advanced.

Garrett Hopper19:03:59

Which is fine. I suppose I could have separate dev and prod index pages.


shadow-cljs has an option for makes <script async ..> work in :none but default CLJS does not

Garrett Hopper19:03:05

I'll have to look into that. Thanks


:async-require wasn't properly documented but I just added a section in case you are interested.


@lee.justin.m I have a project I used a lot of core-async, I agree the vanila things miss important stuff (important in the sense that I see to always require then to use it effectively, but I do it mostly on cljs, so maybe it's something about that). well, adding the <? is very good, but not enough, another one that seals the deal is the (go-catch), that's a go block that will re-throw exceptions, this way you can work very much like in a promises world


so, had you tried using that?