shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
sh54 2021-05-02T06:47:47.116400Z

I am getting an issue that when some required in javascript file changes, the final product shadow-cljs produces does not change.

sh54 2021-05-02T06:47:55.116600Z

I have some fork of some javascript project that I am working on then “compiling” and copying over relevant js files into my clojure project. shadow-cljs is certainly noticing that this happens and starts compiling and hot reload triggers. However the actual change in functionality does not get picked up. If I reload the page there is still no change. But if I go to the shadow-cljs dashboard and press stop then watch then the change appears.

sh54 2021-05-02T06:48:06.116800Z

Not sure if this is a general issue or something very specific here. What I am actually changing is a c++ file that gets compiled to js via emscripten. For this project the wasm binary is just base64 encoded and dumped into the js file. So when I am changing something the only change in the js file is that some def var wasmBinaryFile="data:application/octet-stream;base64,ABCD"; is getting altered. Just for context.

thheller 2021-05-02T07:31:36.117200Z

@slack1003 hard to say without knowing how you actually include those files. why not load the actual .wasm file over the ajax or so? inlining it via base64 will make it needlessly large?

sh54 2021-05-02T07:34:04.118800Z

I agree that it should be compiled to its own file and loaded. I am just on a fork. It is something I have thought of changing. There is a certain simplicity in just having a single js file include though

sh54 2021-05-02T07:34:17.119100Z

