clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
zendevil 2021-07-05T08:23:39.186500Z

Suppose I have a route called “/creators”. This is a reagent app and not a static page, so the javascript does the rendering in the browser and the /creators route sends the boilerplate html to the browser. However, the content to be shown at creators route also depends on values from the database, so not only do I want to send the boilerplate html, but also data from the database. How can I do both simultaneously? Follow up: Suppose that I have other microservices that produce values that need to be rendered in the /creators route, but since those have a higher latency, I would prefer to send what I can as soon as possible and wait for the other microservices to produce the result in the browser when they are done producing the result, kind of how in twitter, the menus load before the tweets do. How will I integrate those microservices with the main server that receives the request? The static response to be sent is:

(layout/render request "home.html")
and the db data to be sent is:
(r/response (get creators- (-> :req :query-params :id)))

p-himik 2021-07-05T09:51:12.187600Z

> I would prefer to send what I can as soon as possible Make / and /creators serve the exact same HTML and make only the frontend initiate data loading upon navigating to /creators. If you're also using re-frame, it's rather easy to do with kee-frame's controllers.

zendevil 2021-07-05T10:05:25.189100Z

I’m sending sequence of maps to the client:

({":db/id" 17592186045425, ":creator/id" "2hhae235", ":creator/name" "Carla Wonder"} {":db/id" 17592186045426, ":creator/id" "23we35", ":creator/name" "Killer Reapers"} {":db/id" 17592186045427, ":creator/id" "234w345", ":creator/name" "Autonomy Band", ":creator/img-src" "<https://c8.alamy.com/comp/BDB71Y/nervous-breakdown-the-rolling-stones-cover-band-from-halle-germany-BDB71Y.jpg>", ":creator/description" "A great band that has rocked the listeners since the 1990s. They released their latest album in 2021 and have only increased their fanfare since their inception with the album Blushes, which was released in 1992 to wide critical acclaim."} {":db/id" 17592186045420, ":creator/id" "23422344", ":creator/name" "Alpatoons"} {":db/id" 17592186045421, ":creator/id" "23ahjqg35", ":creator/name" "Head One Thousand"} {":db/id" 17592186045422, ":creator/id" "23aasg235", ":creator/name" "Purely Black"} {":db/id" 17592186045423, ":creator/id" "asgasg35", ":creator/name" "Headhead"} {":db/id" 17592186045424, ":creator/id" "23agha35", ":creator/name" "Head Fighters"})
However on the client, it gets converted to:
[{::db/id 17592186045425, ::creator/id "2hhae235", ::creator/name "Carla Wonder"} {::db/id 17592186045426, ::creator/id "23we35", ::creator/name "Killer Reapers"} {::db/id 17592186045427, ::creator/id "234w345", ::creator/name "Autonomy Band", ::creator/img-src "<https://c8.alamy.com/comp/BDB71Y/nervous-breakdown-the-rolling-stones-cover-band-from-halle-germany-BDB71Y.jpg>", ::creator/description "A great band that has rocked the listeners since the 1990s. They released their latest album in 2021 and have only increased their fanfare since their inception with the album Blushes, which was released in 1992 to wide critical acclaim."} {::db/id 17592186045420, ::creator/id "23422344", ::creator/name "Alpatoons"} {::db/id 17592186045421, ::creator/id "23ahjqg35", ::creator/name "Head One Thousand"} {::db/id 17592186045422, ::creator/id "23aasg235", ::creator/name "Purely Black"} {::db/id 17592186045423, ::creator/id "asgasg35", ::creator/name "Headhead"} {::db/id 17592186045424, ::creator/id "23agha35", ::creator/name "Head Fighters"}]
i.e. the keywords have two colons instead of one. Why is this the case, and how to fix this?

p-himik 2021-07-05T10:08:23.189200Z

Impossible to tell for sure without all the code that serializes the data and deserializes it.

p-himik 2021-07-05T10:09:39.189400Z

Perhaps, you have something like :keywords? true set on the deserialization side. Calling (keyword ":db/id") will return ::db/id.

danielneal 2021-07-05T10:15:48.191600Z

I’m getting an error “require not defined” when trying to build a single output file using figwheel.main build-once + webpack. The line in the compiled js giving the error is require("react") I’m guessing it’s somehow not bundling the node modules but I don’t know where to start figuring out how to fix it. Any pointers very welcome!! I don’t get the error in normal figwheel operation (with optimizations none)

admarrs 2021-07-05T10:21:55.193400Z

Is it possible to get shadow-cljs to release an app with a versioned name using something like lein-git-inject and lein shadow? I've got a full-stack clojure/clojurescript app and am trying to streamline the release process to add a version string in the .js file to overcome browser caching when pushing out a new version.

p-himik 2021-07-05T10:26:01.193600Z

There's also #shadow-cljs Shadow-cljs can generate output manifest specifically to tackle that issue: https://shadow-cljs.github.io/docs/UsersGuide.html#BrowserManifest It's not a version, but it's a sufficient mechanism to overcome browser caching.

