This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-06-26
Channels
- # announcements (21)
- # babashka (31)
- # beginners (64)
- # calva (51)
- # clerk (4)
- # cljdoc (7)
- # clojars (2)
- # clojure (63)
- # clojure-denmark (2)
- # clojure-europe (15)
- # clojure-nl (2)
- # clojure-norway (22)
- # clojure-sweden (5)
- # clojure-uk (15)
- # data-science (8)
- # datomic (23)
- # graalvm (6)
- # honeysql (3)
- # hoplon (3)
- # hyperfiddle (11)
- # jobs-discuss (6)
- # lsp (4)
- # pathom (26)
- # reitit (4)
- # releases (2)
- # shadow-cljs (41)
- # spacemacs (2)
- # xtdb (1)
I'm building a clojure app with some artifacts compiled using shadow-cljs. I try to build it in some different docker images. Is it somehow possible to first do all the needed dependency fetching in a node container, and then do a releasebuild in a clojure/leiningen-container? - is it possible to a releasebuild without triggering npm, given that all dependencies is already in place, somehow?
why make it so complicated? shadow-cljs doesn't care where the node_modules
folder comes from and it doesn't need npm for anything as long as your dependencies are present
So a lein-uberjar prep-step to compile the relase builds like:
:profiles {:gen {:prep-tasks ^:replace []}
:uberjar {:prep-tasks ["clean" ["clean"]
"compile" ["with-profile" "+gen,+dev" "run" "-m" "shadow.cljs.devtools.cli" "--npm"
"release" "adminspa" "userspa"]]
:omit-source true
:aot :all
:uberjar-name "uberapp.jar"
:source-paths ["env/prod/clj"]
:resource-paths ["env/prod/resources"]}
should not need any node/npm binaries availiable at all, as long as all dependencies are availiable (in node_module and perhaps in jvm classpath)? (That is what I expect, but I might be wrong)
you can skip the --npm
flag, it isn't needed when you are not actually running via npm
I think I still need the npm
on my path (or something that returns 0 when called), since it seems to be triggered anyway:
https://github.com/thheller/shadow-cljs/blob/673e2580889e37f150c6d3afb71e935328ba49e4/src/main/shadow/cljs/devtools/cli_actual.clj#L141-L142
The stacktrace says
running: npm install --save --save-exact @js-joda/[email protected] @js-joda/[email protected] @js-joda/[email protected]
IOException: Cannot run program "npm" (in directory "."): error=2, No such file or directory
java.lang.ProcessBuilder.start (ProcessBuilder.java:1170)
java.lang.ProcessBuilder.start (ProcessBuilder.java:1089)
shadow.cljs.devtools.server.npm-deps/install-deps (npm_deps.clj:113)
shadow.cljs.devtools.server.npm-deps/install-deps (npm_deps.clj:75)
shadow.cljs.devtools.server.npm-deps/main (npm_deps.clj:176)
shadow.cljs.devtools.server.npm-deps/main (npm_deps.clj:162)
shadow.cljs.devtools.cli-actual/main (cli_actual.clj:141)
shadow.cljs.devtools.cli-actual/main (cli_actual.clj:132)
clojure.core/apply (core.clj:671)
clojure.core/apply (core.clj:662)
shadow.cljs.devtools.cli-actual/-main (cli_actual.clj:219)
shadow.cljs.devtools.cli-actual/-main (cli_actual.clj:217)
clojure.lang.Var.applyTo (Var.java:705)
clojure.core/apply (core.clj:667)
clojure.core/apply (core.clj:662)
shadow.cljs.devtools.cli/-main (cli.clj:75)
shadow.cljs.devtools.cli/-main (cli.clj:67)
clojure.lang.Var.invoke (Var.java:399)
user/eval140 (form-init4803926420733755391.clj:1)
user/eval140 (form-init4803926420733755391.clj:1)
clojure.lang.Compiler.eval (Compiler.java:7194)
clojure.lang.Compiler.eval (Compiler.java:7184)
clojure.lang.Compiler.load (Compiler.java:7653)
clojure.lang.Compiler.loadFile (Compiler.java:7591)
clojure.main/load-script (main.clj:475)
clojure.main/init-opt (main.clj:477)
clojure.main/init-opt (main.clj:477)
clojure.main/initialize (main.clj:508)
clojure.main/null-opt (main.clj:542)
clojure.main/null-opt (main.clj:539)
clojure.main/main (main.clj:664)
clojure.main/main (main.clj:616)
clojure.lang.Var.applyTo (Var.java:705)
clojure.main.main (main.java:40)
Caused by:
IOException: error=2, No such file or directory
java.lang.ProcessImpl.forkAndExec (ProcessImpl.java:-2)
java.lang.ProcessImpl.<init> (ProcessImpl.java:295)
java.lang.ProcessImpl.start (ProcessImpl.java:225)
java.lang.ProcessBuilder.start (ProcessBuilder.java:1126)
java.lang.ProcessBuilder.start (ProcessBuilder.java:1089)
shadow.cljs.devtools.server.npm-deps/install-deps (npm_deps.clj:113)
shadow.cljs.devtools.server.npm-deps/install-deps (npm_deps.clj:75)
shadow.cljs.devtools.server.npm-deps/main (npm_deps.clj:176)
shadow.cljs.devtools.server.npm-deps/main (npm_deps.clj:162)
shadow.cljs.devtools.cli-actual/main (cli_actual.clj:141)
shadow.cljs.devtools.cli-actual/main (cli_actual.clj:132)
clojure.core/apply (core.clj:671)
clojure.core/apply (core.clj:662)
shadow.cljs.devtools.cli-actual/-main (cli_actual.clj:219)
shadow.cljs.devtools.cli-actual/-main (cli_actual.clj:217)
clojure.lang.Var.applyTo (Var.java:705)
clojure.core/apply (core.clj:667)
clojure.core/apply (core.clj:662)
shadow.cljs.devtools.cli/-main (cli.clj:75)
shadow.cljs.devtools.cli/-main (cli.clj:67)
clojure.lang.Var.invoke (Var.java:399)
user/eval140 (form-init4803926420733755391.clj:1)
user/eval140 (form-init4803926420733755391.clj:1)
clojure.lang.Compiler.eval (Compiler.java:7194)
clojure.lang.Compiler.eval (Compiler.java:7184)
clojure.lang.Compiler.load (Compiler.java:7653)
clojure.lang.Compiler.loadFile (Compiler.java:7591)
clojure.main/load-script (main.clj:475)
clojure.main/init-opt (main.clj:477)
clojure.main/init-opt (main.clj:477)
clojure.main/initialize (main.clj:508)
clojure.main/null-opt (main.clj:542)
clojure.main/null-opt (main.clj:539)
clojure.main/main (main.clj:664)
clojure.main/main (main.clj:616)
clojure.lang.Var.applyTo (Var.java:705)
clojure.main.main (main.java:40)
this only runs if there is no package.json
present with those packages already listed
ok, great!
OOI why does shadow use a https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/cljs/devtools/server/util.clj#L224 without conveying bindings?
git blame says to avoid a java.lang.NoClassDefFoundError:: https://github.com/thheller/shadow-cljs/commit/a087d6846357e0870f2737044be015fef680e801 https://github.com/thheller/shadow-cljs/issues/273
Yeah I know there are many ways of doing what I wanted, however given the constraints it was the most expedient way of achieving my goal and I was surprised it didn’t work… made me question my understanding of thread local bindings though which is good 🙂
Would https://github.com/thheller/shadow-cljs/pull/1189 be an acceptable PR for those that want to live dangerously?
Well, the above should ™️ be a clean refactor…
As it stands one can’t use dynamic vars inside build hooks running as part of a watch as the bindings are not conveyed to the thread when it’s created.
As to why I want to use a dynamic var in a hook… I’m working on a codebase that is moving towards being a monorepo and there is some interim kludging with dynamic vars in the build process. However they don’t work in hooks. I know there are many ways to in the end achieve what I want, dynamic vars are just the quickest and smallest way to do it. The above PR means there’s a much smaller with-redefs
needed to do it without affecting any other users of shadow.
Happy if you want to close the PR, it’s not an important PR and not one that is preventing me from doing anything really.
what are you doing in that hook? I regret adding hooks, since 99% of the time they are used they are used for stuff they were not meant for
adding a dynamic var to be accessed in a hook makes me kinda certain it should not be a hook in the first place
The hooks are generally file system access, creating assets and resources (some that do actually need information about build state and created js files in particular). The monorepo means file paths change, build configs are no longer at the root of the repo etc., relative paths change and those changing paths are currently done via dynamic vars. Eventually this should all be removed.
Help, I'm having a tough time getting shadow-cljs to work for what should be a simple case. I have two separate projects, one is a cljs library (blockoid) and the other one wants to include it. Both are compiled with shadow-cljs, but I can't get it to come out right, despite endless fiddling with options. I either get errors like these, or a result that won't load. blockoid.js is generated by the first shadow-cljs build.
[:app] Compiling ...
[2024-06-26 10:31:25.623 - INFO] :shadow.build.npm/js-invalid-requires - {:resource-name "node_modules/blockoid/target/blockoid.js", :requires [{:line 899, :column 6}]}
Closure compilation failed with 3 errors
--- node_modules/blockoid/target/blockoid.js:299
Closure primitive methods (goog.provide, goog.require, goog.define, etc) must be called at file scope.
--- node_modules/blockoid/target/blockoid.js:300
Closure primitive methods (goog.provide, goog.require, goog.define, etc) must be called at file scope.
--- node_modules/blockoid/target/blockoid.js:301
Closure primitive methods (goog.provide, goog.require, goog.define, etc) must be called at file scope.
I already tried removing lein-shadow (since that seems deprecated), didn't help.
Adding :js-options {:js-provider :require}
to the config of the using package made the errors go away, but then the code wouldn't load. Similarly with :external
Changing build type to :esm
had no effect.
As you can see, I'm reduced to blindly searching the space of configs, because I have little understanding of how this is supposed to work. Any help appreciated, more details on request.
shadow-cljs is not involved in library creation, since libraries are raw uncompiled CLJS files
so you compiling it and then trying to include compiled files is not a supported use case
OK...but there are those options in shadow-cljs for generating a :node-library
or :npm-module
, that confuses me. Happy to do it the way you describe if it makes my life easier. Publishing to a local or public mvn repo is not a problem.
Also the blockoid package refers to other, non cljs npm packages, so how do they get packaged up? To be clear, the inclusion is blockly → blockoid → enflame, where • blockly is a non-cljs google library packaged in npm • blockoid is my library, wraps blockly in cljs/re-frame (https://github.com/CANDELbio/blockoid/tree/master) • enflame is a browser application that uses the above I may just give up on blockoid and incorporate it into enflame to avoid these problems, but seems like I shouldn't have to.
node-library and npm-module are intended for consumption in pure JavaScript, particularly in Node.js scripts. (note that npm-module is semi-deprecated in favor of the ESM target)
You may be able to import compiled ClojureScript code with them, but I wouldn't recommend it because each compiled artifact contains a copy of cljs.core, so you will be loading cljs.core multiple times. Secondly, the compiled code will have munged symbol names and only expose whatever functions were marked with ^:export
in CLJS
that's why the recommended option is to require cljs files directly rather than consume compiled output
in your case, what I'd do is create a JAR of blockoid, containing CLJS sources, not compiled JS. enflame then depends on this JAR (e.g. install locally then add to lein dependencies) and installs npm dependencies used by blockoid
you can make cljs automagically install npm dependencies with a deps.cljs file, but I don't recommend that since it forces consumers of the library into the exact versions specified in the file, and in general people dont like it when requiring a library results in arbitrary npm invocation
(In fact, all of my shadow-cljs projects have :npm-deps {:install false}
set, preferring to explicitly install dependencies myself)