With latest shadow-cljs emitted code for Node.js , Webpack reports:
WARNING in ./compiled/cljs.nodejs.js
10:22-29 Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
the code:
var CLJS_ENV = require("./cljs_env");
var COMPILED = false;
require("./cljs.core.js");
var cljs=CLJS_ENV.cljs;
var goog=CLJS_ENV.goog;
goog.provide('cljs.nodejs');
goog.require('cljs.core');
goog.require('cljs.core');
cljs.nodejs.require = require;
cljs.nodejs.process = process;
cljs.nodejs.enable_util_print_BANG_ = (function cljs$nodejs$enable_util_print_BANG_(){
cljs.core._STAR_print_newline_STAR_ = false;
cljs.core._STAR_print_fn_STAR_ = (function() {
var G__547__delegate = function (args){
return console.log.apply(console,cljs.core.into_array.cljs$core$IFn$_invoke$arity$1(args));
};
var G__547 = function (var_args){
var args = null;
if (arguments.length > 0) {
var G__561__i = 0, G__561__a = new Array(arguments.length - 0);
while (G__561__i < G__561__a.length) {G__561__a[G__561__i] = arguments[G__561__i + 0]; ++G__561__i;}
args = new cljs.core.IndexedSeq(G__561__a,0,null);
}
return G__547__delegate.call(this,args);};
G__547.cljs$lang$maxFixedArity = 0;
G__547.cljs$lang$applyTo = (function (arglist__564){
var args = cljs.core.seq(arglist__564);
return G__547__delegate(args);
});
G__547.cljs$core$IFn$_invoke$arity$variadic = G__547__delegate;
return G__547;
})()
;
cljs.core._STAR_print_err_fn_STAR_ = (function() {
var G__566__delegate = function (args){
return console.error.apply(console,cljs.core.into_array.cljs$core$IFn$_invoke$arity$1(args));
};
var G__566 = function (var_args){
var args = null;
if (arguments.length > 0) {
var G__571__i = 0, G__571__a = new Array(arguments.length - 0);
while (G__571__i < G__571__a.length) {G__571__a[G__571__i] = arguments[G__571__i + 0]; ++G__571__i;}
args = new cljs.core.IndexedSeq(G__571__a,0,null);
}
return G__566__delegate.call(this,args);};
G__566.cljs$lang$maxFixedArity = 0;
G__566.cljs$lang$applyTo = (function (arglist__572){
var args = cljs.core.seq(arglist__572);
return G__566__delegate(args);
});
G__566.cljs$core$IFn$_invoke$arity$variadic = G__566__delegate;
return G__566;
})()
;
return null;
});
module.exports = cljs.nodejs;
//# sourceMappingURL=...dropped...
Reproduce code https://github.com/Cumulo/cumulo-workflow/tree/master/server
yarn
yarn cljs
# new tty
yarn dev
Don't use the cljs.nodejs namespace. It doesn't provide anything useful.
If you want to create a node script with shadow-cljs you should try:
https://github.com/thheller/shadow-cljs/wiki/ClojureScript-for-node.js-scripts
[{:id :server
:target :node-script
:main server.main/-main
:output-to "server.js"}]
And then shadow-cljs --build server --once (or --dev, --release) to build it.
You don't need *main-cli-fn* or enable-console-print!.
This does also come with a REPL and live-reloading if you specify the :devtools ala
[{:id :server
:target :node-script
:main server.main/-main
:output-to "server.js"
:devtools
{:before-load server.main/stop
:after-load server.main/start}]
Your solution is way simpler than reloading using Webpack, Figwheel or Lumo. However it's not appearing on Google results. Would you like to pick a domain(http://shadow-cljs.org) and put the docs there?
Maybe I should migrate my front-end reloading solution to this too, if I can handle assets build in a proper way. Then I will only need Webpack in deploying.
it is working now with :browser enabled, but i got an unexpected public/ folder generated and the config file is complicated.
still sovling conflicts.
updated:
Now HMR with shadow-cljs https://github.com/mvc-works/stack-workflow/commit/c0c6a3ff05ee8e9298833aa9d919ae486555df6e the configs looks quite messy.
[{:id :dev
:target :browser
:modules {:main-dev {:entries [client.main]}}
:output-dir "compiled/"
:public-dir "dist/"
:public-path "http://localhost:8080/"
:devtools {:after-load client.main/on-jsload!}}
{:id :npm
:target :npm-module
:output-dir "compiled"}
{:id :app
:target :npm-module
:output-dir "compiled"
:compiler-options {:externs ["entry/externs.js"]}}]
:dev and :app are dev and build. I need an npm because I need to run a script polyfill/src/client.render.cljs compiled by it. However, I can't compile it alone because in package.json the source-paths is defined to contain src/.
Combining :browser with webpack isn't fully supported yet. I'll try to create a config that works that is less confusing. I have not fully grasped what you are trying to achieve yet.
Previous solution of HMR with Webpack and shadow-cljs, downsides:
So now I tried to remove js compiled from ClojureScript from the Webpack bundle, but keep using Webpack in CSS development and the bundling step for release, which means using shadow-cljs directly.
As a result I got two WebSocket connections in dev mode. It's not combining both. Just running side by side.
This is far more complicated than I like.
The easy part is the render script, instead of making a build for it you can use it directly from the compiled directory with a little helper in scripts/render.js
https://github.com/thheller/stack-workflow/tree/script
I'm fine with current render script, it's written in yarn script https://github.com/thheller/stack-workflow/blob/master/package.json#L10-L11
Tricky thing I found is when shadow-cljs is running in :browser mode, :output-dir "compiled/" does not work, so I added another config :target :npm-module in order to compile it. And as I compile, all files in src/ and polyfill/ are compiled since it's hardcoded.
Yeah, builds cannot share an :output-dir.
:browser targets must have a dedicated :output-dir that is also served by the webserver (via :asset-path).
{:output-dir "dist/js" :asset-path "/js"} means that all output is written to dist/js/... and the files can be reached by a webserver via /js/.... The files created in :output-dir are browser only and cannot be consumed via require. They won't work with webpack.
I'll try to create a simpler example for this.
Understood. :browser has its own use case.
I think what I need here is something like shadow-cljs --npm --src=polyfill/ --output=compiled/ --once so that I can compiled the script alone.
The issue is that you are trying to create 2 different builds from one build config by using :npm for the webpack release build and the dev client.render.
You can add :entries [client.main] to the :npm config but then you need a second build config for the script. You can configure it like this:
{:id :script
:target :node-script
:output-to "scripts/render.js"
:main client.render/main}
You can then call node scripts/render.js directly.
Tried but I feel like sticking to my old solution. Too slow to generate a node script, while compiling a single file to CommonJS file is fast.
The real issue is that running multiple builds in parallel doesn't work when using the CLI tool. Compiling the :node-script shouldn't be any slower than the rest but launching a new JVM instance just to get it compiled is indeed not great.
I'll think about it, see #33.
Thought for a while, I switched back to Webpack HMR for js since we may have naughty situations like bundling Markdown into JavaScript with Webpack loaders.
Meanwhile I moved shadow-cljs configs out from package.json but instead rewrite it with a scripts.
https://github.com/mvc-works/stack-workflow/blob/master/shadow-cljs.json
https://github.com/mvc-works/stack-workflow/blob/master/entry/env.coffee
For 2 reasons:
package.json frequently, configs looks bad in a generated filepolyfill/ during --release, then no need to add externs for nowMaybe :node-script will be a better way, not sure.
You can also do this, no need to mess around with the source paths.
[{:id :app
:target :npm-module
:output-dir "compiled"
:release
{:entries [client.main]}}]
Which means that --release will only compile client.main and its dependencies, while --dev still does the default to compile every source file it finds. You can specify any configuration entry in :release to override the default. :release {:output-dir "somewhere"} would also work. The same works with a nested map for :dev. Not documented anywhere yet but works.
But as I said .. the problem is that you are running two builds off one config. That will only cause issues and should never be done.
For example if you run shadow-cljs --release and then try to run the yarn html it won't work since you now have mixed output in the compiled directory.
Again, that will get much better once you can run multiple builds in parallel properly.
Btw if you use :entries you can put everything into src. No need for the polyfill directory unless you really want it.
You are right. But I didn't know I could use :release like that before.
Speaking of messy, I think the second one below is messier:
{
"source-paths": ["src", "polyfill"],
"output-dir": "compiled",
"dependencies": [
["mvc-works/hsl", "0.1.2"],
["respo/ui", "0.1.9"],
["respo", "0.4.2"]
]
}
"shadow-cljs": {
"source-paths": [
"polyfill",
"src"
],
"output-dir": "compiled",
"dependencies": [
[
"mvc-works/hsl",
"0.1.2"
],
[
"respo/ui",
"0.1.9"
],
[
"respo",
"0.4.2"
]
]
}
For polyfill/, currently code in my src/ are generated from ir.edn, while code in polyfill was written by hand. I suppose I would migrate polyfill/ in the future.
Yeah, thats why I never want to write to shadow-cljs.edn. Keeping the original format and comments would be hard ... but shadow-cljs add respo would be nice to have. ;)
I don't think so. If you implement add, then it will come with remove upgrade release endlessly. Do you have a good answer to this question? https://groups.google.com/forum/#!topic/clojure/6dNy6caCSiY
Sorry, no good answer. I did the setup once years ago and only do lein deploy clojars since then.
IIRC I installed https://gpgtools.org/ and created a key using the GPG Keychain app. Then added this bit of config in ~/.lein/profiles.clj.
{:auth {:repository-auth {#"clojars" {:username "foo" :password "bar"}}}}
Can't remember if I did anything else.