Hi everyone, I have a question regarding file upload from drag & drop. I do it this way:
https://git.sr.ht/~tyruiop/constellation/tree/main/item/viz/src/main/viz/sidebar.cljs#L233
And it works perfectly fine with firefox, however with Chromium datatransfer remains empty no matter what I do, any idea how to solve it? All the solutions I found on stackoverflow for javascript just didn't work
Nevermind, the problem came from Wayland, it works just fine with Xorg
yes
> GET http://localhost:9000/out/brepl_deps.js net::ERR_ABORTED 404 (Not Found) I'm also bothered by that.
Nvm, I nailed it! This guide here is outdated: https://clojurescript.org/guides/webpack
Is there a guide somewhere about what the Closure Compiler has trouble with when eliminating code?
anything with side effects or what it thinks may be side effects 😉 not aware of more precise docs
I think it struggles with laziness in general, probably fearing side effects. For instance it doesn't seem to remove things like (def foo (concat ...))
That might explain why my advanced builds are usually fat and seem to include quite a lot of unneeded junk (looking at Shadow's report). So I am wondering if it's worth the trouble to wrap top-level vars in some way, or wrap those top-level values in a (delay)
for instance.
yes, laziness is not something it understands. (delay)
works
Then library authors should know about this as it is not something you think about too much unless you're doing a lot of CLJS.
I'm working on a small personal blog app on clojurescript using reagent and reitit as a router. For some reason component isn't updated when atom is. There is a post on Reagent docs on this proble. But it didn't helped: https://cljdoc.org/d/mthomure/reagent/0.8.1-custom-components/doc/frequently-asked-questions/why-isn-t-my-component-re-rendering- May be someone ran into same problem or it's something obvious that I can't see. Here is the code for my post:
clojure
(ns posts.second-post
(:require [cljs-http.client :as http]
[cljs.core.async :refer [<! go] :as async]
[reagent.core :as reagent]))
(defonce d
(reagent/atom nil))
(defonce request
(go
(let [responce (<! (htt p/get "<https://www.google.com/>" {:with-credentials? false}))]
(reset! d responce))))
(def post
{:meta {:slug "first-post"}
;; UPDATE DOESN'T HAPPEND HERE!
:content [:span (str @d)]})
Here is the post view:
clojure
(ns blog.views
(:require [blog.config :refer [conf]]
[reagent.core :as reagent]
[clojure.string :as string]
[reitit.frontend.easy :as rfe]
[blog.posts :refer [posts]]
[cljs.core.async :refer [<! go]
...]))
(defn post
[match]
(let [{:keys [path]} (get match :parameters)
{:keys [slug]} path
requested-post
(first
(filter
(fn [p]
(= slug (get-in p [:meta :slug]))) posts))]
(if (some? requested-post)
[:div (get requested-post :content)]]
[:span "Post not found")])))
And here is the code for my core (and router):
clojure
(ns blog.core
(:require [blog.views :as views]
[reagent.core :as reagent]
[reitit.frontend :as rf]
[reitit.frontend.easy :as rfe]
[reitit.coercion.spec :as rss]
[spec-tools.data-spec :as ds]
[reagent-material-ui.core.container :refer [container]]))
(defonce match (reagent/atom nil))
(defn current-page
[]
[container
(if @match
(let [view (:view (:data @match))]
[view @match]))])
(def routes
[["/"
{:name :frontpage
:view views/home}]
["/post/:slug"
{:name :post
:view views/post
:parameters
{:path
{:slug string?}
:query
{(ds/opt :lang) string?}}}]])
(defn start
[]
(rfe/start!
(rf/router
routes
{:data {:coercion rss/coercion}})
(fn [m]
(reset! match m))
;; set to false to enable HistoryAPI
{:use-fragment false})
(reagent/render
[current-page]
(.getElementById js/document "app")))
(defn ^:export init []
;; init is called ONCE when the page loads
;; this is called in the index.html and must be exported
;; so it is available even in :advanced release builds
(start))
(defn stop []
;; stop is called before any code is reloaded
;; this is controlled by :before-load in the config
(js/console.log "stop"))
I don't see how exactly you're using that posts.second-post/post
.
Also, consider creating code snippets instead of code blocks when your code is rather long. The snippets are collapsed by default which makes it much easier to navigate the rest of the channel.
Thnx. I will try snippets next time.
(ns blog.posts
(:require [posts.first-post :as first-post]
[posts.second-post :as second-post]))
(def posts
[first-post/post
second-post/post])
I need to see the view that ends up using posts.second-post/post
. Anything else is irrelevant, at least right now.
A ratom change causes a view to re-render when both of these conditions are met:
- That ratom was deref'ed in that view
- That view function was used with [...]
and not with (...)
maybe reading https://code.thheller.com/blog/shadow-cljs/2019/08/25/hot-reload-in-clojurescript.html will help
the trouble is most likely holding on to a reference of other namespaces that aren't directly reloaded
see "Holding Code references in State"
(def posts
[first-post/post
second-post/post])
(ns blog.views
(:require [blog.config :refer [conf]]
[reagent.core :as reagent]
[clojure.string :as string]
[reitit.frontend.easy :as rfe]
[blog.posts :refer [posts]]
[cljs.core.async :refer [<! go]
...]))
(defn post
[match]
(let [{:keys [path]} (get match :parameters)
{:keys [slug]} path
requested-post
(first
(filter
(fn [p]
(= slug (get-in p [:meta :slug]))) posts))]
(if (some? requested-post)
[:div (get requested-post :content)]]
[:span "Post not found")])))
is a good example of this pattern that should be avoided
That's the view
@altjsus My bad, the error is actually visible before that. You @
the ratom way before it gets into the view - when you assign the value to def
. It's executed when the resulting JS bundle is loaded - Reagent has no way of knowing that there's a ratom involved at all.
As I said, put all @
on ratoms in view functions. Or in regular functions, but then call those functions only from the view functions.
@thheller I think there's a misunderstanding and it has nothing to do with hot code reloading.
But still - how can the code piece that you quoted cause any issues, given that it's def
and not defonce
? Because first-post/post
is in a different NS that, when changed, won't cause the namespace of posts
to be reloaded?
a -> b -> c when you make changes in c then only b is automatically updated as well but not a. so if a is holding a reference of b that is holding a reference of c then a will become stale after an update in c
And there's no feasible way to circumvent this, is there?
I mean, automatically, without having to wrap everything in lambdas and var stuff.
The current situation is it's only shown on code changed and shadow-cljs reloaded. It's kinda works on recompiling only.
I guess.
That's the current state of the problem.
well you can use :devtools {:reload-strategy :full}
but that will make every reload slower
Nope. Again I don't want to change my reload strategy. This piece don't works as expected even when code is compiled and served with another server.
The problem seems-like to be described by @p-himik
from what I can tell you are putting the reitit match data into an atom
Yes, I kinda hijacked this thread to ask thheller about a way to fix a hypothetical code reloading issue.
Your problem has nothing to do with that. As soon as you move that @
inside a view, it will be working properly.
@thheller Wrong atom. :)
that match data contains a direct reference to a view function
you update the code but the match still contains the old view function
tada you have a stuck hot-reload but I'm not entirely sure this is actually what is happening
Nope, that's not the described problem. Read the end of the very first code block in the OP.
I don't understand what should I fix right now.
@altjsus You have to change quite a lot - you cannot just inline the value of @d
like that. You have to call it when the view is rendered, not before that.
Here's something that's similar to what you're doing:
(def a (reagent/atom 0))
(def b (inc @a))
(defn view []
[:span b])
It will not work because b
is set when the JS is evaluated.
Instead, something like this needs to happen:
(def a (reagent/atom 0))
(defn b []
(inc @a))
(defn view []
[:span (b)])
Now that @
is called only when the view is rendered, not before. And it makes it possible for Reagent to start tracking that ratom for changes.
Can anybody suggest a replacement for goog.dom.query
that was removed from Google Closure? I am trying to fix up some old code that uses query
.
Ok.
Thnx.
(js/document.querySelectorAll ".foo")
But what thheller has said will likely bite you later, so you might want to follow his advice as well.
Dos it also cover things like ".foo li label"
? @thheller
yep, pretty much all the same queries (and more) are supported
it just became a browser standard (a long time ago, so even old browsers support it)
Thanks!
Thanks a lot. I don't know the workaround yet, but I will most likely share it in this theead.
I've got it. Changed the view to:
[:div
((get requested-post :content))]
;; note the double parens
and the post itself to:
(def post
{:meta {:slug "first-post"}
;; UPDATE DOESN'T HAPPEND HERE!
:content (fn [] [:span (str @d)])})
Applying directly what you've said. Thanks/
When using https://clojurescript.org/guides/webpack, with assets https://webpack.js.org/guides/asset-management/#loading-css, is there a way to import './style.css';
from cljs files? Mind you, the goal here is to load 3rd party css.
Just a guess - you can probably do that with the js*
special symbol.
I saw a colleague use this js*
once, but I found no docs for it since. Any tips?
nvm, found (js* "alert('xyz')")
Yeah, I usually just look at the sources - cljs/core.cljs
or cljs/core.cljc
.
Whines: "Can't import outside a module". I'll just make a special pack.js where I add all the css, and add it to webpack emit.
Hi there 🙂,
it seems to me I found a bug in cljs core.async
(`clj` works well). Do you guys agree with me? How to report it?
The issue:
(cljs.core.async/go
(println "XXX vorher")
(let [old 1
new „my-new"]
(println "XXX nacher")
(println [old new])))
=> „XXX vorher"
=> „XXX nacher"
=> TypeError TypeError: 1.call is not a function
Changing the new symbol to xnew works:
(cljs.core.async/go
(println "XXX vorher")
(let [old 1
xnew „my-new"]
(println "XXX nacher")
(println [old xnew])))
=> „XXX vorher"
=> „XXX nacher"
=> [1 „my-new"]
The following snippet of macroexpanding shows the error I mean. The new
for instantiating cljs.core/PersistentVector
got resolved with the value I bound to new
...
(clojure.core/let
[inst_35971
(println "XXX nacher")
inst_35972
(. cljs.core/PersistentVector -EMPTY-NODE)
inst_35973
(js* "[{},{}]" 1 "my-new")
inst_35974
("my-new"
cljs.core/PersistentVector
nil
2
5
inst_35972
inst_35973
nil)
inst_35975
(println inst_35974)
state_35977
…]
…))
So do not use new
as symbol! :-$Looks like a bug to me. The right process to report such things is outlined in the first section here: https://clojure.org/dev/creating_tickets
has anyone tried to spin up shadow-cljs with 2 build ids where there is :main electron :ui reagent and then a server.cljs file for express-node?
I've just been running shadow-cljs watch main ui
and then launching the express server from the repl, but i can already tell this is just hacky
having issues with express, I might need to rethink my plan
Hands up if you've completed the clojure survey
whats the issue? i often have 2 or more builds running
so i actually have 3 builds lol, kinda got it to work by calling my main server within the :main electron file, but this didn't provide HMR because it's just 2 and I was trying to make a 3rd one specifically for express
I'm seeing some unexpected results when benchmarking transducers:
I would expect this: (into [] (comp (map inc) (filter even?)) (take 100000 (repeatedly #(rand-int 2))))
to be faster than this: (->> (take 100000 (repeatedly #(rand-int 2))) (map inc) (filter even?))
But the transducer version is actually much slower (~30ms vs. 1.5ms)
reading it back doesn't even make sense 😅 I'll push this to github real quick where it was sort of working
Extra into
there, how about without it?
this is laziness vs realizing a large vector here
the second is doing almost no work. the first form is doing all of the work and constructing a vector around the results to boot
wrap a doall
around the second to get apples to apples
ah, got it
results make more sense now
thanks guys