This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-04-08
Channels
- # announcements (8)
- # aws (2)
- # babashka (11)
- # babashka-sci-dev (39)
- # beginners (62)
- # calva (5)
- # cider (1)
- # clj-kondo (50)
- # cljdoc (2)
- # cljs-dev (6)
- # clojure (52)
- # clojure-austin (22)
- # clojure-czech (13)
- # clojure-europe (88)
- # clojure-nl (1)
- # clojure-norway (5)
- # clojure-uk (6)
- # clojuredesign-podcast (13)
- # clojurescript (45)
- # community-development (3)
- # core-typed (31)
- # cursive (12)
- # datahike (2)
- # datalevin (7)
- # datomic (5)
- # events (1)
- # exercism (11)
- # fulcro (27)
- # gratitude (1)
- # holy-lambda (3)
- # hoplon (2)
- # introduce-yourself (2)
- # jobs (1)
- # lambdaisland (3)
- # lsp (110)
- # malli (2)
- # meander (4)
- # music (2)
- # off-topic (50)
- # overtone (1)
- # pathom (13)
- # polylith (26)
- # re-frame (4)
- # releases (2)
- # rewrite-clj (3)
- # ring (12)
- # shadow-cljs (20)
- # specter (4)
- # tools-deps (8)
- # xtdb (40)
Hi! I'm trying to use npm module nodemailer. I expect I'm making some basic errors, and would really appreciate a steer from anyone with more experience! My dev.edn looks like this:
^{:watch-dirs ["test" "src"]
:css-dirs ["resources/public/css"]
:auto-testing true
}
{:main simplyonmyway.node-test-2
:install-deps true
:npm-deps {:nodemailer "6.7.3"}}
I require nodemailer in main namespace as follows
(ns ^:figwheel-hooks simplyonmyway.node-test-2
(:require
[goog.dom :as gdom]
[nodemailer]))
This throws error in REPL: #object[Error Error: goog.require could not find: nodemailer]
Can anyone shed some light please? Thanks !@micheal.ocathain you need to use the :target :bundle
- I would double check whatever Figwheel requires for that compiler option
@U050B88UR thanks a lot for the steer! Not quite there yet but working through https://clojurescript.org/news/2020-04-24-bundle-target and https://cljdoc.org/d/com.bhauman/figwheel-main/0.2.14/doc/using-npm. This is great!
Given your description, the quickest way is to just write "some-str"
. :)
But assuming you actually want a full functionality of format
- it's not possible even if you require goog.string.format
, simply because the two aren't equivalent at all. The latter is much more limited.
In the end, it all depends on what exactly you want.
The absolute simplest option is to use str
.
If you have to have a template string, then you can combine str
, str/split
(with %s
probably), and interpose
. Note that it won't handle cases like %%s
correctly.
The next simplest is gstring, yes. If you don't like the funky way you have to require it, just create a wrapper for it in some util ns.

