Fork me on GitHub
Nom Nom Mousse17:01:39

I had a working codebase. Then I did git clean -fdx (for some reason) and now I get weird errors. Might these be related to my git clean?


It is not finding your node modules. Presumably kill the process, npm i and then start again

Nom Nom Mousse17:01:54

npm i                                                                                                                                                                                                                                                                                                                                                                                                            (base)

up to date, audited 91 packages in 2s

found 0 vulnerabilities
I might have fudged up. On the front-end side I was just cargo-culting and now I'm lost XD

Nom Nom Mousse17:01:18

Perhaps #shadow-cljs is the appropriate channel since that is the build tool I'm using

Nom Nom Mousse17:01:37

I think I see it. I had some library versions locked in config files, but others not. So after git cleaning I got the most recent version of one library (d3) while some of the locked libraries expected a different version of d3.


I am banging my head on a problem with using a goog CloSure-compatible javascript library into a clojurescript project. I have created the :libs vector mentioning the .js files. When I try to reference the namespace in the .cljs file and compile, the clojurescript compiler says their namespaces are not available. Do the .js files have to be a magic name? I turned on :verbose and can see the options being passed into the clojurescript compiler.


The clojurescript output mentions looking in various places, but not anything from the :libs files


if they are true closure js files you can just put them on the classpath if they follow the proper naming convention, ie. goog.provide("") is defined in foo/bar.js


no need for build config at all in that case


That was the approach I tried yesterday when I tried a prototype with shadow-cljs. I'll try with this one using fw-main. The files are generated from the grpc tools and some .proto files.


same answer really. it should jsut work assuming the files are named correctly and available on the classpath


During yesterday's prototype, ran into problems with (:require ["protos.mythings"]) and an error about sym. Using unquoted names also ran into a problem but I don't remember it off top of my head.


if its an actual closurejs file using a string to require it is incorrect. so (:require [protos.mythings]) assuming the file lives in protos/mythings.js on the classpath


do the .js files need to be in a separate src tree from the .cljs files?


if you are unclear about what the "classpath" means maybe this helps


they need to be on the classpath. how they get there is up to you. so could be a different root dir or the same.


Article seems very shadow-cljs specific.


I'm going to work my way back up to just clojurescript and see if I can sus out where my understanding goes wrong.


well, yes all the example use shadow-cljs but the semantics of the classpath apply to all clojure/script tools


so deps.edn you have :paths instead of :source-paths and :deps instead of :dependencies. the classpath they construct and how files are looked up are identical

Nom Nom Mousse18:01:36

Is it possible to transpile a .cljs file into readable .js file?


@endrebak :pretty-print true

🙏 1

take the JS file and run it through something like prettier makes it more readable. :pretty-print is not that pretty 😉

Nom Nom Mousse18:01:45

Where do I use the pretty-print arg? And if I use prettier, is there any point in setting :pretty-print true first?


for shadow-cljs :compiler-options {:pretty-print true} in the build config (note that it defaults to true for development builds


and no, prettier will do its own thing. doesn't matter what the input code looks liek


@thheller, thank you. Made progress and got a more meaningful problem now.


some Clojure 1.11 stuff landed in ClojureScript this past week - worth poking around at - :as-alias as well as support for trailing maps - you can use ClojureScript via deps.edn git deps to try it out


I’m trying to use :npm-deps in the ClojureScript compiler to install @react-spring/web. Does anyone know how I might require that? I’ve seem to be able to compile with this in my call:

:npm-deps     {:react              "17.0.2"
                 :react-dom          "17.0.2"
                 "@react-spring/web" "9.4.2"}}
But I have no idea how I would (require "@react-spring/web") after this. Has anyone done this before?


(:require ["@react-spring/web" :as spring-web])


Thanks so much!


Hmm another issue with :npm-deps… I’ve got this setup below:

( ;; or watch with path
 {:output-dir   "public/js"
  :output-to    "public/js/main.js"
  :asset-path   "js"
  :main         "hello-world.core"
  :install-deps true
  :npm-deps     {:react      "17.0.2"
                 :react-dom  "17.0.2"}})
