This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-01-27
Channels
- # announcements (1)
- # aws (10)
- # babashka (53)
- # calva (133)
- # clj-kondo (46)
- # cljdoc (6)
- # cljs-dev (33)
- # clojure (105)
- # clojure-boston (1)
- # clojure-europe (11)
- # clojure-nl (4)
- # clojure-poland (1)
- # clojure-switzerland (6)
- # clojure-uk (13)
- # clojurescript (106)
- # cursive (1)
- # datascript (2)
- # emacs (13)
- # events (1)
- # figwheel-main (4)
- # fulcro (17)
- # graphql (8)
- # heroku (2)
- # honeysql (8)
- # lsp (76)
- # luminus (30)
- # malli (12)
- # meander (23)
- # music (1)
- # nextjournal (83)
- # off-topic (6)
- # pathom (3)
- # polylith (19)
- # re-frame (8)
- # reagent (2)
- # reveal (3)
- # shadow-cljs (54)
- # sql (9)
- # testing (11)
- # tools-deps (15)
- # xtdb (14)
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
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 XDPerhaps #shadow-cljs is the appropriate channel since that is the build tool I'm using
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("foo.bar")
is defined in foo/bar.js
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
if you are unclear about what the "classpath" means maybe this helps https://code.thheller.com/blog/shadow-cljs/2021/05/13/paths-paths-paths.html
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.
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
Is it possible to transpile a .cljs
file into readable .js
file?
take the JS file and run it through something like prettier
makes it more readable. :pretty-print
is not that pretty 😉
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
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 cljs.build.api/build
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?Hmm another issue with :npm-deps… I’ve got this setup below:
(cljs.build.api/watch ;; or watch with path
"src"
{: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 would read over this https://clojurescript.org/guides/webpack 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]
This is the only cljs I’m loading:
(ns hello-world.core
(:require [weasel.repl :as repl]
[react]))
(when-not (repl/alive?)
(repl/connect ""))
(react/createElement "h1" nil "Page title")
This is my call to the compiler:
(cljs.build.api/build
{: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"}})
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?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):
(cljs.build.api/build ;; 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 "0.0.0.0" :port 9001))
Along with src/hello_world/core.cljs
:
(ns hello-world.core
(:require [weasel.repl :as repl]
[react]))
(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)
nil
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
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"}})
(cljs.build.api/build compiler)
(apply cljs.repl/repl
(weasel.repl.websocket/repl-env :ip "0.0.0.0" :port 9001)
compiler)
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
:
(cljs.repl/repl
(weasel.repl.websocket/repl-env
:ip "0.0.0.0" :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:
(cljs.repl/repl
(weasel.repl.websocket/repl-env :ip "0.0.0.0" :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"]})
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
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.
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"}})
(clojure.core.server/start-server
{:accept 'cljs.core.server/io-prepl
:address "127.0.0.1"
:port 6776
:name "build"
:args [:repl-env (weasel.repl.websocket/repl-env :ip "0.0.0.0" :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 http://Heraku.com ! 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:
remote: ! Failed to build.
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.
if you ask me compile locally and only deploy the compiled result as a static website or so
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).
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
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? https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-nodejs
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.
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.