Fork me on GitHub
#clojurescript
<
2021-03-29
>
valerauko02:03:36

What's the CLJS equivalent of a JS for await (const item of channel)?

raspasov08:03:52

There’s no “await” in ClojureScript; some discussion here: https://groups.google.com/g/clojurescript/c/scUMhU-ctEM

valerauko09:03:48

Yeah this was much more pain than it should be.

valerauko09:03:18

Made an example wrapping Deno's HTTP server. Plenty of rough edges... https://github.com/valerauko/cljs-deno-example

thheller10:03:30

deno has a (http/listenAndServe options (fn [req] ...)) which makes for a much easier API from CLJS than using the await asynciterator stuff

💯 3
valerauko10:03:27

yay time to use that instead!

tvirolai06:03:42

I'm having trouble compiling a ClojureScript project to a React component to be used in JavaScript. The problem seems to be related with Material UI, which the project is using. When I'm trying to render the exported component on the JavaScript side, I'm getting an error, the full stack trace is in the thread. This is the kind of export I'm trying to do. Here, export1 works and export2 produces the error, as it contains a component from Material UI.

(ns testinki.core
  (:require [reagent.core :as r]
            [reagent.dom :as d]
            [reagent-material-ui.core.chip :refer [chip]]))

(defn export1 []
  (r/create-element (r/reactify-component (fn []
                                            [:div [:h2 "Hi guys"]])) #js{}))
(defn export2 []
  (r/create-element (r/reactify-component (fn []
                                            [:div [:h2 "Hi there"]
                                             [chip {:label "Hello again"}]])) #js{}))
The problem seems to be related the use of React Hooks inside Material UI, right? Is there a workaround for exporting components using Material UI? I tried googling the issue but can't seem to figure it out.

tvirolai06:03:39

Uncaught Error: Minified React error #321; visit  for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at z (testproject.js:14)
    at Object.d.useContext (testproject.js:20)
    at b.default (testproject.js:408)
    at testproject.js:421
    at testproject.js:437
    at renderWithHooks (react-dom.development.js:14985)
    at updateForwardRef (react-dom.development.js:17044)
    at beginWork (react-dom.development.js:19098)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
    at invokeGuardedCallback (react-dom.development.js:4056)
    at beginWork$1 (react-dom.development.js:23964)
    at performUnitOfWork (react-dom.development.js:22776)
    at workLoopSync (react-dom.development.js:22707)
    at renderRootSync (react-dom.development.js:22670)
    at performSyncWorkOnRoot (react-dom.development.js:22293)
    at scheduleUpdateOnFiber (react-dom.development.js:21881)
    at updateContainer (react-dom.development.js:25482)
    at react-dom.development.js:26021
    at unbatchedUpdates (react-dom.development.js:22431)
    at legacyRenderSubtreeIntoContainer (react-dom.development.js:26020)
    at Object.render (react-dom.development.js:26103)
    at Module.<anonymous> (index.js:7)
    at Module../src/index.js (index.js:18)
    at __webpack_require__ (bootstrap:856)
    at fn (bootstrap:150)
    at Object.1 (reportWebVitals.js:14)
    at __webpack_require__ (bootstrap:856)
    at checkDeferredModules (bootstrap:45)
    at Array.webpackJsonpCallback [as push] (bootstrap:32)
    at main.chunk.js:1
z @ testproject.js:14
d.useContext @ testproject.js:20
b.default @ testproject.js:408
(anonymous) @ testproject.js:421
(anonymous) @ testproject.js:437
renderWithHooks @ react-dom.development.js:14985
updateForwardRef @ react-dom.development.js:17044
beginWork @ react-dom.development.js:19098
callCallback @ react-dom.development.js:3945
invokeGuardedCallbackDev @ react-dom.development.js:3994
invokeGuardedCallback @ react-dom.development.js:4056
beginWork$1 @ react-dom.development.js:23964
performUnitOfWork @ react-dom.development.js:22776
workLoopSync @ react-dom.development.js:22707
renderRootSync @ react-dom.development.js:22670
performSyncWorkOnRoot @ react-dom.development.js:22293
scheduleUpdateOnFiber @ react-dom.development.js:21881
updateContainer @ react-dom.development.js:25482
(anonymous) @ react-dom.development.js:26021
unbatchedUpdates @ react-dom.development.js:22431
legacyRenderSubtreeIntoContainer @ react-dom.development.js:26020
render @ react-dom.development.js:26103
(anonymous) @ index.js:7
./src/index.js @ index.js:18
__webpack_require__ @ bootstrap:856
fn @ bootstrap:150
1 @ reportWebVitals.js:14
__webpack_require__ @ bootstrap:856
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
index.js:1 The above error occurred in the <ForwardRef> component:

    at 
    at div
    at c ()
    at ex_testproject_Component2
    at div
    at App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit  to learn more about error boundaries.

p-himik08:03:15

If it works in the dev setup, then it should work in production as well. Really strange to see that error. You can try replacing (r/create-element (r/reactify-component ...)) with just (r/as-element ...). And if the code above doesn't work in dev as well, then Reagent documentation contains information how to create functional components that can work with hooks.

tvirolai09:03:44

Thanks, unfortunately that doesn't seem to help. To be clear, the application does work in the local development environment and I can get my it to work even in JavaScript side by exporting it as an ESM module (using Shadow-CLJS) that contains all the dependencies and mounts itself to a div id. However, when trying to get it to work as a React component like in the snippet below, I'm running to the error mentioned.

import { Component1 } from './testproject'

function App() {
  return (
    <div className="App">
        <Component1 />
    </div>
  );
}

export default App;

alpox10:03:44

Im not sure what the error could come from exactly but I would have expected that r/create-element shouldnt be used as react (JSX) expects a comonent and not an already created element

tvirolai11:03:24

The strange thing is, the setup for exporting a piece of Reagent as a React component works just fine if the code does not include Material UI components. So the crux of the matter seems to be the way Material UI uses React Hooks, which cannot be used in class components - which this setup produces...

p-himik11:03:49

IIRC the hooks cannot be used in a class component directly. So a class component is still able to use a function component that uses hooks. Maybe the advanced compilation somehow removes some thing function component layer and inlines it within the class component. But that seems like magic to me. Have you tried forcing Reagent to produce a function component from that particular [:div ...]?

valerauko09:03:18

Made an example wrapping Deno's HTTP server. Plenty of rough edges... https://github.com/valerauko/cljs-deno-example

simongray14:03:28

I would like to make a reagent wrapper library for a bunch of 10-year old JS code. The JS code itself bundles like 20 twenty different JS files that it needs. Is there some way to include this all of this JS code with the compiled ClojureScript bundle?

simongray14:03:17

I have lots of CLJS experience, minimal JS experience, and no experience trying to wrap JS code.

simongray14:03:38

Apparently there is an issue for the lack of documentation: https://github.com/clojure/clojurescript-site/issues/224

thheller14:03:52

@simongray how is the JS bundled and used now?

thheller14:03:46

and why do you intend to bundle it together with the CLJS code? why not just keep it as a separate script?

simongray14:03:13

How would I distribute it as a library then?

simongray14:03:26

And honestly, I would prefer more explicit dependencies than this automagic script

thheller14:03:29

well from glancing at this code I can tell you that this is not going to be fun. the code is clearly not written in a bundler friendly style so you are going to have to make adjustments no matter what

simongray14:03:42

My plan was to make som adjustments either way, remove as much as possible and bundle the remainder together with some CLJS to make a reagent component

thheller14:03:47

so this code is really designed to be included as a separate script tag. the bundler cannot change that really your only option is rewriting the code

simongray14:03:43

so the bundler you’re talking about is ClojureScripts built-in way to handle foreign libs?

simongray14:03:32

The files that end up being included look like this

thheller14:03:30

bundler as in generic term for bundler. be that CLJS, shadow-cljs, webpack or really anything bunlding JS

thheller14:03:52

:foreign-libs will not help you here (especially since shadow-cljs doesn't support them)

simongray14:03:12

I really just need a way to load a bunch of JS code in advance

simongray14:03:58

whatever is the shortest path there, I’ll take ity

thheller14:03:13

I can give you shadow-cljs specific options but those will not work with regular CLJS

simongray14:03:17

I was really just trying to see if there was a way to make a CLJS lib that includes some JS. I guess that is not the case?

simongray14:03:46

if it’s just for my own project, I guess I can simply include the JS file that loads everything in the index.html

simongray14:03:10

and then call the JS methods from ClojureScript

thheller14:03:07

:foreign-libs would be the way to go for regular CLJS, after adjusting the code of course.

thheller14:03:51

looks a bit different for shadow-cljs, same idea but different code adjustments 😛

thheller15:03:12

there is one way to make it work generally but I'm unsure the code will actually survive :advanced so that might not work 😉

simongray15:03:41

@thheller Ok. And the regular CLJS way is not supported in shadow-cljs?

thheller15:03:54

:foreign-libs are not no. There is also CSS involved so honestly the best option for making this a library is given the users of the library instructions of where to put the code 😛

simongray15:03:23

I guess I will not be making a library then.

simongray15:03:52

@thheller If you don’t mind my asking, why don’t you support :foreign-libs?

simongray15:03:51

I mean, I get that it’s possibly not the ideal way to go and that shadow-cljs might do it better, but what about ecosystem cohesion?

simongray15:03:22

does supporting the one preclude supporting the other?

simongray15:03:01

@thheller that does assume that the only JS code worth using in CLJS comes from a Node package.

p-himik15:03:29

I wouldn't say so - you can use any local JS file with shadow-cljs.

simongray16:03:57

For your own project, but you can't use it to make a distributable library.

p-himik16:03:24

Ah, I see, right.

thheller16:03:04

as I said there is a way to make it work with all CLJS tools

simongray16:03:35

@thheller is there a guide somewhere?

thheller16:03:20

very difficult to write a generic guide for this since it depends entirely on how the actual JS you are trying to include this way is written

thheller16:03:54

in your case you'd use you'd put all the files from here

thheller16:03:02

into a directory on your classpath. or rather the source-path of the library you are writing

thheller16:03:03

say src/main/simongray/timeline/themes.js and so on

thheller16:03:22

then in that file you add a goog.provide("simongray.timeline.themes") as the first line

thheller16:03:52

with that you can include it in CLJS via (:require [simongray.timeline.themes])

thheller16:03:01

and in this case end up using it via js/Timeline

thheller16:03:33

you do this for every file and you are done. no extra :foreign-libs or so

thheller16:03:45

but since CSS is involved as well this approach doesn't really work

thheller17:03:41

I mean it works for the JS code sure but the consumer of your library would still need to do some kind of setup for the CSS

thheller17:03:04

if they are going to do that anyways you might as well give some extra instructions on how to include the JS separately as that library intends

simongray20:03:47

ok - thank you for the rundown

Ronny Løvtangen17:03:09

We had to integrate some react components bundled as a JS UMD build into our CLJS client built with leiningen. We managed to do so by using :foreign-libs and reagent.core/adapt-react-class project.clj:

:cljsbuild {:builds {:dhp-client
                       {:source-paths ["src/cljs"]
                        :compiler {:main dhp-client.core
                                   :language-in :ecmascript6
                                   :language-out :ecmascript5
                                   :foreign-libs [{:file "resources/lib/kartklient.js"
                                                   :provides ["markerMap" "routeMap" "setCoordinateMap" "setCoordinateOnRouteMap" "setMultipleCoordinatesMap" "setMultipleCoordinatesOnRouteMap"]
                                                   :global-exports '{markerMap MarkerMap
                                                                     routeMap RouteMap
                                                                     setCoordinateMap SetCoordinateMap
                                                                     setCoordinateOnRouteMap SetCoordinateOnRouteMap
                                                                     setMultipleCoordinatesMap SetMultipleCoordinatesMap
                                                                     setMultipleCoordinatesOnRouteMap SetMultipleCoordinatesOnRouteMap}}]}}
Helper:
(ns dhp-client.helpers.kartklient
  (:require [reagent.core :refer [adapt-react-class]]
            [markerMap :as markerMap]
            [routeMap :as routeMap]
            [setCoordinateMap :as setCoordinateMap]
            [setCoordinateOnRouteMap :as setCoordinateOnRouteMap]
            [setMultipleCoordinatesMap :as setMultipleCoordinatesMap]
            [setMultipleCoordinatesOnRouteMap :as setMultipleCoordinatesOnRouteMap]))

(def marker-map (adapt-react-class markerMap))
(def route-map (adapt-react-class routeMap))
(def set-coordinate-map (adapt-react-class setCoordinateMap))
(def set-coordinate-on-route-map (adapt-react-class setCoordinateOnRouteMap))
(def set-multiple-coordinates-map (adapt-react-class setMultipleCoordinatesMap))
(def set-multiple-coordinates-on-route-map (adapt-react-class setMultipleCoordinatesOnRouteMap))
Usage:
[kk/route-map
        {:data kartdata
         :apikey api-key}]

wombawomba19:03:59

How can I delete a __Host-prefixed cookie with CLJS? I'm able to delete it in JS using document.cookie = "__Host-Foo=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; secure'" but neither (.remove .cookies) nor (.remove .cookies "/" nil) nor (.clear .cookies) seem to work.

wombawomba19:03:54

I was finally able to expire it via (.set .cookies "__Host-Foo" "" 0 "/" nil true) 🙂