When I connect to my REPL, I eval these forms:
(require 'react) ;; works!

(react/createElement "h1" nil "Page title") ;; error!
The error I get is:
"#object[ReferenceError ReferenceError: module$Users$neilhansen$Documents$cljs_test$node_modules$react$index is not defined]


@neil.hansen.31 if you're doing web development with :npm-deps you should use :target :bundle


I’ll give that a try next, thanks!


I would read over this and make sure it works for you before going much further


I’m sorry to be a pest… I’ve been trying to figure this out for a long time. I’m still getting the same error: “#object[ReferenceError ReferenceError: module$Users$neilhansen$Documents$cljs_test$node_modules$react$index is not defined]


you need to clear your output dir


This is the only cljs I’m loading:

(ns hello-world.core
  (:require [weasel.repl :as repl]

(when-not (repl/alive?)
  (repl/connect ""))

(react/createElement "h1" nil "Page title")


you compiled in the wrong way - start over


This is my call to the compiler:

 {:output-dir   "public/cljs"
  :output-to    "public/cljs/main.js"
  :asset-path   "cljs"
  :main         "hello-world.core"
  :install-deps true
  :target       :bundle
  :bundle-cmd   {:none ["esbuild" "public/cljs/main.js" "--bundle" "--outfile=public/js/main.js"]}
  :npm-deps     {:react              "17.0.2"
                 :react-dom          "17.0.2"}})


I realize I’m using esbuild instead of webpack, maybe that’s creating my issue?


Will clear everything and try fresh


the above error looks like you compiled w/o :target :bundle at least once


and then didn't start over


Hmm I’m actually realizing that this happens if I call (react/createElement "h1" nil "Page title") from the REPL


When the page just initially loads (react/createElement "h1" nil "Page title"), it works fine. But an evaluation from the REPL leads to the error above.


Is this expected behavior at the repl? I know ClojureScript has always had some caveats around dynamic (require), I suppose I can just remember that calling js namespaces at the REPL is a no-no


you need to switch into the namespace to react you can't use it from cljs.user which is the default namespace


I see, I’m finding that even when I switch the REPL to hello-world.core which has:

(ns hello-world.core
  (:require [react]))
Then (react/createElement "h1" nil "Page title") in the REPL errors. Obviously I can work around that, I’m just trying to understand what’s expected behavior. Is this what you’d expect?


Not expected far as I know


Hmm okay well here’s a minimal reproduction if you’re interested. I have this build.clj file (along with the necessary requires at the top):

( ;; or watch with path
 {:output-dir   "public/cljs"
  :output-to    "public/cljs/main.js"
  :asset-path   "cljs"
  :main         "hello-world.core"
  :install-deps true
  :target       :bundle
  :bundle-cmd   {:none ["esbuild" "public/cljs/main.js" "--bundle" "--outfile=public/js/main.js"]}
  :npm-deps     {:react     "17.0.2"
                 :react-dom "17.0.2"}})

(cljs.repl/repl (weasel.repl.websocket/repl-env :ip "" :port 9001))
Along with src/hello_world/core.cljs:
(ns hello-world.core
  (:require [weasel.repl :as repl]

(when-not (repl/alive?)
  (repl/connect ""))

(js/console.log (react/createElement "h1" nil "Page title"))
REPL opens in my Terminal, and waits for client connection. I serve my public folder with cd public && python3 -m http.server. Navigate browser to localhost:8000. Connection works, REPL prompt appears. In the browser console, I also see the printed form of the React component from hello-world.core:
{$$typeof: Symbol(react.element), type: 'h1', key: null, ref: null, props: {…}, …}
Now that I have a prompt in the REPL, I run:
cljs.user=> (in-ns 'hello-world.core)
hello-world.core=> (react/createElement "h1" nil "Page title")
WARNING: No such namespace: react, could not locate react.cljs, react.cljc, or JavaScript source providing "react" at line 1 <cljs repl>
WARNING: Use of undeclared Var react/createElement at line 1 <cljs repl>
#js {"$$typeof" #object[Symbol(react.element)], :type "h1", :key nil, :ref nil, :props #js {:children "Page title"}, :_owner nil, :_store #js {}}


@U050B88UR You’ve done so much for me here, I’m certainly set to keep working with what you’ve shown me. Thanks so much for your time. I hope the example above is enlightening for what I was trying to do, and if it’s showing unexpected behavior that I’m glad I was able to bring it to your attention.


The build works but the REPL needs the same stuff - it also needs to know about :npm-deps


…it does?


I had no idea. Do you have a resource I could follow for that?


You are doing things in a slightly odd way


But just pass the compiler options to the REPL


Yeah, I know am. I’ve been experimenting with setting up ClojureScript REPLs without CIDER/Figwheel/Shadow etc. Just trying to learn.


Just tried below and got the same error… is this what you were talking about?

(def compiler
  {:output-dir   "public/cljs"
   :output-to    "public/cljs/main.js"
   :asset-path   "cljs"
   :main         "hello-world.core"
   :install-deps true
   :target       :bundle
   :bundle-cmd   {:none ["esbuild" "public/cljs/main.js" "--bundle" "--outfile=public/js/main.js"]}
   :npm-deps     {"react"             "17.0.2"
                  "react-dom"         "17.0.2"}})

( compiler)

(apply cljs.repl/repl
       (weasel.repl.websocket/repl-env :ip "" :port 9001)


Apply won't work


Hmm I’m copy pasting them just to test this out… I get the same error as before when I pass to weasel.repl.websocket/repl-env:

  :ip "" :port 9001
  :output-dir   "public/cljs"
  :output-to    "public/cljs/main.js"
  :asset-path   "cljs"
  :main         "hello-world.core"
  :npm-deps     {"react"             "17.0.2"
                 "react-dom"         "17.0.2"
                 "@react-spring/web" "9.4.2"}
  :install-deps true
  :target       :bundle
  :bundle-cmd   {:none ["esbuild" "public/cljs/main.js" "--bundle" "--outfile=public/js/main.js"]}))


And when I pass those options to cljs.repl/repl, I get the same error, but it happens as soon as weasel makes the websocket connection:

 (weasel.repl.websocket/repl-env :ip "" :port 9001)
 :output-dir   "public/cljs"
 :output-to    "public/cljs/main.js"
 :asset-path   "cljs"
 :main         "hello-world.core"
 :npm-deps     {"react"             "17.0.2"
                "react-dom"         "17.0.2"
                "@react-spring/web" "9.4.2"}
 :install-deps true
 :target       :bundle
 :bundle-cmd   {:none ["esbuild" "public/cljs/main.js" "--bundle" "--outfile=public/js/main.js"]})


Is :npm-deps the only required one, or do I need to pass them all?


This very easy to get wrong I think trying to do it this way is probably not worth the effort - weasel should provide cljs.main style operation


Since it does not I would save yrself time and use figwheel or shadow


I get it, I appreciate your advice. I was just trying to experiment to see if I could “mix and match” different kinds of tooling to support custom workflows, and potentially embedding ClojureScript REPLs in environments like JavaScriptCore.


Seems like I got very close… and I would never have guessed that the REPL needed its own set of compiler options. I certainly appreciate the pointer.


One last thing is




Not the one you are using


If that doesn't work I would probably move on


Weasel seems far behind the times here


Yes, same behavior as above. Oh well, I’ll try something else. I really like how simple weasel is, maybe I can figure out a way to contribute something.


@U050B88UR I dug through the source and realized that I was passing the options to the REPL incorrectly. Here’s a version below that worked for me. Thanks again for the pointer!

(def options
  {:output-dir   "public/cljs"
   :output-to    "public/cljs/main.js"
   :asset-path   "cljs"
   :main         "hello-world.core"
   :install-deps true
   :target       :bundle
   :bundle-cmd   {:none ["esbuild" "public/cljs/main.js" "--bundle" "--outfile=public/js/main.js"]}
   :npm-deps     {"react"             "17.0.2"
                  "react-dom"         "17.0.2"
                  "@react-spring/web" "9.4.2"}})

 {:accept        'cljs.core.server/io-prepl
  :address       ""
  :port          6776
  :name          "build"
  :args          [:repl-env (weasel.repl.websocket/repl-env :ip "" :port 9001)
                  :opts options]
  :server-daemon false})


glad you figured it out! Yeah was on phone yesterday - but just looking at the functions is often quite quick to understand


First time deploy to ! And of course, the build failed.

remote:        [:app] Compiling ...
remote:        The required namespace "react" is not available, it was required by "reagent/core.cljs".
remote:  !     Failed to build.


Ooops, sorry, accidentally pressed ENTER


Ok, usually when I get this, I know that something like npm install fixes this. But how to do this for Heroku?


Heroku should've automatically guessed that it's an NPM-based app if you have package.json at the root. If it didn't guess, you can add the relevant buildpack - it's documented on the Heroku's website.


Yeah, just browsing those buildpacks stuff. Just need to find out how to employ that. I'll give a feedback once I ge all this.

👍 1

if you ask me compile locally and only deploy the compiled result as a static website or so


compiling on heroku just makes things harder and slower


Ah okay, yes, I'd like to do that. It's just documented this way. Didn't know I could compile locally. Thanks


@thheller Correct me if I'm wrong but I'm pretty sure that's only feasible if you either use Docker images (and that doesn't work with pipelines) or commit the build artifacts to your Git repo (yuk).


Being a noob in this, I can confirm that at least the latter is true.


I don't have a clue how heroku works. if it has to be committed to git I'd probably use a separate repo for that. just run shadow-cljs release app on some machine you control (ie. yours) and have the output go to whereever it needs to


then git commit it and push or however heroku works


of course you can do docker and all that stuff if you want. or just build on heroku, I just personally don't see the point. YMMV


hmm... separate repo for the artifacts - I like that! Alas I don't have much time - I need to deploy in a couple of hours or I'm dead. So I stick with the official way for a bit longer. I was just wondering if this would also do the trick: ["shell" "npm" "install"] since buildpacks are also mysterious at this point.


With separate repos, you either have to do everything manually with a chance of screwing things up, or you have to automate it. And at that point building on Heroku is not that complicated anymore. :) It's just running a bunch of scripts, just as you would do locally.


