Fork me on GitHub

Hello all, I'm running cljs tests (using @olical great ) and when I load namespaces that require Expo code which is using ES6 module import I get “Uncaught SyntaxError: Unexpected String”. I'm not expert of js but how can I tell cljs test runners to not error when some of the modules use ES6? Has anyone run tests successfully against Expo? I see there is for JS but I have no idea how to integrate it with cljs


By default, cljs-test-runner executes your code within your local nodejs instance, so I guess that doesn't support the ES6 syntax? (I have no idea, I'm not keeping up with JavaScript features 😬) It's not ideal, but maybe you could try running your dependencies through babel or whatever to compile the unsupported syntax out? Might be worth asking the expo people if they've ever dealt with anything similar. I'd hope they'd provide a version that used require syntax but maybe not.


ES6 modules are not supported in Node.js jet. You have to transpile them to require() form.


Ahhh it makes sense but I have no idea how to transpile them as part of a test pipeline 😞


Thanks for your reply, but I'm still stuck


is it safe to (cljs.reader/read-string x) when x is the output of (with-out-str (cljs.pprint/pprint data)) (assuming data does not contain JS objects and other un-serializable values)?

Dustin Getz13:11:26

i think you want (and


is there a sane way to get bootstrap 4's js on the page and bundled into a cljs project? just something to simply skip requiring it from a cdn (but not as complex as using react bootstrap components)


@joshkh use it as a foreign library

Yehonathan Sharvit14:11:29

In Clojurescript, it is possible to make a type callable as a function (like keywords and maps) by extending the IFn protocol simply like this:

(extend-type js/String
    ([s coll]
     (get coll (str s)))))
Is it also possible in Clojure?


@U09K620SG FWIW you also need to implement applyTo there if you want apply to work

Yehonathan Sharvit14:11:49

Thanks @U09K620SG and @bronsa clojure.lang.IFn is an interface and not a protocol. So we can extend IFn with deftype but not with extend-type.

