Hello My team needs to deliver a nodejs library to another team The other team expect a typescript-like user experience: a beautiful docs website and maybe an autocomplete. Which tools I can use from cljs world to do that? Like, I can generate docs via JSDocs or some other tool that document the API for javascript users, not for clojure users.
Did you figure this out? An option could be to emit JSDoc comments around your exported functions. Typescript will pick up those annotations.
Probably your TS api docs would work then too.
Pretty sure that would work.
Little known fact about TS is that it falls back to jsdoc in some situations, and buried inside it is an implementation of supporting types via jsdoc comments.
https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
Guess this was on your radar already though
very valuable all this information As a clj dev I doent even know how to start to search things like "how do typescript do autocomplete" thank you so much @dazld, I will try to do some POC and maybe a blog post about it š
Iām interested in this topic too - if you remember me when you have something concrete, please do ping
It might even be that you can skip TS completely and just ship jsdoc comments.. perhaps.
Some macro magic may be appropriate, translating specs into jsdoc..
Interesting question, thanks for asking.
What is the best practice to compile some EDN data in .clj file, for consumption in .cljs files? Considering .cljc file, but I only need the .clj code at compile time. I am trying to use a https://github.com/shegeley/airtable-clj to download my data, then use shadow-cljs to compile a web-site with live-reload. I am using https://github.com/OrgPad-com/volcano library, which runs the the web page templating code with shadow-cljs and Reagent cljs when in dev mode, then uses clj via Lein to compile static html for production. It uses .cljc files for this code. It is nice to have a responsive dev mode, but it feels confusing and limiting for me to constrain myself to only code that can be run in both runtimes? I donāt want to try to re-duplicate the AirTable download and parsing code, just to run it in cljs runtime. Maybe Iām over-thinking it. Seems like it should be possible to have some clj functions that return data, then depend upon them in proper shadow-cljs build. Hopefully without having to treat them both like alien runtimes: Lein compile the clj to edn, then pre-load that into shadow-cljs as an in-lined resource, or have the cljs use a fetch function to read it as an external resource. Any hints? Thanks
@chromalchemy you can do this using a macro
depending on the total size I would recommend downloading it in CLJS. inlining is fine for really small files, eg via https://clojureverse.org/t/using-none-code-resources-in-cljs-builds/3745
Thanks guys. @thheller I have successfully inlined some data using that method on another project, it worked! And was crucial to that moment :simple_smile:. But wouldnāt I still need to run some process to download and save the data first, before shadow-cljs can inline it? How could this be worked into a repeatable shadow-cljs build? @borkdude I will try the macro solution too.
if it can change over time I would manage that data on the server and have your frontend download it when needed
Ok, I will consider that. I wanted to keep production site relatively static and simple. It doesnāt have to change often. I will not be using cljs on the production site. The cljs is only running for live-reload (which is probably over-complicating this whole thing.
@thheller wrote in another post > macros rewrite Clojure code at compilation time. They just take the raw form that was passed into the call and rewrite it to something else. They never eval their arguments. > On top of that the macros for ClojureScript are expanded at compilation time which happens in Clojure on the JVM. So they donāt have access to any JS at all. So in my context, would putting the .clj based Airtable data request and parsing code into a macro āmagicallyā make it run in .cljs also? Was just hoping it could eval the .clj code as part of the shadow-cljs compile phase, and .cljc files depend on that resulting data.
it is not clear what you are trying to do here. would help to see some code. sounds like you are making the problem way more complicated that it needs to be.
"eval the .clj code". using a macro does that, so sounds like you want to write a macro?
Hmm.. Ok Iāll try to sort it out. I wasnāt sure if the .clj macro from called from .cljs could eval and return the data. But it seems so. I appreciate your other suggestions though, and will them.
Hello I compiled this simple code
(ns tempproject.tempnamespace)(defn ^:export add_cj [n1 n2] (+ n1 n2))
And i got the js file , someone told me that i can access the add_cj by calling tempproject.tempnamespace.add_cj(1,2); for example
and it works ,but i give this code to MongoDB and it says ReferenceError: tempproject is not definedon the js that is generated i dont see a var temproject, but code works, i tested it
the way of accesing the function with tempproject.tempnamespace.add_cj(1,2); should be working in all js enviroments? can i use something else to access add_cj ?
how did you compile it?
clojure -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version \"1.10.741\"}}}' -m cljs.main -O advanced -c
I don't know mongodb but I guess it probably expects some commonjs or ES module format
is there an alternative way to acces the exported function?
do you have a JS example for the mongodb side? what it expects?
i use it with java , so i give the code as string
function add_cj(arg__0,arg__1) { if(typeof Math.imul == "undefined" || (Math.imul(0xffffffff,5) == 0)) {
Math.imul = function (a, b) {
var ah = (a >>> 16) & 0xffff;
var al = a & 0xffff;
var bh = (b >>> 16) & 0xffff;
var bl = b & 0xffff;
// the shift by 0 fixes the sign on the high part
// the final |0 converts the unsigned value into a signed value
return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
}
}
;var c=this||self;function e(a){var b=a.length;if(0<b){for(var h=Array(b),d=0;d<b;d++)h[d]=a[d];return h}return[]};function f(){this.c=""}f.prototype.toString=function(){return"SafeScript{"+this.c+"}"};f.prototype.a=function(a){this.c=a};(new f).a("");function g(){this.g=""}g.prototype.toString=function(){return"SafeStyle{"+this.g+"}"};g.prototype.a=function(a){this.g=a};(new g).a("");function k(){this.f=""}k.prototype.toString=function(){return"SafeStyleSheet{"+this.f+"}"};k.prototype.a=function(a){this.f=a};(new k).a("");function l(){this.b=""}l.prototype.toString=function(){return"SafeHtml{"+this.b+"}"};l.prototype.a=function(a){this.b=a};(new l).a("\x3c!DOCTYPE html\x3e");(new l).a("");(new l).a("\x3cbr\x3e");var m={},n={};if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof p)var p={};if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof q)var q=null;if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof r)var r=null;if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof t)var t=null;if("undefined"!==typeof Symbol){var u=Symbol;"object"!=typeof u||!u||u instanceof Array||u instanceof Object||Object.prototype.toString.call(u)}
var v="undefined"!==typeof Math&&"undefined"!==typeof Math.imul&&0!==Math.imul(4294967295,5)?function(a,b){return Math.imul(a,b)}:function(a,b){var h=a&65535,d=b&65535;return h*d+((a>>>16&65535)*d+h*(b>>>16&65535)<<16>>>0)|0};function w(a){a=v(a|0,-862048943);a=0^(v(a<<15|a>>>-15,461845907)|0);a=(v(a<<13|a>>>-13,5)+-430675100|0)^0;a=v(a^a>>>16,-2048144789);v(a^a>>>13,-1028477387)}w(1);w(0);if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof x)var x=null;
"undefined"!==typeof console&&(q=function(){return console.log.apply(console,e(arguments))},r=function(){return console.error.apply(console,e(arguments))});if("undefined"===typeof m||"undefined"===typeof n||"undefined"===typeof y)var y=function(){throw Error("cljs.core/*eval* not bound");};function z(a,b){return a+b}var A=["tempproject","tempnamespace","add_cj"],B=c;A[0]in B||"undefined"==typeof B.execScript||B.execScript("var "+A[0]);for(var C;A.length&&(C=A.shift());)A.length||void 0===z?B=B[C]&&B[C]!==Object.prototype[C]?B[C]:B[C]={}:B[C]=z; return tempproject.tempnamespace.add_cj(arg__0,arg__1); }
console.log(add_cj(1,2));
this is my code , it runs from example in http://playcode.io.
thats irrelevant to my question. I don't know the mongodb parts so I expect that it maybe requires something special to be exported or so
and this isn't advanced output, so you did some custom wrapping?
yes i didnt do anything big
only wrap it on function add_cj and in the end i added return tempproject.tempnamespace.add_cj(arg__0,arg__1);
to make the code a function
yeah but why?
mongodb need 1 function as argument
not any js code
unless you can point me to some mongodb docs or example I really cannot help you
ok i know , but me accesing the function with tempproject.tempnamespace.add_cj(arg__0,arg__1); is ok?
no
ok do you know how to access it properly? it works this for example in http://playcode.io
> unless you can point me to some mongodb docs or example I really cannot help you
i dont have a place to explain limitations
i was searching for that in mongodb
but for normal js , how i should acces the exported function ?
https://docs.mongodb.com/manual/reference/operator/aggregation/function/#std-label-function-lang
but this wont help
it just says give a javascript function as string
it expects this "function(arg1, arg2, ...) { ... }"
that looks like it'll just serialize the entire code and send it to the server? that'll be tricky with cljs
the weird thing is that the code works, even in mongo shell , when i do load(myfunction.js);
i can call it as add_cj(1,2); fine , but when i send it as string it says reference not found
the ^:export
is likely the problem. that wants to export the whole thing into the global scope, which may not be allowed or blocked for security reasons
in the past it worked, i dont know why , i used that code in MongoDB , maybe i changed something i dont know or MongoDB new version blocked something
all i want is 1 Clojurescript function to become 1 Javascript function
maybe something like
(ns tempproject.tempnamespace)
(defn my-fn [a b]
(+ a b))
(my-fn js/arg__0 js/arg__1)
with your add_cj
wrapperyes but this will not generate 1 javascript function
mongoDB expects 1 javascript function not any js code
your wrapper creates that fn
ok i will try to make the call from clojure thank you : )
is there an easy way to do sha256 in ClojureScript?
goog.crypt.Sha256
, goog.crypt
in general
thanks
i am trying long time the js/arg__0 js/arg__1 arguments dissapear on advanced compile, i tried to make the code more complicated like (apply myfn [js/arg__0 js/arg__1]) and it worked, but code from 2k characters gone to 91k characters
also i need to add a function(arg__0,arg__1) and a return , i need return also
note that you should expect 91k for any function you write that uses any of the cljs datastructures. it'll only stay small if you stick to very basic JS interop. you probably need externs to prevent the unwanted renaming.
oh right I forgot about the return
, too tired to think about that one now š
is there a way to prevent the rename? i dont know how to use externs
dont worry you helped me anyways
i might benchmark the 91k , because probably i wouldnt avoid it anyways
yeah I'd expect that as a baseline