How can I read a file with clojurescript. The slurp and http://clojure.java.io (of course) are gone.
I've never had to deal with that but I know that the platform itself has some constraints. And seems like people use https://github.com/itinance/react-native-fs Nothing CLJS-specific about it, although maybe someone has written an alternative or wrapper for react-native-fs in CLJS.
There are a couple ways I've explored and one I haven't. If you can read the file at compile time, you can use clojure's slurp in a macro: See https://gist.github.com/noprompt/9086232. Another way is to open the file using showOpenFilePicker and weave your way through a sea of promises to eventually read the file. See https://web.dev/file-system-access/. There's a corresponding showSaveFilePicker routine that works to spit your file. Finally, you can use a FileReader to open a file and read it in. See https://web.dev/read-files/#:~:text=To%20read%20a%20file%2C%20use,a%20data%20URL%2C%20or%20text.. This is probably closest to what you want, but I haven't tried it. Here's some (probably crappy) code that reads and writes json using the second method:
(def json-file-types (clj->js {"types" [{"description" "JSON documents"
"accept" {"text/json" [".json"]}}
{"description" "Text documents"
"accept" {"text/plain" [".txt"]}}]}))
(defn read-file
[f]
(-> (. js/window showOpenFilePicker json-file-types)
(.then #(.getFile (first %)))
(.then #(.text %))
(.then #(f %) #(fn [_] nil))))
(defn writable-data-structure [data] (clj->js {"type" "write" "data" data}))
(defn save-file
[data]
(-> (.showSaveFilePicker js/window json-file-types)
(.then (fn [^js handle]
(.createWritable handle)) (fn [_] nil))
(.then (fn [^js writable]
(-> (.write writable (writable-data-structure data))
(.then (fn [_] (.close writable)) (fn [_] nil))
(.then (fn [_] true))) (fn [_] nil)))))
The read-file function allows one to pick a file, opens it (just one, even though showOpenFilePicker allows multi-select) and reads it by passing a function that takes the data into it. If something goes wrong, you get a nil for the data. Similarly, save-file allows one to pick a file and save the data. It returns true if everything goes well and nil if something goes wrong. Anyhow, if you want to be able to grab a file, and you don't mind asking the user for the file path at run time, this is how to do it.
(aset some-obj some-attr value)
Is this a guaranteed behavior to set attribute on js object? I tested the function works, but dunno if it is officially supported.
Don't use aset
for anything that's not an array.
It works but it's not guaranteed to work because it's not in its contract.
If some-attr
is a dynamic value, use goog.object/set
. If it's a static value, use set!
.

I haven't been paying a great deal of attention to cljs evolution over the last seven-ish years but will be getting back into it later this year (I get to rewrite our last legacy app and I'm considering an SPA with cljs/clj as one of the options) but I wondered whether cljs is still targeting "whole programs" only or whether the story for using cljs instead of JS for "small amounts of interactivity" has changed/improved? For example, could cljs be used for the event handling stuff in an HTMX app, to avoid JS?
One thing that happened during that time (and I don't know up from down, I just read the news) had something to do with the cljs compiler + g.closure being able to emit multiple distinct js script files and modules, so your app need not be literally an SPA but might be a 2PA or 3PA, yet the distinct js files and modules would be optimally & automatically determined?
you can use htmx just fine too if you want. no need to go the full SPA route, although as David said given the baseline size of a CLJS output thats what most people do
Yeah, this app doesn't really need to be an SPA so HTMX would give it enough interactivity (mostly just reloading panels when sidebar links are clicked) but I would still prefer to avoid JS if I can -- you know my feelings about JS/Node/npm stuff 🙂
yeah, you can just use the CDN version of htmx. thats totally fine. no need for npm or so
but you always pay for cljs.core
overhead so the minimum baseline for a 3 line htmx extension then becomes 30kb or so
Good information. Thanks.
I don’t think you need a ton of interop when using htmx - not in my experience. There are a couple of htmx specific events you might want to listen to and a little bit of configuration, that’s pretty much it on the client side. On the server you want to add a bit of special handling and structure depending on htmx specific http headers. 30kb for cljs isn’t much, but likely unnecessary if you only have minimal state on the client such as toggling attributes/classes etc. in that case it would easily more than double your JS payload. Htmx is very small. If you do however want to have any client side state that isn’t isolated or want to render templates, consider that htmx is deceptive. You suddenly need to coordinate things across (ajax) events. Htmx works best if thought of as an enhancement over pure SSR in a HTTP/Hateoas kind of way.
Oh and be careful with caching if you serve htmx specific responses, you need htmx specific caching. I think it’s an easy thing to miss 😅.
But is there really any benefit for using Cljs without react? with the DOM being very imperative and full of mutation
I still use CLJS regularly for just plain DOM interop. hot-reload doesn't work as well but that's fine. its usually just for swapping a class
or similar trivial stuff
We used JavaScript for "a sprinkling of features" in a mainly static webpage for a year or so, but with time all such "not enough JS to warrant CLJS" grow in size and scope. We've recently rewritten it in cljs, and it was a massive improvement.
https://parenscript.common-lisp.dev and https://wisp-lang.github.io/wisp/ have both caught my eye for the light-weight use-case. Haven't had a chance to really try either just yet, but I think I would prefer it to writing javascript.
Took a closer look at wisp out of a renewed curiosity, and I'm impressed! Especially for the "a sprinkling of features" use-case; if it grows beyond that, translation to cljs is already mostly done as it shares a lot of the same syntax. https://github.com/wisp-lang/wisp/blob/master/doc/language-essentials.md