This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-17
Channels
- # announcements (3)
- # babashka (3)
- # beginners (53)
- # biff (2)
- # calva (16)
- # cider (1)
- # clj-commons (1)
- # clj-kondo (97)
- # clj-on-windows (137)
- # clojure (49)
- # clojure-europe (63)
- # clojure-gamedev (1)
- # clojure-nl (2)
- # clojure-norway (50)
- # clojure-uk (4)
- # clojurescript (36)
- # core-async (28)
- # datomic (32)
- # emacs (22)
- # events (1)
- # graalvm (8)
- # honeysql (6)
- # jobs (2)
- # lambdaisland (5)
- # malli (6)
- # nbb (31)
- # off-topic (171)
- # pathom (14)
- # rdf (2)
- # reitit (4)
- # releases (2)
- # scittle (19)
- # shadow-cljs (46)
- # sql (6)
- # squint (6)
@thheller question if this blasphemy is possible -- I want to use some typescript source code in my clojurescript project. I see that it is possible to https://shadow-cljs.github.io/docs/UsersGuide.html#_access_cljs_from_js ...
1. is it possible to use clojurescript from javascript and include that javscript into the project in a single compilation step, or are multiple compilation steps required?
a. Will multiple copies of cljs.core be created, or just 1?
2. If it can be done in a single step, can I do the following:
a. cljs.core
-> javascript -> project cljs files
-> other local javascript -> other local source files?

