This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-08
Channels
- # announcements (3)
- # babashka (3)
- # beginners (25)
- # calva (12)
- # cider (58)
- # clara (11)
- # clj-kondo (19)
- # cljsrn (2)
- # clojure (84)
- # clojure-austin (1)
- # clojure-europe (5)
- # clojure-nl (4)
- # clojure-spec (23)
- # clojure-uk (53)
- # clojuredesign-podcast (5)
- # clojurescript (24)
- # core-async (57)
- # cursive (16)
- # datomic (39)
- # emacs (1)
- # fulcro (40)
- # funcool (2)
- # graphql (17)
- # jackdaw (31)
- # jobs (2)
- # joker (3)
- # malli (7)
- # off-topic (12)
- # re-frame (9)
- # reagent (2)
- # reitit (1)
- # ring (4)
- # shadow-cljs (170)
- # sql (36)
- # tools-deps (5)
- # xtdb (20)
i was using multiple socket connections to shadow-cljs, thinking to have one with a current namespace set to one namespace and others set to other namespaces. when i do in-ns in one, all of the other connections appear to have their current namespace affected. is this the expected behavior?
hey @thheller I have a yarn link:ed package in node_modules
(let's call it lul
). whenever I modify the contents of lul
, and then trigger a compile using (shadow.cljs.devtools.api/watch-compile! :app)
, it seems that it won't "recompile" lul
. is there something I can do to fix this? 🙂
oh wait, maybe this was no fault of shadow-cljs. I restarted yarn, and then it works. never mind then : ]
Very often recently I’ll see the warning “Stale Client! <...>” — is the workaround to always have the Chrome dev tools open and disable the network cache?
I see it only when I restart shadow-cljs server/worker. Do you see it without any restarts?
Another reason for that is if you serve a stale JS bundle with your web server. At least, I've made such an error in the past where I was caching manifest.edn
during development.
@U7PBP4UVA the shadow-cljs caches don't matter for this error. it is your output that is cached or just plain out of date. sometimes people forget to adjust their paths in the HTML after changing the :output-dir
in their config?
if you are not using the built-in http servers than it might be your server just using too lax cache headers
Ah, yes, I’m using my own server. I’ll make sure I’ll set the correct headers — thanks!
BTW, the Stale Client warning is a very good one! I can’t imagine the frustration if caching is in play and you didn’t know. Thanks!
@thheller This morning, I went to a different computer, updated shadow-cljs to 2.8.61 - started a REPL/node and now the defn with a docstring is returning nil instead of the var - I swear it worked yesterday on my other computer after the fix - is there some sort of cache I'm not seeing?
no. are you sure you upgraded correctly? ie. if you use project.clj or deps.edn just updating package.json isn't enough?
and/or are you sure you restarted after updating? sometimes easy to forget a running server instance. shouldn't say connected to server ...
on startup
$ shadow-cljs node-repl
shadow-cljs - config: /mnt/c/Users/thheller/code/shadow-cljs/shadow-cljs.edn cli version: 2.8.61 node: v10.13.0
shadow-cljs - connected to server
cljs.user=>
shadow-cljs - config: /home/chris/Projects/its-nancy-land-app/shadow-cljs.edn cli version: 2.8.61 node: v10.16.3
shadow-cljs - server not running
<- that's what i get after stopping> shadow-cljs watch frontend server
shadow-cljs - config: /home/chris/Projects/CloudRepo/its-nancy-land-app/shadow-cljs.edn cli version: 2.8.61 node: v10.16.3
shadow-cljs - HTTP server available at http://localhost:8700 shadow-cljs - server version: 2.8.45 running at http://localhost:9630 shadow-cljs - nREPL server started on port 8450
Thanks - and you also have the Clojure community funding? (I forget what that thing is called)
I have a JS library (closure compatible) that uses ES6 classes: class Foo extends Bar {}
that compiles to $jscomp.inherits(Foo, Bar);
which means that it needs $jscomp
(which is the es6 closure runtime polyfill) defined. This runtime is only included with simple optimizations (and up) per https://github.com/google/closure-compiler/issues/1138 but shadow-cljs in development mode is in :none
mode thus $jscomp
is undefined.
Now, say that I have extracted this $jscomp
polyfill into a js file (as this guy suggested https://github.com/google/closure-compiler/issues/1138#issuecomment-347902571 ). Is there any way I can include this in my dev build?
:compiler-options {:output-feature-set :es6}
or :dev {:compiler-options {:output-feature-set :es6}}
Because I wanted to use this library in a web worker I also tried to importScripts the $jscomp
runtime but it fails with weird errors
depending on which version you are on you might need to delete the .shadow-cljs/builds
cache
I fixed a bug in the last release where cache wasn't invalidated if you changed :output-feature-set
i've got a CIDER nrepl session connected to a shadow watch build cljs-repl, with a browser attached... mostly seems to work fine, but print output seems to be lost - i.e. (prn "foo")
executes but i can't see the output - can i configure something to get print output ?
if it doesn't its a CLJS side issue, could be caused by calling (enable-console-print!)
after shadow-cljs initialized its logging
same result with shadow-cljs cljs-repl
ok, so do you mess with set-print-fn!
in any way? directly or indirectly via enable-console-print!
or some such?
ok, i found the offending (enable-console-print!)
in our codebase 😊
I am wondering if anybody is doing hiccup->html generation as part of their shadow-cljs build and how they are going about it. I am only just starting to play with the tool (fine, fine work by the way). My M.O. with this stuff is often to dive in and start trying to use something for things it wasn't intended for 😉, but i had this bright idea of using a build hook to generate a little index.html into the build directory on compile. Potentially I would do this with some garden->css too, so I have one watcher process that just assembles everything. I am sure this probably constitutes ridiculous abuse of the tool, but in any case, it doesn't really work because build hooks are not watched or reloaded on change, so you have to restart the watch process for any changes to take effect thus somewhat nullifying the concept. I suspect the right answer here is to stop trying to use shadow-cljs for stuff it wasn't really intended to do and just use some kind of npm concurrently trick to start seperate watcher processes for each thing, but I thought I would check in with the community here first in case there is a better option I am missing.
My initial thought is that shadow-cljs is mostly for compiling to JS and that can be plugged into other pipes for hiccup->html
but there are hooks you can add at development time that can run everytime code is reloaded
I'm playing with the serverless framework, created a toy project: https://github.com/fbielejec/shadow-cljs-serverless Allthough the deployed endpoint works fine I'm struggling to get a nice local workflow going. Serverless provides an offline plugin https://www.npmjs.com/package/serverless-offline for just that, but with the shadow-cljs in a watch mode I get compilation errors after touching the sources:
Error: No protocol method ISwap.-swap! defined for type cljs.core/Atom: [object Object]
at Object.cljs$core$missing_protocol [as missing_protocol] (/ClojureProjects/shadow-cljs-serverless/api/cljs-runtime/cljs/core.cljs:312:3)
at Function.cljs$core$IFn$_invoke$arity$4 (/ClojureProjects/shadow-cljs-serverless/api/cljs-runtime/cljs/core.cljs:854:1)
at Function.cljs$core$IFn$_invoke$arity$4 (/ClojureProjects/shadow-cljs-serverless/api/cljs-runtime/cljs/core.cljs:4509:6)
at Object.cljs$spec$alpha$def_impl [as def_impl] (/ClojureProjects/shadow-cljs-serverless/api/cljs-runtime/cljs/spec/alpha.cljs:312:5)
at /ClojureProjects/shadow-cljs-serverless/api/cljs-runtime/cljs/spec/alpha.cljs:1384:1
at global.SHADOW_IMPORT (/ClojureProjects/shadow-cljs-serverless/api/graphql.js:70:44)
Yeah, I looked at those too but I assume they run inside the browser when it is the target meaning quite limited access to the file system. I think you are probably right re: other pipelines. I think my aversion is just in having multiple processes all doing the "watch" work. Would probably be nice to have a single generic watcher with plugins.
@wesley.hall what do you mean by this? > it doesn't really work because build hooks are not watched or reloaded on change
Do you mean the browser doesn't reload with your settings, or that there is no hook that executes at the time you want?
@isak The lifecycle hooks are written in clojure but these hooks are loaded at the start of the watch processes and any subsequent changes are not loaded until you restart the watch process. You can edit the clj files but triggering a new build (by changing the cljs files), while it does cause the hooks to be rerun, it is code that was read at the start of the watch process and not the latest changes that are executed.
if you’re trying to use hiccup in your CLJS code, that will get compiled just fine. if you’re trying to compile hiccup to some static html, outside of your CLJS code, it doesn’t currently support that
the question comes up a lot when people want to add Sass compilation, and thheller usually tells people it’s a better idea to run a separate watcher
@wesley.hall If you want dynamic reload of the hook itself, that may be tricky, but if you are able to write a function that watches+writes (and can remain stable), that is pretty easy to add in via the hooks
@lilactown Cool, I suspected that was probably the case. It's probably more a matter of me watching to "reuse" the watch process than start other ones. The docs on the build hooks do say something to the effect of, "this is a very powerful extension point", so I am probably just testing how far I can push this, but fully understand what is meant here is, "extend it to do more cljs->js stuff", rather than abuse it for other usages.
I'd disagree with @lilactown on this, I found it very easy to add other watchers to, and other compile steps
I think you can even get shadow-cljs to reload the page at arbitrary times, stuff not related to it's own build events, since you have access to the build runtime
AFAICT build hooks are good for triggering additional effects based on changes to CLJS files
@isak Yeah, I had thought about writing the hooks as relatively static code that does the dynamic loading within them. I can see how that might be done fairly easily. Then we probably get into best practice stuff.
they are not good for, e.g. reading and compiling files that don’t show up on the classpath (.scss/.graphql/etc.)
it sounds like what you’re trying to do is a little different, but similar in spirit to those things
I think there are two challenges to this: 1. you will need to figure out how to get shadow-cljs to watch those files (probably the stopper) 2. you will need to read the file from disk on each change
here is what I added at work to watch our custom CSS build: https://gist.github.com/isaksky/f693864aeedef8b54c1163342b36d788
I think the problem you were running into @wesley.hall is you need some way to reload the Clojure files you’re interested in compiling. I’m not sure the best way to do that
it might be reading them in from disk, it might be reloading them from the classpath, not sure
It's actually simpler than this in my little test case. My clj hook code literally just says, "convert this embedded hiccup to html and spit
it to this file". It's because the hiccup is embedded in the hook clj code that means it doesn't "see" the changes until I restart the watcher. I am kind of leaning towards just running different watch processes for each thing now. I think I was more or less here just to see if somebody was going to say, "oh, just set :reload-hooks true
in the build config" 🙂.
The interesting thing though is both @isak and myself are really just looking for ways to embed our own little jobs into the watcher process. This does somewhat support my previous idea that there might be a space for a generic watcher application into which jobs can be configured. i.e. "if these files change, pass them through shadow-cljs, if these ones change, pass them through the garden compiler" etc etc. I've had this effect before actually. The delights gain by a solid live reload / watcher process are so great that you want the process to do "all the things" 🙂
In @isak's case, I guess since he is starting a seperate watcher in his code, he could equally do that using an npm script and concurrently and keep the two things entirely separate. So that might be a matter of taste.
In any case, thank you gentlemen. I now have a clearer picture of what I need to look at. Appreciate the opportunity to bounce it around a little. As always, community delivers 🙂
@wesley.hall Agreed, and I think Thomas was talking about adding something like that eventually ( file-watch -> run arbitrary code/process helper). Though the good thing is it isn't too bad to add it yourself in the meantime.
@isak you :build-hook
things "leaks". it is never shutdown if you edit the build config file while watch
is running
@thheller Hmm ok, is there an event for that? For :configure, it says it is only run once
It's so people don't need to start multiple consoles to run the build in development mode
shadow-cljs run dev/setup
and
(ns dev
(:require
[shadow.cljs.devtools.api :as shadow]))
(defn setup
{:shadow/requires-server true}
[]
(start-your-watcher)
(shadow/watch :your-build))
seems like a better choice?hm, it is not obvious to me why. Also, when you say it leaks, do you mean if the hook is removed in a shadow-cljs.edn update?
if you modify the build-config while watch is running the old build-state is thrown away and a new one is created with the new config
leaks in the sense that it doesn't get thrown away immediately, having to wait for the GC?
you could use the plugin support, since that actually supports lifecycles fully. but it isn't documented or tested much 😛
activated via https://github.com/thheller/shadow-cljs/blob/1fb0b087a2051645ed6e7e9cfe179c51a67c9052/shadow-cljs.edn#L16
basically the :start
fn is called when the server starts, and :stop
is called when it ends
@isak @wesley.hall my challenge for both of you would be to build whatever you want to build AS IF shadow-cljs did not exist at all. just CLJ functions and then show me why it needs to be intergrated into a shadow-cljs build 😛
typically if you just have a CLJ function turns out to be a enough. since you can run that from the REPL or CLI
but coupling yourself too much to shadow-cljs specifics makes it really hard to run things independently
don't make things more complicated than they need to be just because it might safe you 5seconds of time per day
@thheller I just want to hijack the workflow. It's probably just cheating. The "wrapper" html is a stupidly trivial example anyway because it changes so rarely. For garden and css (which is obviously more dynamic), I can just use one of the (apparently several) services built for watching and compiling garden. It's just a matter of it feeling nicer to do in a single process. It's not really that much of a big deal. I don't really want you try to convince you to create another webpack, because at the same time I am asking all these questions, I am acutely aware of the impact trying to support every little usecase has on projects like this. Just really wanted to know if there was a cleverer solution that I was missing that was in regular use. When you have a compilation tool like this, that ultimately moves stuff from src to dist, the obvious problem is that it's now not just my js that needs to go into dist, but probably some html and some css (and indeed, images, fonts, etc etc). I am just trying to figure out the neatest way to get them there.
@wesley.hall I understand what you want but the question I have is "why does copying CLJS to dist have to be coupled to copying html/css to dist?" why can't they be 3 different steps?
I know your answer .. I just want to challenge your assumptions. you want to run one command, so my answer is that that one command shouldn't be shadow-cljs but something else that triggers those 3 steps (one being shadow-cljs)
have you ever looked at a 2 year old webpack config that nobody can upgrade anymore?
Yes, which is one of my two possible solution right now. The trouble there of course is that the "one step up" from shadow in the "standard" setup is npm, which dumps me in node land, which not only makes me sad, but means not only do I need a new process but I need a new JVM...
@thheller Yeah, I saw that. The run option I actually didn't know about. Is this documented anywhere? Does it just clj
with shadow on the classpath or is there more to it than that?
I do want to reiterate by the way, how great shadow-cljs is. I am really just working on a toy project here, playing with the tools and seeing how cljs to the browser looks in 2019 because i've been buried in backend stuff for a while. Clojurescript and the ecosystem around it has come on a long way apparently, and I appreciate greatly the part you have played in that. Cheers 🙂