Fork me on GitHub
#shadow-cljs
<
2019-06-11
>
tony.kay00:06:25

Did something change with respect to modules that isn’t documented? I can build a code-split app with the last of the shadow 2.7 series, but if I use latest it tells me it cannot find my module.

tony.kay00:06:00

when I look at shadow.loader.mm.moduleInfoMap is it empty

tony.kay00:06:04

It does build an output file though:

SHADOW_ENV.load({}, ["book.demos.dynamic_ui_main.js","shadow.module.ui-main.append.js"]);

thheller07:06:53

@tony.kay only the initialization logic changed. in general that should only be an issue if you use shadow.loader before it was initiated

tony.kay15:06:07

But I was using cljs.loader, so I thought that didn’t apply. It’s ok I guess. I’m making shadow-cljs a requirement in Fulcro 3, so it won’t matter 🙂

thheller15:06:46

you can use cljs.loader thats fine

thheller15:06:58

its just a timing issue. can't use it before its initialized

tony.kay15:06:13

I’m triggering it from a user mouse button press

thheller15:06:17

if you just use :init-fn as intended it won't be a problem

tony.kay15:06:24

ok, I’ll do that. Thanks 🙂

thheller15:06:26

hmm that should definitely work

tony.kay15:06:34

that was my thought 😉

thheller15:06:15

I'll try to take a look later

tony.kay15:06:49

in the meantime, I’ll add init fn 🙂

tony.kay15:06:26

Ah, is this new?

You only need to add :module-loader true to your build config. The loader will always be injected into the default module (the one everything else depends on).

tony.kay15:06:00

I didn’t have that

thheller15:06:03

no that was always there

tony.kay15:06:45

I think that fixed it. My bad, it seems 🙂

tony.kay15:06:15

it worked without that option in the 2.7 series for some reason

thheller15:06:23

hmm yeah it should be optional but I need to figure out a better way to see if its needed automatically first

thheller07:06:07

I'd recommend using :init-fn which ensures that doesn't happen

thheller07:06:21

otherwise you might need to call (shadow.loader/init "") manually wherever your init happens?

thheller07:06:32

can't find the actual init for the book code?

thheller07:06:04

@stefan.age font files are not related to CLJS compilation in any way so any non-webpack example of adding fonts will work

thheller07:06:27

ie. a tiny bit of CSS @font-face

p-himik09:06:37

I just an interesting error on a new project:

The required JS dependency "process" is not available, it was required by "node_modules/prop-types/checkPropTypes.js".
The peculiar thing is that in an old project, prop-types is also used by some library, but it works fine.

p-himik09:06:52

Although I have no idea how it's all supposed to work given that the apparent source of the error is this line: if (process.env.NODE_ENV !== 'production') {. I think process.env is available only for nodejs targets, not for browser targets. And yet the old project somehow works.

thheller09:06:19

install shadow-cljs in the project.

p-himik09:06:26

That worked, thank you. But how is that supposed to work in production, given that the manual recommends installing shadow-cljs as a dev dependency?

thheller09:06:48

dev dependency is fine

thheller09:06:27

having only the global install is not fine

p-himik09:06:59

I don't think that's the case. I just removed node_modules, ran npm i --production=true, and finally shadow-cljs release main. It gave me the same error about missing process.

thheller09:06:02

uhm don't do that

thheller09:06:08

npm i --production=true

thheller09:06:16

it doesn't affect the build in any way

thheller09:06:33

and you need dev dependencies to build stuff

p-himik09:06:57

Oh, right. I remember now reading somewhere that you don't agree with the split of prod and dev dependencies because CLJS compilation deals with dead code anyway. But there's some virtue to it still. E.g. there are dependencies required only for testing, profiling, debugging, tracing. And while they won't end up being in the released JS file, their installation takes time. And if we think about CLJ dev dependencies, they also take space when you don't ship your whole app in a single uberjar.

thheller09:06:23

no you are misunderstanding how things work

thheller09:06:18

think about it for one second. assuming you don't have the global shadow-cljs install (which you shouldn't rely on anyways) and you only have shadow-cljs in your dev dependencies (which you should)

thheller09:06:32

how would you invoke shadow-cljs with npm i --production=true

thheller10:06:06

having shadow-cljs installed in the project was pretty much ALWAYS required. it just sort of worked sometimes if you had the global install

thheller10:06:04

production=true is only for runtime for node apps, nothing that requires building will ever work with that

p-himik10:06:45