zendevil 2021-07-05T10:27:24.193800Z

instead of making changes in the server, is it possible to use two colon keyworeds in the client?

p-himik 2021-07-05T10:30:45.194100Z

Yes, but don't do it. Three proper ways to tackle it: • Change the backend, if you have control over it - either to use a different format for keys or to use something other than JSON that preserves data type, like Transit • Do not convert data keys into keywords - just use strings. It makes sense because you seem to be sending strings in the first place. Keep keywords keywords and strings strings • Traverse the received data structure and convert all string keys that start with : to a keyword yourself

emccue 2021-07-05T13:19:22.194500Z

or, use transit on top of json instead of just json

emccue 2021-07-05T13:19:44.194700Z

that will serialize/deserialize keywords correctly

zendevil 2021-07-05T13:23:55.196100Z

I am mapping a sequence of maps like so across @(rf/subscribe [:creators]), however, I’m still getting the react unique key error in the console, while each creator does have a unique id with (:creator/id creator)

(defn creator-view [creator]
  [:a {:key (:creator/id creator) :href (str "/creator-page?id=" (:creator/id creator)) :style {:cursor :pointer}} (:creator/name creator)])

(defn creators []
  [:div {:style {:display :flex :flex-direction :column}}
   (map (fn [creator]
          (prn "creator id " (:creator/id creator))
          [creator-view creator]) @(rf/subscribe [:creators]))
   ])
react.development.js:221 Warning: Each child in a list should have a unique “key” prop. Check the render method of creators. See https://reactjs.org/link/warning-keys for more information. at cmp (http://localhost:3000/js/cljs-runtime/reagent.impl.component.js:496:43) at cmp (http://localhost:3000/js/cljs-runtime/reagent.impl.component.js:496:43) at div at div at cmp (http://localhost:3000/js/cljs-runtime/reagent.impl.component.js:496:43)

p-himik 2021-07-05T13:27:57.196600Z

Your [:a ...] elements have unique keys. React complains about the [creator-view ...] elements. Even if it doesn't result in a separate HTML node for creator-view, it's still a React element.

zendevil 2021-07-05T13:30:31.196800Z

so the best bet is wrapping creator-view in div and putting a key there?

2021-07-05T13:31:47.197Z

Either use into with your map or add the key as metadata

2021-07-05T13:32:35.197200Z

(into [:div {:style {:display :flex :flex-direction :column}}] (map (fn [creator]
          (prn "creator id " (:creator/id creator))
          [creator-view creator]) @(rf/subscribe [:creators])))

2021-07-05T13:32:38.197400Z

something like that

zendevil 2021-07-05T13:33:29.197600Z

how does the metadata thing work?

p-himik 2021-07-05T13:34:16.197800Z

Reagent reads the metadata and sets the key when creating the corresponding React element.

p-himik 2021-07-05T13:35:08.198Z

And with into above, you don't need :key at all since all the laziness is removed. But I've seen such a method being discouraged because, depending on the circumstances, the performance might suffer.

zendevil 2021-07-05T13:35:42.198200Z

how to set the key in the metadata exactly?

p-himik 2021-07-05T13:36:04.198400Z

^{:key (:creator/id creator)}
[creator-view creator]
Can be in a single line if you prefer.

p-himik 2021-07-05T13:38:51.199Z

Are you sure :creator/id is always set and is unique across all records? Are you sure it's the creators component and not something else? - ah, right, the error mentions it explicitly. Unless there are multiple components named like this. Does the error disappear if you use the into method above?

danielneal 2021-07-05T15:07:04.200300Z

I’ve made a minimal repro of my figwheel.main “require not defined” error, can anyone spot what dumb mistake / misunderstanding I’m making? https://github.com/danielneal/figwheel-webpack

danielneal 2021-07-05T15:28:43.201400Z

^ The issue was that webpack wasn’t running, I’m guessing the bundle-cmd is a map of optimisation level to bundle cmd, I’d completely overlooked that I only had :none &lt;bundle-cmd&gt; in there and nothing for :default (or :advanced)

danielneal 2021-07-05T15:28:56.201600Z

😅

thheller 2021-07-05T16:06:41.201800Z

https://github.com/day8/shadow-git-inject

thheller 2021-07-05T16:07:31.202100Z

but yeah the manifest is the intended solution for this when combined with :module-hash-names true

clj8394 2021-07-05T16:37:33.208500Z

hello, wanted to share my feedback with cljs so far and see how I can improve further. I have gotten used to the syntax and all that, the language itself is well designed and easy to use, in these respects i am having no issues. the issue i am having is in regards to tooling, specifically on the IDE side of things. Im currently using vscode with the calva extension, and can connect to a repl, so can get feedback quickly and the repl works well. but, I currently dont know of any extensions that provide linting, autocompletion for NPM modules, and debugging. I could probably live without these features, but I think they are very useful to have and want to see what's available for vscode that might do these things. Anyone know of any tools for this?

