This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-21
Channels
- # announcements (1)
- # aws (18)
- # babashka (5)
- # beginners (72)
- # biff (2)
- # calva (38)
- # cider (2)
- # clj-commons (6)
- # clj-yaml (2)
- # clojars (7)
- # clojure (41)
- # clojure-austin (5)
- # clojure-europe (78)
- # clojure-nl (1)
- # clojure-norway (18)
- # clojure-uk (3)
- # clojurescript (13)
- # component (9)
- # cursive (37)
- # datahike (3)
- # datomic (7)
- # fulcro (7)
- # graphql (3)
- # holy-lambda (2)
- # honeysql (8)
- # introduce-yourself (1)
- # jobs (1)
- # kaocha (1)
- # leiningen (19)
- # lsp (104)
- # malli (5)
- # nbb (8)
- # off-topic (60)
- # polylith (22)
- # portal (2)
- # reagent (24)
- # reveal (1)
- # shadow-cljs (126)
- # test-check (11)
- # tools-build (39)
- # vim (23)
- # xtdb (10)
when implementing server-side-rendering, I'm thinking about switching to :target
:esm
so I'm able to keep a single bundle that I can run in the browser and in node (or graal). Are there any reasons I'm missing why this would be a bad idea?
well for node you usually wouldn't bundle all the dependencies and let node load them
right, I think you convinced me regarding getting things working in node vs in graal first.
oh, there's still issues with it? Ok, will try :node-script
on the first glitch I run into
ESM needs to be opt-in for node. only ESM code can include ESM packages thought, so depending on what you want to use that may be required
ok, so I actually do load esm modules in node now, so trying :esm
instead of :node-script
running into ReferenceError: WebSocket is not defined
at shadow$cljs$devtools$client$websocket$start
(full error in 🧵 ) with target :esm
and trying to run it via node
.
node public/js/viewer.js
Installing CLJS DevTools 1.0.3 and enabling features :formatters :hints :async
file:///Users/mk/dev/clerk/public/js/cljs-runtime/shadow.cljs.devtools.client.websocket.js:5
var socket = (new WebSocket(ws_url));
^
ReferenceError: WebSocket is not defined
at shadow$cljs$devtools$client$websocket$start (file:///Users/mk/dev/clerk/public/js/cljs-runtime/shadow.cljs.devtools.client.websocket.js:5:14)
at Object.attempt_connect_BANG_ (file:///Users/mk/dev/clerk/public/js/cljs-runtime/shadow.cljs.devtools.client.shared.js:482:128)
at Object.shadow$cljs$devtools$client$shared$init_runtime_BANG_ [as init_runtime_BANG_] (file:///Users/mk/dev/clerk/public/js/cljs-runtime/shadow.cljs.devtools.client.shared.js:970:16)
at file:///Users/mk/dev/clerk/public/js/cljs-runtime/shadow.cljs.devtools.client.browser.js:957:36
at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:541:24)
at async loadESM (node:internal/process/esm_loader:91:5)
at async handleMainPromise (node:internal/modules/run_main:65:12)
Node.js v18.7.0
mk@studio ~/d/clerk (main) [1]> node public/js/renderer.js
file:///Users/mk/dev/clerk/public/js/renderer.js:5
var SHADOW_IMPORT_PATH = __dirname + '/../../.shadow-cljs/builds/renderer/dev/out/cljs-runtime';
^
ReferenceError: __dirname is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/Users/mk/dev/clerk/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
at file:///Users/mk/dev/clerk/public/js/renderer.js:5:26
at file:///Users/mk/dev/clerk/public/js/renderer.js:1797:3
at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:541:24)
at async loadESM (node:internal/process/esm_loader:91:5)
at async handleMainPromise (node:internal/modules/run_main:65:12)
Node.js v18.7.0
so I have a module in public/js/viewer.js
that I can load without errors in node but am too stupid to write another script that imports and uses it 🙈 The js ecosystem often makes me feel this way…
first of all drop the notion of public
for node. to me that look like it would end up as a public script in http sense, which I assume what you are not building here
tried various ways to import (also moving it to the ./
path but didn't figure out how to make it work
this is something shadow-cljs internal, it is not relevant for anything besides that
import "viewer.js"
is viewed by node a npm package and it'll try to load an npm package
Is there any guide that says something about how to use the output of the "release" target? I see various files lying around in ".shadow-cljs/builds/app/release", but.. what do I do with them?
you don't do anything with those, you only use the actual configured output files. ie. :output-dir
in a browser build
the files in .shadow-cljs
are build supporting files (eg. caches). they are build internal and aren't used anywhere besides that
Ah, I see thanks. 🙂 Okay, now I need to find out why the release build doesn't work.
"Error: No item 1 in vector of length 0"
There's some of my own log messages in the console before the error, so I guess I need to see where it crashes by putting in more console logs.. or is there a better way?
or npx shadow-cljs release app --pseudo-names
but that doesn't have source maps, so a little lower level and may require looking over some JS code
Damn, I actually have a single stupid "nth" in my code. I'll check that right away. Thanks so much!
now running into https://clojurians.slack.com/archives/C6N245JGG/p1627574180362500 with the advanced build. @borkdude you wrote you replaced this, is there a way to let shadow fix this now?
(spit "lib/nbb_core.js"
(str/replace (slurp "lib/nbb_core.js") (re-pattern "self") "globalThis"))
https://github.com/nextjournal/clerk/blob/d84badfae668cf0753dd5b8a61f8621afdef0865/shadow-cljs.edn is the config, bb release:js if you want to reproduce it
clerk$ npx shadow-cljs release viewer --pseudo-names
shadow-cljs - config: /mnt/c/Users/thheller/code/oss/clerk/shadow-cljs.edn
shadow-cljs - starting via "clojure"
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate shadow/cljs/devtools/cli__init.class, shadow/cljs/devtools/cli.clj or shadow/cljs/devtools/cli.cljc on classpath.
Full report at:
/tmp/clojure-13405443538645289994.edn
https://github.com/nextjournal/clerk/blob/82c35e2fc23a492ad1dd4ff201b39ed141098a1f/bb.edn#L27
@U05224H0W will do, thanks so much for all your support, greatly appreciated! 🙏
Good riddance: https://github.com/babashka/nbb/commit/bff81f8c9d66a69dfbbf5aeeea42649eb451e09b
Want to confirm there's no shadow-cljs easy pathway for this kind of js:
import 'draft-js/dist/Draft.css';
The only way to get that to work is to webpack compile it then require the webpack compiled javascript with shadow via the normal js interop routes?
aka
// ./src/js/project/css.js
import 'draft-js/dist/Draft.css';
(defn project.css
(:require "/project/css")) ;; <-- Invalid namespace declaration
etc?correct, shadow-cljs does not support css. use a tool that actually only handles css and don't try to turn css into js
and absolutely never even try to include some webpack output in a shadow-cljs build just to get css. thats madness 😛
So, I have an idea that I'm working on, and I'm trying to figure out how to proceed. In essence, I want a command line tool that executes, reads some data from the local directory, and then launches a browser to interactively show the results. I'm just trying to find my way around all the browser UI stuff I've ignored for about 10 years, and wrap my head around shadow-cljs concepts. First off, is this a normal use-case?
As in, I would want my browser FE on launch to chat with a local server, passing EDN or Transit or JSON back and forth.
yes, you can use shadow-cljs to build the cljs code that ends up running in the browser
Right, so a Clojure CLI command that, at launch, starts up a web server, serves up the previously compiled JS & assets plus additional routes specific to the tool, and opens a browser to the URL?
well running it locally is probably not done too often. but any CLJ website works that way, so yes very good path
I'm a little lost into how I can add my own routes to http://localhost:8080 when running shadow-cljs watch frontend
well that should be the server you intend to run for "production", which shadow-cljs should not be a part of
So far, no server support. I guess we would set up :8080 for JS and other assets, and another port, say :8081, for data?
no, just one server. as far as JS and other assets are concerned, it just needs to serve the static files. any webserver can do that
So far, all I have is this:
;; shadow-cljs configuration
{:deps true
:dependencies
[]
:dev-http {8080 "public"}
:builds
{:frontend
{:target :browser
:modules {:main {:init-fn }}}}}
Ah, ok. I need to specify a :handler for my non-static assets.you create a server to run your CLJ code. the one you intend to use for your command line tool
So I want all the live reloading goodness when developing, but then I want to package it all up and serve static assets off the classpath; so it feels like you are telling me about the second part of the story (one production server to handle static and dynamic) but I'm not quite sure what it looks like during development (where I want all the shadow-cljs live reloading goodness, at least for client components).
all REPL and hot-reloading is handled independently of the :dev-http
server. it is not involved in that
that is handled by the main shadow-cljs server running on :9630, which also serves the UI parts
the server serving the JS doesn't need to do anything special, just static files. it'll work with any server and needs no knowledge of shadow-cljs
Oh, it's coming into focus for me; so the shadow-cljs code is doing its thing and it's writing stuff intoo my public/js folder and using websockets to force the client to reload, but the server on :8080 is vanilla, and I can just replace that with my own app-specific server that servers assets from public but also hands the routes I need.
> IMPORTANT These are just generic web servers that server static files. They are not required for any live-reload or REPL logic. Any webserver will do, these are just provided for convenience.
Yes, I'd love to expand on this a bit: "As you develop your client side application, you will reach the point where it needs to communicate with a backend; at that point, you should remove :dev-http and provide your own server, that serves the assets in public but also provides the additional routes your frontend requires." Something like that.
you might not. we use a reverse proxy to route our requests to either our local UI, local APIs or dev env APIs
Ok I am trying to figure out how this sorcery works:
import cljs from "goog:cljs.core";
Is this a shadow thing or a Google Closure Compiler thing?sorcery