Hi folks, I have this project / editor setup:
• emacs / cider
• I ’m migrating from figwheel to shadows
• it’s a mono repo with server-side code (clojure) and cljs
• server side i want to start a http-kit server
• and i want to run shadow-cljs
• preferrably by just running one command: cider-jack-in-clj-and-cljs
Is this possible? I was talking to chatGPT but eventhough it’s very confident, it doesn’t seem to help me.
I get this:
Caused by: java.io.FileNotFoundException: Could not locate shadow/cljs__init.class, shadow/cljs.clj or shadow/cljs.cljc on classpath.
I was planning to run my app in locally via:
(ns cs2.dev
(:require
[shadow.cljs.devtools.api :as shadow]
[cs2.handler :refer [handler]]
[org.httpkit.server :as http]))
(defonce server (atom nil))
(defn start-httpkit! []
(when-not @server
(println "Starting HTTP-Kit server on port 3447")
(reset! server (http/run-server handler {:port 3447}))))
(defn stop-httpkit! []
(when-let [stop-fn @server]
(stop-fn)
(reset! server nil)
(println "HTTP-Kit server stopped")))
(defn watch-client! []
(println "Starting shadow-cljs watch for :app")
(shadow/watch :app))
(defn start-dev! []
(start-httpkit!)
(watch-client!)
(println "✅ Dev environment running."))if you run embedded you need to start shadow-cljs via server/start! https://shadow-cljs.github.io/docs/UsersGuide.html#embedded
is what i want possible at all, or do i need a separate watch terminal running
I just spent a bit of time seeing how far I could push the JS integration, specifically if I could integrate something like shadcn
Some notes from that process:
• The src/gen approach seemed good, I ended up using swc to compile .tsx files but otherwise 👌
• Shadcn heavily relies on aliases to create location-independent, consistent requires in the form of @/ui/components/badge etc, adding the snippet below to .swcrc seemed to make that work
• Finally I ran into ReferenceError: Can't find variable: cn$$module$js$lib$utils — the source JS file looks reasonable so this is where I gave up 😅
"baseUrl": ".",
"paths": {
"@/*": ["./src/js/*"]
}
Full SWC config and command
yarn swc -w src/js --out-dir src/gen --strip-leading-paths
{
"$schema": "",
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true
},
"baseUrl": ".",
"paths": {
"@/*": [
"./src/js/*"
]
},
"transform": {
"react": {
"runtime": "automatic"
}
}
}
} anything larger than just 1 or 2 files I'd recommend putting into packages/foo/that/stuff and (:require ["foo/that/stuff" :as x]) + :js-options {:js-package-dirs ["packages" "node_modules"]}. that gives those files npm semantic (e.g. :simple only)
still needs conversion from JSX of course, but it basically becomes your own npm package that way
ohh
does this need a package.json etc?
yeah, npm init -y in packages/foo is usually sufficient
I'm not sure if you can configure shadcn to use a different alias, otherwise packages/@ is a valid folder name 😉
hmmm that makes it a bit more complicated 😄
I'll keep playing with this, thanks for the ideas!
I guess one other option with this is also just bundling all JS into a single foreign lib and importing from that?
I guess then you have the challenge of shared deps etc
not a fan of bundling twice, but sure 😛
:js-provider :external also works for that
i am trying to migrate to shadow-cljs, and when I run npx shadow-cljs watch app, it also starts compiling .clj files (ie. the server-side part / Ring part of the webapp app).
Is this expected? Because I don’t think i would want that
most likely this is triggered by a user.clj on your classpath. clojure unconditionally loads that and shadow-cljs can't stop it.
yeah i have that file. I use it from time to time. Do you recommend not using :deps true? Or does user.clj need to go
I usually avoid having a user.clj due to the unconditional load
okay thanks!
you can move it so its only on the classpath when you start the server
yeah i see
thanks!
or change the code in that file, so that it only does stuff when actually needed 😛
yeah
thanks sir!
BTW: chatGPT was helpful, but i told it you were more helpful 😄
hehe
$> npx shadow-cljs watch app
shadow-cljs - config: /Users/marten/Sites/clojure/cs2/shadow-cljs.edn
shadow-cljs - starting via "clojure"
Warning: environ value 30 for key :retention-days has been cast to string
Warning: environ value true for key :is-dev has been cast to string
Warning: environ value 640 for key :image-thumb-width has been cast to string
those environ things are a server side thingi’m almost there… migrating from figwheel-main -> shadow
[:app] Build failure:
The required namespace "webpack.bundle" is not available, it was required by "cs2/core.cljs"
One more thing, i have a bundle.js, that’s built with webpack, that i previously just required like
(cs2.core
(:require [webpack.bundle])
The compiled bundle.js is still tehere, and this is my shadow-cljs.edn
{:deps true
:builds
{:app
{:target :browser
:output-dir "public/js"
:asset-path "/js"
:modules {:main {:init-fn cs2.core/init}}
:foreign-libs [{:file "resources/public/js/compiled-webpack/bundle.js"
:provides ["webpack.bundle"]
:global-exports {webpack.bundle window}}]
}}}
and this was how it was compiled:
window.deps = {
'parchment' : require('parchment'),
'variableblot' : require('../quill/VariableBlot'),
'menumarkerblot' : require('../quill/MenuMarkerBlot'),
'uppy-core' : require ('@uppy/core'),
'uppy-xhrupload' : require('@uppy/xhr-upload'),
'uppy-dashboard' : require('@uppy/dashboard'),
'uppy-dragdrop' : require('@uppy/drag-drop'),
'uppy-progressbar' : require('@uppy/progress-bar'),
'uppy-fileinput' : require('@uppy/file-input'),
'uppy-droptarget' : require('@uppy/drop-target'),
'uppy-imageeditor' : require('@uppy/image-editor'),
'papaparse' : require('papaparse')
};
window.Uppy = window.deps['uppy-core'];
window.XHRUpload = window.deps['uppy-xhrupload'];
window.Dashboard = window.deps['uppy-dashboard'];
window.DragDrop = window.deps['uppy-dragdrop'];
window.DropTarget = window.deps['uppy-droptarget'];
window.ProgressBar = window.deps['uppy-progressbar'];
window.FileInput = window.deps['uppy-fileinput'];
window.ImageEditor = window.deps["uppy-imageeditor"];
window.Parchment = window.deps['parchment'];
window.VariableBlot = window.deps["variableblot"];
window.MenuMarkerBlot = window.deps["menumarkerblot"];
window.Papa = window.deps["papaparse"];shadow-cljs doesn't support :foreign-libs. Usually you'd just require the things directly without the webpack.bundle at all. so just (:require ["parchment" :as parchment]) and using parchment directly instead of js/parchment
if for some reason you want to stick to webpack you can use :js-provider :external which basically generates that JS code for you
https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider-external
or if you want it manual you just have webpack build that file and you include it separately via its own <script> tag
this you can just remove then (:require [webpack.bundle])
right, so indeed most of these things i can put in package.json is what you are saying, right? The two Blot things i created myself back in the day… so i need to make those js modules presumably
assuming you access things via js/Uppy and stuff anyway
ah yeah of course that’s also an option
i do yeah
that’s pragmatic indeed
then just build it like you are used to and don't tell shadow-cljs about it 😉
🤫 ack
should I do that differently? or should this just work with :foreign-libs?