@U01BEC6NUSY What is mysterious about buildpacks exactly? Have you seen this page, or any like it?


A "buildpack" is just a fancy name for a bunch of scripts that rely on predefined environment variables set by Heroku during build time. npm is installed and is run by the nodejs buildpack. It checks whether your app has package.json, installs node along with npm and caches them for future use, runs npm ci, caches the resulting node_modules, and let the rest of the buildpacks run.


Thanks for the explanation. I've seen that page and many more. For instance, I wasn't sure whether I should use the Node.js-buildpack or the Clojure one. And then, how to apply that thing? Pls, don't explain, lol. Because a) I'stealing too much time from you guys and b) this is already embaraasing enough. I just tried [shell npm install] in project.clj and will let you know...


dammit: remote: Uberjar aborting because jar failed: Cannot run program "npm" ok, so I try that node.js-buildpack. Thanks to you I already know which one to use. I'll let you know.


Every buildpack does one thing, usually. The nodejs one only installs node and npm, runs npm ci, and runs node if the relevant entry point is specified. That's it. But yeah, without that buildpack you won't have npm. A Clojure buildpack (not sure which one you're using - I ended up writing my own because back then there was no good support for deps.edn) does only Clojure stuff, without anything else. In the case of one of my apps, the CLJS build is done via a custom script that's run by a yet another buildpack that simply runs custom scripts - apart from running shadow-cljs it also does some somewhat related things, like uploading source maps to a logging service.


> I'stealing too much time from you guys Irrelevant - I'm volunteering on this server of my own volition, not because someone forces me to. :)


🙂 well, honestly, you guys are heroes to me. Said it months ago. Have a constant information overflow syndrome. No clue, how you got through this. Anyway, on to it -- or "they" kill me in 4 hours for a blank page.

👍 2

To be super-cautious:

heroku buildpacks:set heroku/nodejs
in my project folder activates this stuff?


I don't remember what :set does and it seems to be undocumented for some reason (`heroku buildpacks --help`), so I usually use :add. Given that they both have the same exact arguments, my guess is that they're the same, and :add is just more clearly named.


But yes, that would add the buildpack. Note that sometimes the order of the buildpacks is relevant. E.g. in the case of building CLJS the nodejs buildpack has to be before the one that actually does the building.


I used :add because you said so, and IT WORKED. Now I want a Marvel like action figure of you. Phew... ok, on to the database. The gallows is a less likely now.

😄 3