user=> (extend-type java.lang.String
  #_=>   clojure.lang.IFn
  #_=>   (-invoke
  #_=>     ([s coll]
  #_=>      (get coll s))))
Evaluation error (IllegalArgumentException) at clojure.core/extend (core_deftype.clj:784).
interface clojure.lang.IFn is not a protocol

Yehonathan Sharvit14:11:21

what’s the difference between protocols and interfaces?

Dustin Getz14:11:40

TIL, i thought protocols were interfaces

Yehonathan Sharvit14:11:30

@bronsa can you illuminate us regarding interfaces vs. protocols?


protocols are backed by interfaces


each protocol has a matching interface


when you implement a protocol inline in a deftype, that interface is implemented


when you extend an existing type to a protocol, the implementation is added to a runtime virtual dispatch table


when you invoke a protocol method, clojure first checks the type for direct implementation of the interface, then looks into this dispatch table


there's various caches and optimizations but that's an impl detail

Yehonathan Sharvit14:11:16

Thanks Why IFn is not a protocol?




IFn needs to exist before protocol exist


+ protocols make use of IFn in their implementation


so it would be circular

Yehonathan Sharvit14:11:28

somehow in cljs it works


it's not impossible to make IFn a protocol in clojure, but it would require a significant reimplementation of clojure


well cljs is a different beast than clojure


the runtime is different, has different limitations and strenghts


and most importantly, cljs was designed with protocols at the bottom


clojure wasn't


protocols came to clojure years after the original implementation

Yehonathan Sharvit14:11:18

Any idea why records are not functions in Clojure and ClojureScript?


it's by design, not a limitation


no idea, ask in #clojure-dev


I suspect because records are still considered lower level than maps, and you might want to define invoke as a different operation than get


but that's just my guess

Yehonathan Sharvit14:11:26

Why do you think records are considered lower level than maps?


that's what they were designed for, to be a lower-level, faster, interoppy alternative to maps


maybe lower-level is not the appropriate word here


but I don't know how else to express it

Yehonathan Sharvit15:11:01

what about “less generic” than maps?

Yehonathan Sharvit16:11:45

@bronsa in Clojure, we can read a record like this (read-string "#user.Person{:firstname 1, :lastname avc, :age 3}") Is there something similar availailable in cljs?

Yehonathan Sharvit16:11:04

I tried this in cljs ( "#my.playground.Person{:firstname Dave, :lastname Smith, :age 42}")

Yehonathan Sharvit16:11:21

And I got: “No reader function for tag my.playground.Person.”


it couldn't work


or rather, it could only work in self-hosted cljs


actually, hmm, not sure that is true

Yehonathan Sharvit16:11:25

I am interested in self-hosted cljs


give me 10 minutes to think about it, I forgot the details of how this works in cljs


ok sorry, what I was talking about earlier relates to a different thing than what you're asking


i.e. in clojurescript source code you can't have #my.record[1] inlined, as the record exists at cljs runtime while the reader is executing in the clojure environment at cljs compile-time


as to why you can't have (read-string "#my.record[1]"), it looks like I simply forgot to implement that part when porting over from the clj impl


can you make a ticket in the tools reader jira?

Yehonathan Sharvit16:11:20

I’m in another call for the moment

Yehonathan Sharvit16:11:27

Will get back to you in an hour or so


not for existing types


not JS primitive types


I even think you may be able to make it work, but strongly discouraged as potential to definitely break stuff

Yehonathan Sharvit14:11:25

I know that it is dangerous but it seems to work with JS strings


the potential issue is that some JS libraries will type dispatch on .call property to distinguish fns


and that'll lead to a read head scratcher if that check comes before string check


anyways - unless this is for some kind of toy - not recommended

Yehonathan Sharvit14:11:24

it is for a toy (I mean a talk)


then put red flag on that


it's not a feature

Yehonathan Sharvit14:11:10

Any idea why records are not functions in Clojure and ClojureScript?

Yehonathan Sharvit14:11:44

I mean with a map you can have ({:a 1} :a) but now with a record


very nice

👏 4

@viebel huh, I didn't know that, probably Clojure JIRA has some information, it must have come up before

Yehonathan Sharvit15:11:03

OK. I wrote a blog post (2 years ago) “records are wacky maps” based on a talk by Michał Marczy

Yehonathan Sharvit15:11:10

But it’s only today (2 years later) that I am asking myself the “why” question :thinking_face:


can only speculate - but I would still consider records to be a performance construct, I personally almost never use them


(:a record) is an optimized case


so perhaps IFn omission was to discourage using them if maps suffice

Dustin Getz15:11:45

Given spec and Cognitect guidance to prefer maps of namespaced keywords from many namespaces, is defrecord legacy at this point?


If I needed a map that did more than usual map like things, I'd probably start with defrecord, rather than extending the map


But I never really need to personally


It's like an object with the convenience of a getter/setter interface of a map

Dustin Getz15:11:28

multimethod + map seems to beat defrecord + protocol in the happy path



Dustin Getz15:11:52

no, flexibility and power


That's my pref

Yehonathan Sharvit15:11:20

but for simple use cases “defrecord + protocol” are more easy to grasp For instance, you don’t have to explicitly mention that the behavior depends on the type of the first argument

Yehonathan Sharvit15:11:47

I mean code written with “defrecord + protocol” will be easier to understand

Dustin Getz15:11:26

That's not immediately obviously true to me, i will need to think on that, thanks


I would disagree with any claims of readability and records


Clojure kind of bucks the legacy notion - nothing is going away - if it’s useful - use it


Halo I just discovered macchiato and am using cljs to make a node.js server. i would also like to have my clojurescript application compile to a separate .js file from the server.js ...


is there a way to write out such a way in the project.clj to get 2 separate js files from the /src/... dir?


okay, it looks like modules are a thing...


@sova that is not what modules are for. you basically want 2 different builds. one for the lcient and one for the server


Aha. So it is! okay I have one.. :target :nodejs ... what's the defacto? :target :???


and the correct answer was, delete that line when not node.js ^_^


So how do I ask lein to build my build named :client ?


argh, I just spent 30 minutes finding out why str/starts-with? didn’t work with my regex… solution: it doesn’t accept a regex at all (why not actually?)

Alex Miller (Clojure team)19:11:36

you can use the existing re- functions for that

Alex Miller (Clojure team)19:11:24

(re-find #"^foo" "foobar")


yeah, it’s easy to forget in cljs:

(str/starts-with? "" #"https?://") ;; false, no error


in Clojure you get a cast exception (from JVM)


in ClojureScript we just defer to goog.string which doesn’t do any validation of any kind


yeah, it all makes sense


someone should write a spec for it 😉


I am trying to use web workers in my project and I get this error The key :target at (:cljsbuild :builds 1 :compiler) has a non-conforming value: :webworker. It should satisfy #{:nodejs} I have [org.clojure/clojurescript "1.10.238"] and [figwheel "0.5.17"] [figwheel-sidecar "0.5.17"] cljs builds work fine, I get this error when I try to start repl programatically by figwheel-sidecar.repl-api/start-figwheel!


the error seems pretty specific. you have a :target :webworker in your compiler config, but that's not valid


yeah, but its valid since ClojureScript “1.10.238”


what are all the options for clojurescript on the server via node?


I noticed that you're in macchiato channel. That's only framework I know of. You can also use reitit routing library that allows you to generate swagger doc and have input validation using spec: It is not perfect, but people working on macchiato and reitit react pretty quickly on issues and pull requests 🙂


@sova I've only used it for quick scripts thus far rather than a full project, but I've had good luck with lumo (installable via npm undre lumo-cljs, which can both run cljs directly via its embedded node and be used to run a compile script if you want to run in an existing node project (or different version than that embedded in lumo)


@sova clojure is one option 😛


Cool. I'm very happy using cljs on the clientside but now that I want to have some sort of minimal cross talk and persistence i'm trying to keep it all looking like cljs ^_^


and yeah you can just use clojure itself + the regular compiler these days with pretty good results


joking aside, cljs ecosystem is not as mature as clojure for server side stuff, at least that's my view for experience both, which has been very little time


lumo just saves you some overhead waiting for the jvm to initialize and whatnot


yeah the server machine i'm using it'd be much nicer to do an npm deploy because it doesn't need many resources to get started


i'm frustrated by this new term "serverless" that is just a lie


serverless is just moving the complexity from one place to another


more complex from what I have seen


yeah I am very skeptical. people like it because it seems like less complexity but it adds more complexity the same way microservices do once you have to deal with every single thing happening over a network boundary


it's very much more on the easy side of the scale, than the simpler side


there are some frameworks that ameliorate this but I also don't like the fact that it couples you to a proprietary service without a universal protocol


it's super easy to author a Node.js AWS Lambda in the browser very quickly


but yeah, things like integration testing, developing locally, performance testing, etc. become a pain because your code is complected with the environment it gets run in