I’m assuming that this also applies to Cljs libraries.. https://blog.fikesfarm.com/posts/2017-11-18-clojurescript-performance-measurement.html cc @mfikes
I’m working through @asmeredith’s Learn Clojurescript. Is listing 5.4 is the same deps.edn file as listing 5.1? I added the aliases, ran clj -M:dev, and got “Error building classpath. Error reading edn. Invalid file, expected edn to contain a single value.”
can you post the contents of the deps.edn file here?
This is the deps.edn in the project directory:
{:deps {org.clojure/clojurescript {:mvn/version “1.10.773”}} :paths[“src”]} :aliases {:dev {:main-opts [“-m” “cljs.main” “--compile” “test-cljs-project.core” “--repl”]}}
{:deps {org.clojure/clojurescript {:mvn/version “1.10.773”}}
:paths[“src”]
:aliases
{:dev {:main-opts [“-m” “cljs.main”
“--compile” “test-cljs-project.core”
“--repl”]}}}
you had aliases and the map it corresponded to outside of the top level mapwhich is why the tooling was complaining that the edn file had more than one value. It should have only a single map
Awesome! Thank you @dpsutton That was the problem!
Hi 👋 Has anyone tried out the re-dnd
library? How does it compare to say react-dnd
?
The function compile-str
in cljs.js
doesn't seem to ever call the finished callback, I'm not sure what's going on, any suggestions on the best way to debug this?
Is there a way to use template literal tag functions from js in cljs? I need to do
sql`SELECT * FROM my-table
`
but not sure how, or if it’s possible.If I'm not mistaken tagged template literals are still just functions, so you should be able to call the fn with the string as the only argument
(sql "SELECT * FROM my-table")
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Okay, I did finally get the compile function to return. Although now I have another question:
When I use eval-str
in cljs.js
on some module B that requires module A, the load function finds the module A, and then executes both module A and B.
However, if I use compile-str
instead, the load function seems to find both A and B, but only seems to compile B.
Is that correct behavior?
ah, I've misunderstood slightly. the template literal fn only receives args for the interpolated values positionally, not the whole string as it's only arg
https://codeburst.io/javascript-template-literals-tag-functions-for-beginners-758a041160e1
(And if so, is there any way I can get a compile-str
like function, that either: (i) compiles A and B together, or (ii) compiles B in a way that doesn't require me to manually call compile-str
on A?
the 0th argument to the fn is the template string
the n+ args are the interpolated values
(When I do try to pass the result of compile-str
to js/eval
I get: Error: goog.require could not find: A.core)
@leif https://clojure.atlassian.net/browse/CLJS-3288 and https://clojure.atlassian.net/browse/CLJS-3286 are two open issues regarding self-hosted cljs to be aware of. We recently switched to https://github.com/borkdude/sci for eval and are quite happy with it, found it less complex to setup and it’s lighter weight. It even works with advanced compilation. The downside is that it’s a slower as it’s an interpreter, not a compiler.
@mkvlr Thanks for pointing those out.
I'm looking for something that can output javascript that I can potentially transform with babel, can sci do that?
It 'looks' like its mostly an evaluator to me.
But maybe I'm wrong?
You're correct that sci
is a clojure interpreter (not a compiler)
Thanks! I also tried the template tag in node and realized it just returns
{sql: "SELECT * FROM tabl WHERE id=$1",
type: "SLONIK_TOKEN_SQL",
values: [7]}
Rats. oh well
Although I guess if it has the capability to pause computations that would be enough for me.
But might do your suggestion so it at least looks like I’m trying to be a good user
(Like if I could set up (loop [] (recur))
to be breakable and not inherently freeze the browser until the tab is reloaded.
That sounds challenging (in a javascript environment) but not strictly impossible... I think you'd have to hack something into sci
to allow evaluation to be interruptable with core.async
(for example)
I don't know enough about sci
but I'd say if you're willing to modify it, you should be able to make a core.async
loop that does a few steps of evaluation and then checks if the kill
channel has been closed
@blak3mill3r Oh, I'm using stopify (https://www.stopify.org/) right now, which seems to work surprisingly well for how small a project it is.
That's actually why I was using compile-str
.
@leif Maybe you can run sci (compiled as JS) itself through stopify? ;)
FWIW I haven't been able to find a satisfying answer to the halting problem
Even when instrumenting sci with all kinds of checks, there is still probably a program that can work around it
@borkdude That's not a bad idea actually.
There are advanced type systems with less powerful programming languages, like Dhall, which provably terminate
some inspiration to keep trying: https://m.youtube.com/watch?v=MdmQUlD7P40
Although ya, it would be nice if we could solve the halting problem, fortunately what I"m trying to do is MUCH simpler then that. 😉
but sci did have some flags to control execution time https://github.com/borkdude/sci/issues/348
I mean, the thing about CP(>0) is the answer is: "no, your analysis won't halt. 😉 )
those were experimental and were never implemented
after I saw that it wasn't good enough
but 0.1 still had them? https://github.com/borkdude/sci/blob/master/CHANGELOG.md#breaking-changes
There were flags to control the max length of realization of lazy seqs
but that was removed as well
ah right
The https://arxiv.org/abs/1802.02974 seems to indicate that the techniques are more general than just javascript > We apply Stopify to 10 programming languages
@smith.adriane Only partially.
It applies to other languages if and only if they can compile to javascript.
ah
When you look at the source code for their little clojurescript debugger demo, it actually compiles to javascript first.
Stopify sounds cool. I think you might have luck running sci
with Stopify.
@blak3mill3r I'll give it a shot and let you know how it goes. 🙂
Thanks for the suggestion.
I'm curious... I mean I guess Stopify must be doing some sophisticated static analysis and source->source translation
kinda like core.async...
I think you can even fool core.async, by putting`(Thread/sleep 1000000)`, it won't help you there
I doubt its exactly like core.async, but same idea.
I mean that core.async's implementation details involve code splitting/rewriting using clojure macros
luckily JS doesn't have Thread/sleep
@borkdude well that would be a recipe for freezes. 😉
On the other hand, if it did, you could run your eval in a thread and then kill the thread if it took too long ;)
Yeah I thought for a moment about WebWorkers
run self-hosted cljs or sci in a WebWorker and perhaps there's an API to kill it after a timeout
@borkdude True, but aren't webworks a relatively recent addition to JS?
@blak3mill3r A webworker won't work, I want to manipulate the dom.
(Ideally directly.)
yeah
you'd have to do that indirectly which would be a pain
Although I guess if its possible to get react working with actors (sounds painful), I'd be willing to give it a go.
Oh, also, you can look at the compiled stopify output if you find that interesting.
Modified from a recent message I sent to Arjun:
<script src="<https://github.com/ocelot-ide/Stopify/releases/download/0.7.3/stopify-full.bundle.js>"></script>
<script>
const prog = `
var i = 0;
debugger;
while(i < 10) {
console.log(i);
i = i + 1
};`;
let runner = stopify.stopifyLocally(prog);
runner.g = {console};
runner.run(() => {
console.log(runner.g.i);
console.log("DONE!");
});
</script>
@leif there is (an old) version of sci on npm available, if you want to try it out quickly
I guess you could try stopify.stopifyLocally(sci.evalString)
oh, good idea.
I have deprecated the npm package more or less since it's way easier to configure it from CLJS and the compile it to JS yourself
and usually you want to include a lib or so anyway
LOL
$ ls node_modules/sci
LICENSE package.json README.md
Probably a different package.
"Yet another math library for your browser" yup. woops
Ah, found it: https://www.npmjs.com/package/@borkdude/sci
Yeah, still seems to work:
> const { evalString } = require('@borkdude/sci');
undefined
> evalString("(str (assoc {:a 1} :b 2))")
'{:a 1, :b 2}'
Sadly it doesn't quite seem to work with stopify...although maybe I'm doing something wrong
sci.js?3eac:910 Uncaught Mn {message: "Dc(...).append is not a function [at line 1, column 1]", data: k, Bc: TypeError: Dc(...).append is not a function
at Function.VU.f (webpack-internal:///./node_module…, name: "Error", description: undefined, …}
Code is:
var stopify = require ('@stopify/stopify');
var sci = require('@borkdude/sci');
window.stopify = stopify;
let runner = stopify.stopifyLocally(sci.evalString("(println (+ 1 2))"));
runner.g = {console};
runner.run(() => {console.log("DONE!");});
@leif this is a warning you will get when using println, this doesn't work with sci out of the box, you will have to bind the out stream to something
so for just testing this, it's better to configure your own println or just avoid printing for now
oooh
So it 'might' actually be working...nifty.
try (doall (range))
> evalString("(println (str (assoc {:a 1} :b 2)))", {"namespaces": {"clojure.core": {"println": console.log}}})
{:a 1, :b 2}
Hmm:
Uncaught TypeError: this.input.charCodeAt is not a function
at Parser.fullCharCodeAtPos (index.js?0cd6:781)
at Parser.nextToken (index.js?0cd6:766)
at Parser.parse (index.js?0cd6:1672)
at Object.parse (index.js?0cd6:7305)
at Object.stopifyLocally (compiler.js?e91e:100)
at eval (in.js?73b4:10)
at Object../in.js (out.js:96)
at __webpack_require__ (out.js:20)
at out.js:84
at out.js:87
does stopifyLocally only accept JS code as strings as input?
Oh wait, I think I know what's going on.
No, it can also accept babel AST nodes.
But it just occurred to me that it could be that sci is putting something in the window object that the stopify sandbox isn't allowing.
it isn't doing that
all mutation is local to sci, it never mutates the outside world unless you configure it to (hence no printing by default)
Ah, okay, never mind then.
Oh...right, I wasn't calling it right.
This is what I needed to do.
var stopify = require ('@stopify/stopify');
var sci = require('@borkdude/sci');
window.stopify = stopify;
//console.log(sci.evalString("(+ 1 2"));
const prog = `
console.log(sci.evalString("(doall (range))"));
`;
let runner = stopify.stopifyLocally(prog);
runner.g = {console, sci};
runner.run(() => {console.log("DONE!");});
Sadly I suspect the runner.g = {...};
line at the bottom will break the sandbox. 😕
it's stoppable ^ like that? That's pretty nifty
@blak3mill3r Sadly no. 😞
what is runner.g?
It tells stopify what objects can be in the sandboxed namespace.
(from the outside world)
So in this case, sci is coming in from the outside world. Hence why I suspect it doesn't work. So now I need to see if I can bring sci itself in.
Ah, sad. So I can't seem to get stopify to work with webpack packages just at the moment. I'll poke Arjun and see what he has to say. I'll get back to you about this later @blak3mill3r and @borkdude . Thanks for all your help btw! 🙂