This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-01-18
Channels
- # aleph (1)
- # announcements (2)
- # aws (4)
- # beginners (73)
- # boot (2)
- # boot-dev (3)
- # cider (6)
- # cljs-dev (40)
- # clojure (64)
- # clojure-austin (2)
- # clojure-belgium (1)
- # clojure-dev (25)
- # clojure-estonia (1)
- # clojure-europe (16)
- # clojure-italy (11)
- # clojure-nl (4)
- # clojure-spec (90)
- # clojure-sweden (2)
- # clojure-uk (105)
- # clojurescript (58)
- # core-async (10)
- # cursive (23)
- # data-science (1)
- # datascript (3)
- # datomic (14)
- # duct (11)
- # fulcro (48)
- # graphql (1)
- # hyperfiddle (3)
- # kaocha (95)
- # liberator (1)
- # lumo (6)
- # nrepl (1)
- # off-topic (14)
- # onyx (2)
- # overtone (8)
- # portkey (3)
- # re-frame (31)
- # reagent (6)
- # shadow-cljs (185)
- # sql (12)
- # tools-deps (6)
- # vim (6)
- # yada (224)
evaluating a module that contained code instantiating this type:
(deftype MockRemote [query-map error-map]
dp/IDataRemote
(query! [this query config]
(-> (p/delay 100)
(p/then
(fn []
(when (contains? error-map query)
(throw (error-map query)))
(if (contains? query-map query)
(query-map query)
(query-map :mock/default)))))))
completely failed in a release buildthe error at runtime:
Error: 1
at modulemanager.js:588
at $goog$module$ModuleLoadCallback$$.execute (moduleloadcallback.js:60)
at $JSCompiler_StaticMethods_callCallbacks_$$ (moduleinfo.js:324)
at $JSCompiler_StaticMethods_onError$$ (moduleinfo.js:287)
at $JSCompiler_StaticMethods_dispatchModuleLoadFailed_$$ (modulemanager.js:1261)
at $JSCompiler_StaticMethods_requeueBatchOrDispatchFailure_$$ (modulemanager.js:1193)
at $goog$module$ModuleManager$$.$APP.$JSCompiler_prototypeAlias$$.$handleLoadError_$ (modulemanager.js:1146)
at $JSCompiler_StaticMethods_evaluateCode_$$ (moduleloader.js:373)
at $goog$module$ModuleLoader$$.$APP.$JSCompiler_prototypeAlias$$.$handleSuccess_$ (moduleloader.js:256)
at $JSCompiler_StaticMethods_fireListeners$$ (eventtarget.js:284)
at $goog$net$BulkLoader$$.$APP.$JSCompiler_prototypeAlias$$.dispatchEvent (eventtarget.js:381)
at $goog$net$BulkLoader$$.$APP.$JSCompiler_prototypeAlias$$.$handleSuccess_$ (bulkloader.js:168)
at $goog$net$BulkLoader$$.$APP.$JSCompiler_prototypeAlias$$.$handleEvent_$ (bulkloader.js:118)
at $JSCompiler_StaticMethods_fireListeners$$ (eventtarget.js:284)
at $goog$net$XhrIo$$.$APP.$JSCompiler_prototypeAlias$$.dispatchEvent (eventtarget.js:381)
at $JSCompiler_StaticMethods_onReadyStateChangeHelper_$$ (xhrio.js:867)
changing it to
(p/promise
(fn [resolve _]
(js/setTimeout #(resolve "resolved") 100)))
resolved the issuesay I want to distribute a cljs component through clojars. the component has some css and depends on some npm modules.
- how do I indicate that the component depends on certain npm modules?
- how do I deal with css? I know I can put it under resources
, but is there a better way?
thx
css is highly dependent on what users use to build their css. don't think there is a good way for this currently. css support is still in the planning stages for shadow-cljs.
thank you for the npm-deps
tip. regarding the css, re-com is just bundling it inside resources/public/assets/css
and I think that's good enough
but I guess it works when using a using a java webserver serving the public
resources
what do you suggest? the main user of this "component" is me. I'd like to @import
it in my scss code but I won't be able to if it's a resource
my plan was to simply require it in the HTML code along the css file compiled from scss
I already have code to run the scss compiler from clojure, more code to move files around won't bother me much
but, regarding the path, is it a good idea to do this? resources/{groupId}/{artifactId}/{version}/main.css
?
or without the version
nah without version. I would just namespace it normally. resources/your/lib/foo.css
Hi, I split my code using the method described on https://shadow-cljs.github.io/docs/UsersGuide.html#_modules , but :advanced
optimization errors Uncaught ReferenceError: Oe is not defined
. I tried :simple
optimization, no error occurs. Is that related to the code splitting during :advanced
?
@cmal try :advanced
with shadow-cljs release your-build --pseudo-names
to find out what Oe
is. I always use :advanced
with :modules
so it should work
are you doing anything with the code after shadow-cljs is done with it? any other processing like adding a wrapper or so?
This is what I use
:app
{:target :browser
:output-dir "./min"
:compiler-options {:source-map true}
:modules {:application {:init-fn app.core/run}}}}}
You can read more about it here: https://shadow-cljs.github.io/docs/UsersGuide.html#compiler-options
:foreign-libs
are intentionally not support at all. so no there is no way to use it with shadow-cljs. https://shadow-cljs.github.io/docs/UsersGuide.html#cljsjs
Hi, I am building a full stack web app and currently using lein and cljsbuild for compilation. (Based on reframe lein template.) I am thinking of switching to shadowcljs for npm support. What is the workflow for web server compilation, to produce uberjar?
if you're deploying an uberjar with your front-end CLJS compiled code inside of it (e.g. in resources
), then you'll run the CLJS compilation step first. Then create the uberjar. Then deploy the uberjar
is it recommended to use shadow-cljs from lein project file?
what a lot of people do is put their CLJ (Java) dependencies in their project.clj, and their CLJS dependencies in their shadow-cljs.edn
I see, do you have an example of some simple project so I could take a look how is everything set up?
I wonder — could I use React Native as the host for shadow-cljs? https://code.thheller.com/blog/shadow-cljs/2017/10/14/bootstrap-support.html says that First you need a “host” build which will be your “app” (currently limited to :browser builds).
Basically what I have is some code that needs to be run in a bootstrapped environment that I want to be able to be run in both simple and advanced compilation modes in both the browser and in React Native. Also in simple mode I'd like it to be able to be auto-reloadable like Figwheel. I know shadow-cljs can do most of this but the things in question are 1) advanced compilation mode for bootstrapped and 2) bootstrap + React Native
A big ask, I know 😄 If there's code to be written I'd be happy to lend a hand. But if there's an out-of-the-box solution I'll take that
Hmm, that’s disappointing @lilactown… I had figured that if I used google-closure-compiler-js
or rather the JS version of google-closure-compiler
it might work
Basically what I’m needing is for the source language to be the same as the compilation language. This is because I’m trying to create a type system that is able to leverage arbitrary spec-like predicates by evaluating them at compile time to elide as many runtime checks as possible.
I assume that requires a bootstrap build
So like (defmacro abc [] (do-this-in-cljs-not-clj))
e.g. (defmacro abc [x] (js/parseInt x))
Currently when compiling CLJS, any code inside macros is evaluated in CLJ
Only the code outputted from the macro is evaluated in CLJS
So like in CLJS if you did (defn abc [x] (js/parseInt x))
that’s fine, but (defmacro abc [x] (js/parseInt x))
it would fail off the bat since you can’t defmacro
in CLJS without bootstrap anyway
Ehh never mind, maybe I answered my own question
What are you surprised about haha?
Never mind haha I think I answered it
I think if I'm understanding correctly, you actually want shadow-cljs, the tool to run in CLJS?
No, I don’t think so
shadow-cljs is a JVM program, so it's always going to evaluate your macros etc. at compile-time in a JVM context
I haven't explored this at all, but maybe something like lumo, which is a completely self-hosted compiler, could do what you're looking for
shadow-cljs bootstrap' support is simply going to push those macro expansions to runtime, which it doesn't sound like is what you want?
Ohh okay yeah then perhaps shadow-cljs is not what I’m looking for
I do want to evaluate the CLJS forms at compile-time
Though I’m not sure Lumo supports useful things like auto-reloading etc.
Might have to hack this together
I'm curious why you need the compile-time evaluation context to be the same as the runtime?
I’m trying to build a type system. An example might be this:
(t/defn append! [s #?(:clj (t/isa? java.lang.StringBuilder) :cljs (t/isa? js/StringBuffer)), x string?] #?(:clj (.append s x) :cljs (.join s x)))
So a typed function that takes a StringBuilder in CLJ or js/StringBuffer in CLJS
And appends it
The type system will need to know at compile time whether callers of append!
are indeed providing a js/StringBuffer
or not
So like (append! 123 "abc")
would fail whereas (append! (js/StringBuffer.) "abc")
would succeed, both at compile time
If you wrap it in a macro, e.g. let’s call it t/dotyped
, it can analyze the forms and see in (js/StringBuffer.)
that it’s a constructor (`new` form), which returns a class of whatever the first argument is (in this case js/StringBuffer
). The compiler can then evaluate the symbol 'js/StringBuffer
to the actual class
Then do an inheritance (well, equality) check of the evaluated symbol against the actual js/StringBuffer
I’ve got it to work with something similar in CLJ (and much more complex things)
I don’t see why it couldn’t in CLJS if the compiler were written in JS/CLJS
Good point — it would only know the type of str-buf
which is a js/Function
; it wouldn’t have any knowledge about the internals of str-buf
However
This is why I would use t/fn
in that case
So like (def str-buf (t/fn [] (js/StringBuffer.)))
In that case the compiler would know what the return type of str-buf
is
Because the type of str-buf
would be (t/ftype [> (t/isa? js/StringBuffer)])
i.e. a function that takes no args and returns a js/StringBuffer
, when str-buf
is called, (dotyped (append! (str-buf) "abc")
would know the type
but it sounds like at some point you're going to have to eval the entire program with this strategy
Yes incrementally
That’s what macros do anyway in CLJ
Yes they emit code but then that code is evaluated in CLJ
I’m speaking only about compile time
That is definitely one strategy
But I want this to work for arbitrary predicates
Not just concrete classes / interfaces
The type system does work in Clojure 🙂
evaluating arbitrary predicates at compile time is an open area of research. see experimental languages like Idris that implement dependent types
For instance (t/defn f [m (t/and t/map? my-arbitrary-predicate)] ....)
, then (t/dotyped (f {:a 1 :b 2}))
can be checked at compile time
Granted, in the case of (t/fn [m t/map?] (f m))
, my-arbitrary-predicate
will have to be checked at runtime
So there are quagmire-y things to be sure
Then it fails
With something like “cannot resolve symbol”
No at compile time (assuming a CLJS-in-CLJS compiler)
Of course maybe the runtime has a different environment than the compile-time environment i.e. runtime has js/StringBuffer, compile-time doesn’t
But I feel like that point you’re on your own haha
I mean yeah this is why if you’re using the type system on things that may or may not be there you might have to polyfill as a fallback
Or just don’t use those things that may or may not be there
There may be other strategies of course, like not using the type system for those things, or falling back to runtime type checking in those cases
i guess my point is that I don't know what you buy for moving your type system to run in CLJS at compile-time
Perhaps the effort is more than it’s worth, I don’t know
But it seems like more of a pain to support an arbitrary predicate that uses some CLJS-specific thing but can only be symbolically analyzed (i.e. does the symbol js/StringBuffer
equal the symbol js/StringBuffer
?)
For instance if you did (t/defn f [x my-arbitrary-predicate] ...)
and (t/dotyped (f "asd"))
you could run my-arbitrary-predicate
in CLJ at compile-time to figure out type-satisfaction, whereas in CLJS you’d always have to resort to runtime type checking
Maybe that’s a small price to pay to stay within the non-bootstrapped ecosystem, not sure
Perhaps what I’ll do for CLJS is only do symbolic analysis falling back to runtime checking to begin with. Then for those use cases where that isn’t good enough, weigh that against switching to bootstrapped CLJS. I can’t think up all the cases ahead of time, to be fair
Anyway thanks for your help!
but I think that the fact that js/StringBuffer
in your type-checking program is the same as js/StringBuffer
at runtime is only accidental
Yeah fun chat! 🙂 If you want to keep talking about it that’s fine! I just didn’t want to be a pain with my counterarguments haha
'js/StringBuffer' in your type-checking program is the same as 'js/StringBuffer' at runtime is only accidental
→ I get what you’re saying. For instance js/StringBuffer
might mutate or something, or be completely different in compilation than at runtime
Clojure doesn’t have any of these (ahem) fun little intricacies… it would be nice for CLJS to, well, play just as nicely as CLJ does haha
Clojure definitely has its own idiosyncrasies
But none so frustrating as the compile-time platform being (completely — not just like V8 vs SpiderMonkey) different than the runtime platform
host interop is kind of easiest thing to point at, but even something like:
(def a 1)
;; nested in some other code
.... (def a "foo")
(defn inc-a []
(+ a 1))
;; nested in some other code
.... (def a "foo")
My answer is just don’t do that hahawhat you end up doing is either using static analysis at a best guess (walking the AST, checking symbols, etc.), or you have to evaluate the persons entire program
You can find out a surprising amount of information — no “best guess” required — but yes if you look at the whole program, and evaluate key parts of it
being able to evaluate (def a 1)
and resolve that to a Number
or java.lang.Integer
doesn't buy you any more guarantees
If you did (t/def a 1)
then the type of a
would be (t/value 1)
which is a lot more useful than Number
or java.lang.Integer
I guess you could also just do a normal def
and it would resolve from the environment
But yeah you would have to evaluate the whole program
Anything that’s top-level anyway — anything that the (CLJ) compiler would normally evaluate
That’s already done in CLJ though, no?
Perhaps my understanding of CLJ compilation is flawed but I would be surprised
That’s interesting to me what you say
Like if ns A depends on ns B which is not in your source code (e.g. let’s say it’s in a jar on the classpath imported via Leiningen), my understanding was that the compiler evaluates ns A, and in order to do that, has to evaluate ns B
Of course if it’s a Java class then it just loads the class (but may not necessarily use it in such a way that its static
block is run as in Class/forName
)
That’s fair
Or as some say, “the bytecode is the .js file”
For CLJS compilation my understanding is that it works kind of like you seem to be getting at — it doesn’t actually evaluate the code, but rather analyzes it just enough (macroexpanding in the process) to generate JS code
Yeah so I’m suggesting that it would be much easier to enforce the contracts of the type system if the code were actually able to be evaluated, just as CLJ evaluates it
So yeah Lumo might be what I’m looking for
Like (t/defn [x my-arbitrary-predicate] ...)
requires that my-arbitrary-predicate
will have had to have been evaluated at compile time, not just symbolically analyzed, to truly enforce it
CLJ plays nicely with that; CLJS does not (barring e.g. Lumo)
So perhaps I’m misunderstanding what bootstrapping actually does; I thought [bootstrapping] = [CLJS in CLJS] = [CLJS compiled (well, transpiled) to JS via a CLJS compiler]
Or is bootstrapping just CLJS compiled as usual by CLJ, but provided with a compiler such that cljs.core/eval
works at runtime?
Ohhh so self-hosting ≠ bootstrapping?
Yes I do
Thanks so much for the clarification haha this explains quite a few things