I see, thanks. > how would you invoke shadow-cljs with npm i --production=true lein yada-yada-yada. Or via the code, in my case: juxt/kick.apha - we've talked about it some time ago. > having shadow-cljs installed in the project was pretty much ALWAYS required So ideally, we should have 3 scopes instead of just prod and dev: running in production, running in development, building. And the shadow-cljs dependency would fit only in the building scope, right?

thheller10:06:51

to be accurate here. it isn't the missing shadow-cljs that causes the issue here. it is the missing https://github.com/webpack/node-libs-browser which shadow-cljs depends on (eg. for process)

thheller10:06:47

dunno why you'd split development and building. "development" seems to cover that in my mind

thheller10:06:29

in case of browser things. NOTHING is required for "running in development" since the produced build output contains everything

thheller10:06:44

don't make things more complicated than they already are 😛

thheller10:06:50

just keep it at prod/dev

p-himik10:06:54

Yeah, I probably described it poorly. I meant it more like a composition thing. The building scope is extracted to a separate one because it's common for every other scope. And the development scope just always includes the building one, yes. > just keep it at prod/dev But that's exactly what I'm trying to do! 😄 I just didn't realize that including shadow-cljs as a dev dependency doesn't mean that it's useful only during the development. So in my case, I'll probably just move it to the main list of dependencies, to make the dev list contain only the things that are not even supposed to be downloaded for the production build.

thheller10:06:28

no don't do that

thheller10:06:21

well .. I guess you can but it wouldn't be idiomatic in case you ever build a node app

thheller10:06:19

shadow-cljs release is still a development thing. only the output is a production thing.

p-himik10:06:25

Oh. I must admit I've never touched node. And hopefully, never will. > shadow-cljs release is still a development thing So the production image building process is considered a development step? And "production" is only "running the production build"? See, that's why the three hypothetical scopes are still somewhat useful. I guess it's just profiles in terms of lein/`deps.edn`, but AFAIK package.json doesn't support anything like it. I just remembered another point towards not downloading dev dependencies during the production build. Apart from the saved space, it's also a safeguard against including something dev in the production env.

thheller10:06:59

not installing dev dependencies to build is just not an option

thheller10:06:45

if you want to split into more profiles you can do that but even for deps.edn you can't build an uberjar without some kind of dev dependency

thheller10:06:23

and putting things into dev dependencies IS you safeguard against installing dev stuff in production

thheller10:06:54

we are talking about the browser here anyways so it doesn't make sense to talk about production deps in any way

thheller10:06:03

since the browser can't use your node_modules folder anyways

thheller10:06:06

doesn't matter whats in it

p-himik10:06:22

> you can't build an uberjar without some kind of dev dependency Interesting point, thanks. Looking into all kinds of uberjars is still on my radar. So far, the experience has been far from pleasant. > since the browser can't use your node_modules folder anyways > doesn't matter whats in it Yes, I realize that. But I don't quite realize how that could ever work without profiles and without dead code elimination. So, generally speaking, how does that even work in the browser JS world? Suppose I have some... I don't know, React debugging library that must be built into the application code in order to work. Obviously, you don't want to use it in production at all. But at the same time, if you have to use dev dependencies during the release image build process, how do you prevent that debugging library from ending up in the production code?

thheller10:06:33