I am requiring it in via (:require #?(:cljs ["imgui-js" :as imgui]))

thheller 2021-05-02T07:36:19.120100Z

so its in node_modules/imgui-js? node_modules files are not hot-reloaded. to invalidate the cache it has you can touch node_modules/imgui-js/package.json which will then trigger a recompile

sh54 2021-05-02T07:38:34.121600Z

so I have kept it out of the node_modules right now. in my own build it just copies it into a directory on the class path. then in my shadow-cljs config I do :js-options {:resolve {"imgui-js" {:target :file, :file "src/cljc/imgui/imgui.js"}}}

thheller 2021-05-02T07:39:04.122400Z

do NOT use :resolve if you have stuff on the classpath anyways

sh54 2021-05-02T07:39:13.122600Z

not sure if that is best practice by any means but seems easiest for development

sh54 2021-05-02T07:39:15.122900Z

k

thheller 2021-05-02T07:39:18.123100Z

just use (:require ["/imgui/imgui.js" :as imgui]) https://shadow-cljs.github.io/docs/UsersGuide.html#classpath-js

sh54 2021-05-02T07:39:23.123200Z

i’ll get that changed then

sh54 2021-05-02T07:39:57.123800Z

thanks, i’ll see if that helps.

sh54 2021-05-02T07:44:13.126400Z

ahh, I remember there was a particular reason for why i did that! There is a separate js file I include that I have done that style: #?(:cljs ["/imgui/imgui_demo.js" :as imgui-demo]) . And it tries to do require('imgui-js') to get in that same file. Since it looked like I needed that resolve bit to make imgui_demo.js happy i just used that in my cljc file too.

sh54 2021-05-02T07:44:59.127400Z

can I leave the :resolve in the shadow cljs settings to keep the other include happy and move to use (:require ["/imgui/imgui.js" :as imgui]) in my cljc file then?

thheller 2021-05-02T07:45:20.127800Z

sorry I don't have a clue what you are doing and would need to see some actual code

thheller 2021-05-02T07:45:49.128500Z

otherwise there are far too many unknowns for me but it looks like you are trying to hack this together in the wrong way

thheller 2021-05-02T07:46:20.129Z

using :resolve for packages you already control is almost guaranteed to be wrong

sh54 2021-05-02T07:48:52.130900Z

maybe… main issue is I don’t have “full” control. Just on a fork to add some functionality. and if I don’t have to change some of the build fundamentals in that project then I would like to leave them be and deal with things on the clojure side.

sh54 2021-05-02T07:49:32.131700Z

sorry if my explanation here is lacking. I can get back with a better summary of how things are wired together

thheller 2021-05-02T07:50:04.132500Z

wasm in general requires rather specific "glue" code that currently isn't very bundler friendly

sh54 2021-05-02T07:50:14.132900Z

It all works fine outside of the hot reload.

thheller 2021-05-02T07:50:47.134Z

yeah, I'm gonna need to see some code to comment on that

sh54 2021-05-02T07:51:14.134300Z

Yeah I have done my own wasm tests a while back and I remember having quite a few issues with the glue code then.

sh54 2021-05-02T08:23:57.134600Z

k incoming essay: 🙂

sh54 2021-05-02T08:23:59.134800Z

So I include https://github.com/flyover/imgui-js as a git submodule.

sh54 2021-05-02T08:24:02.135100Z

I have a little build tooling that just runs its make file and copies the relevant compiled js files over somewhere into my class path.

sh54 2021-05-02T08:24:05.135300Z

Here I guess I may be going wrong and that I should register it as a node module. Not sure how to do that but I’m sure I can figure it out if thats the way to go.

sh54 2021-05-02T08:24:08.135500Z

Anyway, the project compiles down to two important files. imgui.js really is the thing that does everything. imgui_demo.js is several thousand lines of js that is recommended to include when developing since it both serves as documentation and a settings tweaker. Again all not really my code, though I can always change things up if necessary in the fork.

sh54 2021-05-02T08:24:12.135800Z

It seems like it is the interplay between those two files that causes some issues with shadow-cljs. The top of imgui_demo.js has one of those standard check all sorts of places to figure out how to require imgui.js.

sh54 2021-05-02T08:24:18.136Z

// imgui_demo.js top
    (function (global, factory) {
        typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('imgui-js')) :
        typeof define === 'function' && define.amd ? define(['exports', 'imgui-js'], factory) :
        (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ImGui_Demo = {}, global.ImGui));
    }(this, (function (exports, ImGui) { 'use strict';
    ... );

sh54 2021-05-02T08:24:32.136200Z

The important thing being the require('imgui-js') it seems?

sh54 2021-05-02T08:24:55.136500Z

Right now I really only include them in my wrapper files.

sh54 2021-05-02T08:24:57.136700Z

What works with the requires is when I do the following:

sh54 2021-05-02T08:25:03.136900Z

(:require
      #?(:cljs ["imgui-js" :as imgui])
      ;;#?(:cljs ["/imgui/imgui.js" :as imgui]) ;; this does not work!
      #?(:cljs ["/imgui/imgui_demo.js" :as imgui-demo]))

sh54 2021-05-02T08:25:07.137100Z

Then everything builds fine. But alterations to the js file do not get picked up and require a stop and watch. But hardly the end of the world.

sh54 2021-05-02T08:25:10.137300Z

and in my shadow-cljs config include:

sh54 2021-05-02T08:25:14.137500Z

:js-options {:resolve {"imgui-js" {:target :file :file "src/cljc/imgui/imgui.js"}}}

sh54 2021-05-02T08:25:19.137700Z

Now I have tried with the following instead:

sh54 2021-05-02T08:25:25.137900Z

(:require
      #?(:cljs ["/imgui/imgui.js" :as imgui])
      #?(:cljs ["/imgui/imgui_demo.js" :as imgui-demo]))

sh54 2021-05-02T08:25:28.138100Z

Right now this results in imgui.js somehow being included twice! The imgui_demo.js file seems to get its own copy.

sh54 2021-05-02T08:25:30.138300Z

I can see this by looking at my shared.js which shadow-cljs is compiling.

sh54 2021-05-02T08:25:33.138500Z

In this setup it has the lines:

sh54 2021-05-02T08:25:37.138700Z

SHADOW_ENV.evalLoad("module$imgui$imgui.js", true , ......
    SHADOW_ENV.evalLoad("module$src$cljc$imgui$imgui.js", true , ......

sh54 2021-05-02T08:25:41.138900Z

so two copies of imgui.js which compiles fine but crashes at runtime.

sh54 2021-05-02T08:25:44.139100Z

I guess I could try to keep them in my node_modules instead? Maybe it will give better results. Though it feels like it should be possible to handle them being files in the class path too.

thheller 2021-05-02T08:33:54.139500Z

first of all forget about :resolve. as I said that this is NOT relevant here

thheller 2021-05-02T08:34:28.140100Z

WHY did you add it in the first place? WHY do you think require('imgui-js') is a problem?

thheller 2021-05-02T08:35:28.140600Z

again this is would be much much much much much easier if you just put the code into some repo so I can look at it together

sh54 2021-05-02T08:45:09.141600Z

Without the :resolve bit then shadow cljs is not able to build anything: X Compilation failed.

The required JS dependency "imgui-js" is not available, it was required by "imgui/imgui_demo.js".

sh54 2021-05-02T08:46:09.142600Z

How I have things required in is the only way that the project is building, and not throwing at runtime, and not double including imgui.js

sh54 2021-05-02T08:47:05.143700Z

I can try to reproduce in a simpler repo.

thheller 2021-05-02T08:47:21.144300Z

WHERE is imgui-js from? it is not the file you generate from the wasm right? did you modify that file in any way?

sh54 2021-05-02T08:48:05.145200Z

as stated before the require('imgui-js') part is in the helper files like imgui_demo.js that are also a part of that project

thheller 2021-05-02T08:48:30.146Z

I asked where the file is from, not where it was included from

thheller 2021-05-02T08:48:58.146800Z

src/cljc/imgui/imgui.js WHERE is this from? is this also wasm generated code?

sh54 2021-05-02T08:49:12.147100Z

got you

sh54 2021-05-02T08:49:52.148200Z

that is just copied from the build output of the project. Copied unmodified like all the rest of the build artifacts I am relying on

thheller 2021-05-02T08:50:08.149Z

ok, so you have two files in a directory?

sh54 2021-05-02T08:50:20.149200Z

yup

thheller 2021-05-02T08:51:16.150200Z

ok, my first suggestion would be to just modify the generated demo.js to replace require('imgui-js') with require('./imgui.js') instead

thheller 2021-05-02T08:51:33.150500Z

since you are generating that file anyways that should be trivial to add

sh54 2021-05-02T08:51:54.151100Z

yeah I can try that

thheller 2021-05-02T08:52:04.151300Z

the goal of this is to make everything self-contained so it doesn't rely on build config and the code expressing its intent correctly

thheller 2021-05-02T08:53:04.153100Z

right now require('imgui-js') is interpreted as "require the imgui-js npm library" but it is not an npm library. avoid resolve to fix this, much better to fix it in the source directly

sh54 2021-05-02T08:53:16.153300Z

totally. I guess you have to deal with all sorts of different js files doing some funky things when it comes to dependencies sometimes 😕

thheller 2021-05-02T08:54:54.153900Z

the problem really is :resolve to :file. I should probably remove that altogether since it is basically never the correct way to do anything

sh54 2021-05-02T08:56:43.154100Z

good to know

sh54 2021-05-02T09:04:30.155900Z

hey, so your suggesting on changing the require to ./imgui.js works nicely. I eliminated my use of :js-options :resolve too. just going to alter my tooling to alter the files then I can check if hot reload works

sh54 2021-05-02T09:04:43.156200Z

thanks a bunch for your help and time

sh54 2021-05-02T09:05:17.157100Z

I was going in with the idea of not altering the build artifacts and fudging things on the clojure side

thheller 2021-05-02T09:05:18.157300Z

hot-reload was likely broken because of the :resolve

thheller 2021-05-02T09:05:56.158200Z

can you send me the generated demo.js file? I'd be interested to see how that looks in full

sh54 2021-05-02T09:06:07.158400Z

but it looks like the way to go is to provide files with the right refs

sh54 2021-05-02T09:06:19.158600Z

sure

sh54 2021-05-02T09:07:07.159Z

the two files where imgui_demo.js has been patched

thheller 2021-05-02T09:10:47.160200Z

hot-reload is probably going to be a problem. the code doesn't really allow it. but recompile and browser reload should be ok without :resolve

thheller 2021-05-02T09:11:13.160900Z

the caching problem should be gone though

sh54 2021-05-02T09:12:34.162100Z

yeah as long as the browser reload is all good then that is plenty good enough! I figured hot reload would be a problem given the important stuff happens in the wasm

thheller 2021-05-02T09:13:12.162500Z

would be a little easier to accomplish without the wasm inlined into the source

sh54 2021-05-02T09:33:13.167800Z

yeah the recompile is now working! thanks again for the help

👍 1
Sam Ritchie 2021-05-02T20:02:04.171900Z

hey all.. I am having the toughest time converting to shadow-cljs from lein, for my CIDER repl workflow. I run cider-jack-in-cljs, select shadow-cljs then shadow as the repl type,

Sam Ritchie 2021-05-02T20:02:21.172400Z

and everything boots, but then when I try to eval a form, I see

No available JS runtime.
See <https://shadow-cljs.github.io/docs/UsersGuide.html#repl-troubleshootingnil>

Sam Ritchie 2021-05-02T20:03:00.172700Z

my goal is to get a node repl running

Sam Ritchie 2021-05-02T20:03:38.173300Z

so… MAYBE I am supposed to run the generated file and it will get a repl going? except this is my test target, so it probably will not…

Sam Ritchie 2021-05-02T20:06:19.174200Z

I must be missing something obvious here, for getting up a workflow that uses node to evaluate forms without needing a browser. sorry for the fumbling question… I’ve been at CLJS a long time and build stuff can still be mystifying

Sam Ritchie 2021-05-02T20:21:00.174900Z

node-repl is saving me… before it was failing with an error I can’t find, but I may be in business!! apologies for the flailing, I think I’m good 🙂