My usecase for this heresy: I'm trying to practice some so-called "Domain Oriented Design" where the business logic closely matches the common sense notions of the business rules. I'm trying to make it open for extension but closes for modification, so I want the code to be polymorphic and compile-time extensible. I can do this with defprotocol/defrecord but it's too slow and there's too much code duplication, so I'm dipping into typescript. However -- I want to use all the cljs functions. Then I want to use those datatypes in my clojurescript library code. Then I want to use the clojurescript library code in the javascript functions to make more sophisticated datatypes. Then I want to use THOSE more advanced datatypes in the clojurescript app code.
More detailed notes:
// baseData.ts
get: () => any
}
interface ISettable<out T> {
set(x: any): T;
}
export interface IGetSet<out T> extends ISettable<T>, IGettable {
}
type MapType = cljs.core.PeristentHashMap | cljs.core.PersistentArrayMap;
export class MyData implements IGetSet<MyData> {
cljsData: MapType
constructor(data: MapType) {
this.cljsData = data;
}
get(): any {
cljs.core.get(this.cljsData, cljs.keyword("data"))
}
set(x: any): MyData {
let existingData = this.cljsData;
let path = cljs.keyword("data");
let newData = cljs.core.assoc(existingData, path, x);
return new MyData(newData)
}
}
(ns somens.core
(:require ["./path/to/src/gen/baseData.js" :as my-data]))
(defn ^:export fancy-cljs-fn [my-data]
(.set my-data 42))
// fancyData.ts
import {fancy_cljs_fn} from "???"; // help needed
import {IGetSet, MyData} from "./baseData";
class FancyData implements IGetSet<FancyData> {
mydata: MyData;
constructor(data: MyData) {
this.mydata = fancy_cljs_fn(data);
}
get(): any {
return this.mydata.get();
}
set(x: any): FancyData {
let newData = this.mydata.set(x);
return new FancyData(newData);
}
}
(ns fancyns.core
(:require ["./path/to/src/gen/fancyData.js" :as fancy]))
(defn ^:export super-fancy [fancy-data]
"yay")
wtf xD
for requiring cljs in JS, there's the doc : https://shadow-cljs.github.io/docs/UsersGuide.html#_access_cljs_from_js
import {fancy_cljs_fn} from "goog:somens.core"
Did you already try it?
Ohhh ok I thought that "goog:cljs.core"
was a hardcoded constant or something, didn't realize that was extensible
Ok there's no way this is possible in the same compiler pass.
Or is it :thinking_face:
The JS file is not processed by shadow, it is used directly as it is, so I think it should work. With a parallel TS watcher of course.
this will be wild
I think it's gonna work but ran out of time
damn it actually works
I can't even believe this works 😮
I think this must be what Voldemort felt like when he got into the blood magic section of the library
It will I think as soon as I get hot reloading to work!
Is there a way to hot reload userland javascript?
Okay at the bottom of https://shadow-cljs.github.io/docs/UsersGuide.html#_javascript_dialects it mentions this:
but I'm not observing this behavior
ok, probably on my end then
does it watch subdirectories, too? so for instance if I have
src/gen
in :source-paths
, will it watch src/gen/sub
, or do I need to mention that explicitly?
Yeah if anyone has any more suggestions I'd be appreciative. The change is not being recompiled to js/cljs-runtime
.
{:source-paths
["src/cljs"
"src/gen"]
:deps true
:dev-http {8080 "public"}
:nrepl {:port 9000
:middleware [cider.piggieback/wrap-cljs-repl]}
:builds
{:frontend
{:target :browser
:modules {:main {:init-fn cljstable.core/init}}
:devtools {:repl-init-ns cljstable.sidecar
:repl-pprint true}}}}
Here's the compilation results and relevant directory structure. Am I doing something wrong here?
Invoked via cider
with:
;; Startup: /home/jay/.nvm/versions/node/v16.14.0/bin/npx shadow-cljs -d nrepl/nrepl:0.8.3 -d cider/piggieback:0.5.2 -d refactor-nrepl/refactor-nrepl:2.5.1 -d cider/cider-nrepl:0.26.0 server
;;
;; ClojureScript REPL type: shadow
;; ClojureScript REPL init form: (do (require '[shadow.cljs.devtools.api :as shadow]) (shadow/watch :frontend) (shadow/nrepl-select :frontend))
Even when I delete the js/cljs-runtime/module$cljstable$baseData.js
, it gets rebuild with the unchanged code
this makes no sense, unless you have a second js source file with the old code. Or could it have cached the old result somehow ? I don't see why
yeah, ripping my hair out about it
will try to start with a fresh project 😞
uuugh yeah with a fresh project it works. there's some garbage artifacts somewhere. good call @U02F0C62TC1
Yeah not sure how to fix that when doing cider-connect-cljs
Ok I FINALLY figured out what it was... sort of
working:
not working:
so it seems that I need to reference at least one of the js file in the :init-fn
namespace in order for shadow-cljs to recognize a recompile
> Yeah not sure how to fix that when doing cider-connect-cljs
You'd have to have a look at whatever is your nrepl server (maybe some webapp?)
yarn shadow-cljs watch frontend
then whatever cider does when connecting
yeah, confirmed, there needs to be some kind of reference to the javascript file in the :init-fn
namespace in order to recompile... phew... thank god... can move on with my life now...
taking a quick look at the docs, looks like shadow-cljs picks up whatever cider-nrepl version is defined in either your project.clj or deps.edn.
The docs also reference a ~/.shadow-cljs/config.edn
file, although it looks like it's not much advised
@U3BALC2HH as a general rule: shadow-cljs only compiles files that are actually required in a build. so :init-fn
is following all :require
in the namespaces (or import
in JS files) and compiles those. a file that is not required is not compiled, as you learned 😉
also when using :deps true
the :source-paths
config in shadow-cljs.edn
has no effect. you should be warned about that on startup, but depending on how you start things that may not be visible (eg. emacs hiding it in some buffer)
as a general warning the JS support is not widely used and can cause issues with externs in release builds. since there is no externs inference those might be hard to debug later
Makes a ton of sense when you put it like that. There were so many moving parts with that typescript debauchery that I got lost in the sauce
Ok I'm assuming the answer is "because of idiots like me" but I'm really confused why this is not part of standard clojurescript: https://shadow-cljs.github.io/docs/UsersGuide.html#_requiring_js
Ok I'm assuming the answer is "because of idiots like me" but I'm really confused why this is not part of standard clojurescript: https://shadow-cljs.github.io/docs/UsersGuide.html#_requiring_js