well that where the if (process.env.NODE_ENV !== 'production') { comes into play

thheller10:06:44

that lets you do conditional requires in node

p-himik10:06:06

No-no-no, browser JS.

thheller10:06:12

that is browser JS

thheller10:06:29

webpack AND shadow-cljs compile that away

thheller10:06:47

so that only the conditional requires are removed

thheller10:06:02

basically it is inline as a constant

thheller10:06:15

if ("development" !== 'production') {

thheller10:06:29

the closure compiler then takes care of removing the "dead" code

p-himik10:06:00

That's why I wrote "and without dead code elimination" 🙂 Is the DCE our only hope here? Did things not work at all before it has been brought into the JS ecosystem?

thheller10:06:12

hehe the fun times are ahead of us since with ESM you can't do the conditional require anymore

p-himik10:06:22

I feel like something like that is going on in the Python world right now, with requirements.txt. Since there are no scopes and profiles anywhere, people just write multiple files with all kinds of suffixes, and then write scripts to use different files in different environments.

thheller10:06:24

so they have to come up with new fun ways to do things

p-himik10:06:44

Oh wow. The fun never ends, does it.

thheller10:06:58

yeah. so far it looks like this is our future https://github.com/WICG/import-maps

😱 4
thheller10:06:32

but its still planning stages. nothing implemented yet.

thheller10:06:24

the other path using dynamic import() is even more fun ..

thheller10:06:32

JS is a complete mess 😞

thheller10:06:03

to be fair though conditional requires aren't exactly easy or nice in CLJS

p-himik10:06:03

Well at least they bring this point there. > JS is a complete mess 😞 And it pains me to see that CLJS cannot avoid some of it, even if we forget about imports at all. But to be honest, I'm still reluctant to just throw everything together during the release process. Imagine you have hundreds of MBs of libraries that are only useful during debugging. And that DCE has some bugs. What would you do?

thheller10:06:41

first of all things won't compile at all if you are relying on DCE to remove things

thheller10:06:52

(if the deps are missing)

p-himik10:06:14

Oh no, I don't. There are dev preloads.

thheller10:06:22

then you didn't rely on DCE 😉

p-himik10:06:41

God dammit.

p-himik10:06:33

So if a library is in node_modules and nothing ever imports that library, it won't end up in the release JS files even if DCE is not used?

thheller10:06:53

no just like CLJS only things that are actually required will be used in a build

thheller10:06:15

just having files sitting there does nothing

p-himik10:06:04

Hmm. I guess I got confused by Java/CLJ. Hard to say at this point.

p-himik11:06:54

Anyway, thank you for the discussion. It has definitely been fruitful for me - now I know how to shave this yak a bit better.

thheller11:06:22

to be fair here the java/CLJ parts could use some yak shaving as well

thheller11:06:50

we pretty much are content with including an entire dependency in an uberjar

thheller11:06:01

even if we only used one class out of potentially thousands

p-himik11:06:35

Does uberjar'ing include only the dependencies that are explicitly imported? So if I use conditional imports, do I somehow have to explicitly make sure that the required dependencies end up being in the uberjar? Regarding single classes, or functions in case of CLJ - yes, Rich Hickey had a talk on it, a quite good one.

thheller11:06:02

no uberjar just includes everything in the source .jar file

thheller11:06:21

there are tools that remove unused stuff but they don't work for CLJ

p-himik11:06:57

Ah. So it's even worse. If I forget to remove something from deps.edn and never use it, it will still be there.

thheller11:06:23

although only in size, they still won't be loaded at runtime

thheller11:06:29

just dead bytes in the uberjar

mccraigmccraig15:06:21

i'm currently looking at moving my boot driven cljs compilation over to shadow... and wondering whether to keep boot around or not. what other tools do people use for doing things like [a] dynamic configuration of closure-defines (from e.g. envvars) and [b] less compilation

thheller15:06:25

people mostly just use shadow-cljs

thheller15:06:01

this lets you override closure-defines from the CLI, similar to env vars I guess https://shadow-cljs.github.io/docs/UsersGuide.html#config-merge

mccraigmccraig15:06:17

ah, cool, i can definitely use that

mccraigmccraig15:06:21

and for things like less/sass compilation, do people generally use node stuff directly ?

idiomancy19:06:01

is there an equivelant to webpacks copy-webpack-plugin thay copies over static assets to the output directory? I want to put some ES6 node_modules during build over there

idiomancy19:06:50

actually I suppose I need the html plugin... the one that recursively converts imports in html files. but then again, I may be able to simply use webpack :thinking_face:

idiomancy19:06:24

the ES6 stuff never interacts with the cljs stuff

credulous19:06:48

Hi! I’m trying to get a project working using shadow-cljs and the cli/deps tools. It’s a re-frame app. Everything seems to be working as expected… except I can’t get the actual browser DOM to update when I make changes to the source files.

credulous19:06:05

Here’s the app core.cljs:

credulous19:06:14

(ns alexandria.core
   (:require
     [reagent.core :as reagent ]
     [re-frame.core :as rf ]
     [day8.re-frame.http-fx]
     [alexandria.events]
     [alexandria.subs]
     [alexandria.routes :as routes]
     [alexandria.views :as views]
     )
   )

 (defn main-panel
   []
   [:h1 "Alexandria"]

 ;  (let [active-panel (rf/subscribe [:active-panel])]
 ;    [views/show-panel @active-panel]
 ;      [:div [:h2 "Alexandria "]]
 ;    )
 )

 (defn mount-root
   []
   (rf/clear-subscription-cache!)
   (println "mounting root")
   (reagent/render [main-panel]
                   (.getElementById js/document "app")
                   ))

 (defn ^:export init
   []
 ;  (routes/app-routes)
   (println "Initializing")
   (rf/dispatch-sync [:initialize-db])
   (mount-root))

credulous19:06:44

I’ve reduced it to just putting a h1 on the page. That works. When I change the string “Alexandria”, or change the h1 to an h2, shadow compiles it fine, the shadow-cljs dashboard page shows a compilation, and the shadow-cljs icon at the bottom left of the browser window appears. But the text on the page doesn’t change - the actual DOM doesn’t get updated.

credulous19:06:25

I’m making some boneheaded mistake or omission, but I haven’t been able to find it.

isak19:06:31

@credulous in your shadow-cljs.edn, do you have something like {:devtools {:after-load alexandria.core/mount-root}} ?

isak19:06:36

i'd try that, or code changes wont re-render app, AFAIK

isak19:06:03

in case you don't already have that key, the path is [:builds <something> :devtools ...]

credulous19:06:19

Yup, adding now…

credulous19:06:52

That did the trick, thanks!

4
lxsameer20:06:25

hey folks, I'm using re-frame with shadow-cljs, when i update my component code and save it, hot code reload works and i can see in the console that my namespace re-evaluates but the dom doesn't update, i have to do a full refresh to see the dom changes

lxsameer20:06:37

how should i debug this

thheller20:06:10

@lxsameer see the above conversation. do you have a lifecycle (ie. after-load) configured to re-render your app? https://shadow-cljs.github.io/docs/UsersGuide.html#_lifecycle_hooks

thheller20:06:16

mount-root in the above example

lxsameer20:06:31

interesting

lxsameer20:06:12

actually it doesn't work in my case, apparently it's a caching issue, i changed the namespace but the log messages are still for the old one

thheller20:06:28

look at the browser console. shadow-cljs will tell you what its doing. the rest is up to you

lxsameer20:06:45

if i block my main namespace would it recompile the whole project on each change ?

thheller20:06:14

main namespace?

lxsameer20:06:44

i don't get what you mean by "shadow-cljs will tell you what its doing. the rest is up to you"

lxsameer20:06:58

it's connected by it shows no reaction to changes

thheller20:06:55

is there a warning in the bottom left?

thheller20:06:08

whats with all the 404?

lxsameer20:06:17

that's a css file

thheller21:06:52

you are using a regular watch I presume?

thheller21:06:56

what does that log show?

lxsameer21:06:17

the interesting this here is that , I removed the console.log expression for line 4 and 5

lxsameer21:06:11

I'm using shadow/watch fn

lxsameer21:06:37

the log stuck in compiling

lxsameer21:06:40

which is weird

thheller21:06:13

dunno what you are doing. it definitely shouldn't be stuck

lxsameer21:06:24

i'm stoping the worker

thheller21:06:29

try restarting maybe? is you CPU at max?

thheller21:06:41

infinite loop or something?

thheller21:06:50

one core at max?

lxsameer21:06:36

i don't think so

lxsameer21:06:55

no all the cores are working but not more that 20%

lxsameer21:06:05

stop-worker stuck as well

thheller21:06:21

call (shadow.cljs.devtools.server/reload!)

lxsameer21:06:43

I had to close the session

lxsameer21:06:56

the problem seems to be solved, i just fired up a new repl

lxsameer21:06:37

is there a way to manually invalidate the cache for a namespace ?

thheller21:06:21

touch src/foo/bar.cljs?

lxsameer21:06:08

no I mean via clojure, I was reading about the compiler cache in the docs

thheller21:06:30

why would you need to?

lxsameer21:06:17

apparently if I want to use macros with side effects i should black list the namespace right

lxsameer21:06:44

sorry add the ns in :cache-blockers

lxsameer21:06:10

so shadow won't cache that ns

thheller21:06:18

or use (ns ^:dev/always foo.bar)

lxsameer21:06:03

ok in this case it make sense to let the developer invalidate the cache for that ns in specific cases

lxsameer21:06:44

for example I know when my macro would do the side effect and i can just invalidate the cache in that situation otherwise i still can benefit form the cache

thheller21:06:35

that would be possible but currently there is no API for that

grant23:06:59

Does anybody have a suggestions for trying to debug an npm package that will give me an object when I :require it, but doesn't seem to have the export I am looking for?

-->
(require '["basicchart" :as bc :refer (BasicChart)])
-->
-->
bc
-->
#js {...}
-->
-->
BasicChart
-->
nil
-->

lilactown23:06:17

@grant it would help to know what’s inside the object 😛

lilactown23:06:27

I can’t find the lib you’re talking about on npm

grant23:06:14

That one was more an example. I can't share the code on the actual package, unfortunately, and I only have the minimized version myself.