pez 2021-07-05T16:42:40.209300Z

Calva should give you linting. Doesn't it?

pez 2021-07-05T16:45:23.211600Z

As far as debugging goes, that is not really available afaik. I seldom lack it, though. Especially since I'm often using shadow-cljs and it's excellent inspector.

clj8394 2021-07-05T16:55:06.211800Z

i see source formatting but don't see linting for anything like missing function name, For example, if i write a function but never use it the editor doesnt catch it

pez 2021-07-05T17:12:22.212700Z

It should work. If your code is public I can have a look.

clj8394 2021-07-05T17:39:40.212900Z

im trying again with a simple hello world example. I have a function

(defn hello-world "hello world")
and am not using it, but the IDE isn't giving me a warning that it isn't being used

clj8394 2021-07-05T17:41:24.213100Z

maybe its an issue with my machine, I see Initializning Clojure Language Features via clojure-lsp in the bottom left corner of the editor. Maybe that's why im not getting having issues?

clj8394 2021-07-05T17:41:31.213300Z

I can connect to the repl fine

clj8394 2021-07-05T17:44:50.213500Z

also, regarding debugging, is there no way to use the source maps with a debugger? im not familiar with shadow-cljs, how does the inspector work with it? Im primarily trying to use clojurescript through node and not in the browser

clj8394 2021-07-05T18:09:43.213700Z

i did some testing, it seems that when I have a deps.edn file, on my installation calva is not able to initialize the clojure-lsp for proper linting, but without deps.edn I cant connect to the repl

clj8394 2021-07-05T18:10:08.213900Z

any idea on what may be the issue here?

pez 2021-07-05T19:06:38.214800Z

Might be something to ask about in #lsp

borkdude 2021-07-05T19:21:00.215Z

yes, this should work right out of the box

clj8394 2021-07-05T19:22:59.215300Z

I asked in the #lsp channel. It does appear to be working probably when I don't have a deps.edn file in my workspace. not sure what is causing the issue here

clj8394 2021-07-05T19:44:51.215500Z

got it working, turns out it was a configuration issue on my end. thanks for the help yall

clj8394 2021-07-05T19:46:04.215700Z

also amazing stuff with this extension, thanks for all the hard work yall put in on making this

clj8394 2021-07-05T19:46:37.215900Z

one last thing @pez is there any way to change the colors of the parens, would like to use a custom scheme if possible

2021-07-05T20:21:51.220800Z

Hey all, trying to port this fragment from js to cljs: this.map = this.add.tilemap("tilemap"); The RHS is

(ocall this [:add :tilemap] "tilemap")
using https://github.com/binaryage/cljs-oops. To port the set operation I am doing
(aset this "map" (ocall this [:add :tilemap] "tilemap"))
. A few questions: • Is this the “correct” translation of this fragment? • The oset! function in cljs-oops doesn’t work, saying the key “map” is unexpected. I understand the warning, but I wonder if this is a hint that I should be doing something else. Any tips if this isn’t the right way to do it? • If it is right, I see that you can set with string keys or keywords (e.g. :map ). Is there any downside to that approach? Also note that I am getting this from the this-as macro if that matters.

2021-07-05T20:32:02.221300Z

I can also just store all desired created objects in an atom. This may be more Clojuric, but I also want to understand the js->cljs translation as well.

pez 2021-07-05T20:37:04.221800Z

There is! https://calva.io/customizing/

clj8394 2021-07-05T20:46:10.222100Z

awesome, will definitely check out the customization options! thanks for all the help

p-himik 2021-07-05T20:46:39.222300Z

aset is most definitely wrong because it's for arrays, not objects. You don't need cljs-oops either. oset! can work if you add ! to the non-existing key: :!map. This would be a 1-to-1 translation from JS to CLJS:

(this-as this
  (let [add (.-add this)
        tilemap (.bind (.-tilemap add) add)]
    (set! this -map (tilemap "tilemap"))))
And if tilemap doesn't need its this to be bound to add, you can remove the .bind part.

pez 2021-07-05T20:47:48.222500Z

About source maps. I’ve had some limited luck with using the Chrome debugger, but the source maps seem to be a bit lacking, so it hasn’t been worth the fiddling.

pez 2021-07-05T20:51:17.222700Z

shadow-cljs starts a console at http://localhost:9630 where, amongst other things, you find an inspector that will show you things that you tap&gt; from the REPL. And Calva has some commands for making tapping extra convenient. Shadow works great for node work as well as for the browser.

p-himik 2021-07-05T20:51:43.222900Z

Actually, I'm probably wrong about the need for bind - this should be sufficient:

(this-as ^js this
  (set! this -map (.. this -add (tilemap "tilemap"))))
Notice how I added ^js in this example - it's important for the advanced compilation to not munge -add and -map. I'm not 100% sure that tilemap will be preserved. If not, you need one extra ^js somewhere in that .. form.

🙏 2