This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-07
Channels
- # babashka (31)
- # babashka-sci-dev (10)
- # beginners (64)
- # biff (11)
- # clerk (5)
- # cljdoc (2)
- # clojure (84)
- # clojure-boston (3)
- # clojure-conj (2)
- # clojure-europe (11)
- # data-science (19)
- # datomic (118)
- # fulcro (3)
- # graalvm (3)
- # hoplon (6)
- # inf-clojure (146)
- # instaparse (5)
- # lsp (13)
- # malli (3)
- # off-topic (13)
- # pedestal (5)
- # proletarian (5)
- # re-frame (14)
- # reitit (12)
- # releases (1)
- # ring (19)
- # scittle (2)
- # shadow-cljs (155)
- # slack-help (3)
is there a way to make the dev-server auto-open the browser on init
macros are weird. and I don't get it why it has to be different for browser builds than as for node-script builds
well, I am not sure what the heck I am doing wrong, but they do behave differently for me
I can look at some code if you want. besides my blog post on the subject I don't have much to add in generic advice
(ns server.main
(:require
[ui.hiccup :refer [hcc-server]]
[ui.html :as ui-html]
["express" :as express]
["serve-static" :as serve-static]
["node:http" :as http]
["react" :as react :refer [createElement]]
["react-dom/server" :as rdc :refer [renderToPipeableStream]]))
(defonce server (atom nil))
(def serve (serve-static "build", #js {:index false}))
(defn request-handler [^js req ^js res next]
(let [did-error (atom false)
stream (atom nil)]
(if (not (= (.-url req) "/"))
(serve req res next)
(reset!
stream
(renderToPipeableStream
(clj->js (hcc-server ui.html/index))
#js {:onError (fn [e]
(reset! did-error true)
(js/console.error "Error rendering" e))
:onAllReady
(fn []
(js/console.log "ALL READY"))
:onShellError
(fn [err]
(set! (.-statusCode res) 500)
(.send res (str "ERROR:" err)))
:onShellReady
(fn []
(set! (.-statusCode res) (if @did-error 500 200))
(.setHeader res "Content-Type" "text/html")
(.pipe ^js @stream res)
(.end res))})))))
(defn start [bs]
^:dev/after-load
(let [app (express)]
(.use app request-handler)
(reset! server (http/createServer app))
(.listen ^js/Node.http.Server @server 8000 (fn [] (println "Server running on port 8000")))
bs))
I have ui.hiccup cljs
(ns ui.hiccup
(:require-macros [ui.hiccup] [hicada.compiler :refer [compile]]))
and cljc
(ns ui.hiccup
(:require
[ui.html]
[hicada.compiler :refer [compile]]))
(defmacro hcc-server [body]
(hicada.compiler/compile
(eval body)
{:create-element 'react/createElement
;:transform-fn (comp)
:array-children? false}))
(defmacro hcc-client [body]
(hicada.compiler/compile
body
{:create-element 'js/React.createElement
;:transform-fn (comp)
:array-children? false}))
notice the eval body that I needed there in hcc-server, without that, it was not working. Now I am trying the client side and it's breaking with eval, which makes sense, but can't get it to work with anything
well, what is it doing in the first place. (clj->js (hcc-server ui.html/index))
this makes no sense to me
because otherwise react complains that can't really do anything with the returned clojurescript object
but it's large, I can't always type it and maybe I want to use different hiccup edns in multiple projects, so I need a way to require and use them both on the server and on the client to render react nodes
ok, so I assume that your intent is to compile that form. this isn't possible in CLJS.
turn that into (def index (html [:div "x"]))
, so the macro is getting the actual EDN, not a symbol referring to it
I do not know what the hicada compiler is doing, but did you verify that the code you think you get you actually get?
yes, but the macro just needs to know the edn, nothing else, doesn't call cljs or js anything
then I don't understand what you are trying to do in the first place. everything seems to behave as you want then?
well, ... this is exactly why I warn against using .cljc
code. I assume that is the part you don't correctly understand.
.cljc
is two files in one. a CLJS file and a CLJ file. clj eval
can ONLY find the CLJ parts, it has no knowledge of CLJS parts
sorry for not being more specific here, I couldn't get the reader conditionals to activate, that's why I have two macros
don't know why custom reader would factor into anything here, so that statement just confuse me 😛
is your intent in any way to run this in CLJ? or is this purely CLJS running the browser and/or node?
I need to write this macro because of hicada. And doing hiccup needs macro anyway, since I don't want js to evaluate static stuff over and over again
because edn is just data, it doesn't matter what runtime. clj cljc cljs and who knows how many others are all context dependent and behave very differently under different builds and runtimes
when it is truly just data then make it a .edn file, nothing stopping you from doing that
i don't want hicada, but manually writing this thing for react is a huge task, and hicada seemed the freshest of all the options for hiccup and clojurescript
it was really difficult to load then the edn files into the client build. node server was very easy of course.
you can use the edn file via macros, they don't need to be loaded at runtime. but I'm still guessing at which problem you are trying to solve exactly
it seemed the one with recent activity, others were either older or didn't use hiccup or did it with runtime transformation
but I may be wrong about this, not saying I spent more than 1-2 days googling hiccup libraries and reading their docs
yes, I do want to optimize the hiccup parsing to compile time, at least where it's feasible, like with SSR. So everything that can be render on the server, shouldn't then be re-parsed on the client side
thats not what is going to happen? the server spits out html, it doesn't spit out hiccup?
it was a week ago when I was trying to do this, so I don't have all the details. need change the code again.
If I understand you correctly, I should use some clojure/java thing to read the file, then the edn reader to parse it, and then somehow I can give it to the macro, hopefully. 😄
Does shadow-cljs support hot-reloading in node while targeting esm? Or how would I configure shadow-cljs to support a repl in node while using the esm target?
I’m compiling cljs code with shadow, and I’ve configured it with this:
{:output-dir "./cljs-server"
:target :esm
:runtime :node
:js-options {:js-provider :import}
:modules {:app.server {:exports {add app.server/add}}}
:release {:compiler-options {:optimizations :advanced}}}
Is it possible to connect to a running repl after importing the CLJS modules into a node program?
Is it possible to use the devtools for the node or npm_module for this? Or does it need to have its own devtools?
ok, in the build config you may set :runtime :custom :devtools {:client-ns your.attempt}
your.attempt
is a namespace. you can probably start with a copy of one of the defaults
don't start with this one, as it is the most complicated since it also handles the HUD and CSS reloading stuff
https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/cljs/devtools/client/node.cljs
feel free to ask questions about them, they all work the same just adapted to specific platforms
the common bits are extracted out already, the main differences are in the eval parts
so :npm-module
evals the code entirely differently https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/cljs/devtools/client/npm_module.cljs#L96-L114
so you could probably take the browser, rip out everything related to HUD and CSS and change it to use the ws
package instead of js/WebSocket
at least that is likely how I would start. I have not yet done any work related to this
could maybe also start with the npm-module client, but rip out all the commonjs bits
thats all it takes to swap out the impl, yes you could probably polyfill that in different ways
node always makes me want to throw me pc out the window. so I haven't looked at it in a while 😛
ie. node wants ws package, browser wants js/WebSocket
, don't even know what deno or bun want
they’ll probably try to use the node option but deno may try to implement js/WebSocket
how should i attempt to test my changes? do still use the shadow-cljs sources in my own source paths? or do I need to build the cli and link that to node_modules?
don't even need the shadow-cljs sources at all. changes to the CLJ parts should not be required in any way
I thought I would importing shadow-cljs devtools modules if I was copying the node or browser implementation. Can I still re-use some code with my implementation?
I don't understand that question. there are no "shadow-cljs devtools modules". they are just regular CLJS namespaces, that you compile with your build
I see, so a namespace like this would be available to my code: shadow.cljs.devtools.client.env
?
its all just CLJS namespaces, you can even replace existing ones by just putting them on your source path with the correct name
Okay happy to report that copying the browser version and replacing roughly two lines works so far
Probably just need to shake out the unrelated browser stuff and it should be fine I think
Okay sounds good, I’ll continue to tweak this until I think it’s ready for a review, then I’ll try to setup a PR