What's the CLJS equivalent of a JS for await (const item of channel)
?
Take a look at https://clojurescript.org/guides/promise-interop
There’s no “await” in ClojureScript; some discussion here: https://groups.google.com/g/clojurescript/c/scUMhU-ctEM
Yeah this was much more pain than it should be.
deno has a (http/listenAndServe options (fn [req] ...))
which makes for a much easier API from CLJS than using the await asynciterator stuff
yay time to use that instead!
thanks!
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.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.
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;
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
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...
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 ...]
?
Uncaught Error: Minified React error #321; visit <https://reactjs.org/docs/error-decoder.html?invariant=321> 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 <http://localhost:3000/static/js/main.chunk.js:11931:19>
at div
at c (<http://localhost:3000/static/js/main.chunk.js:41823:18>)
at ex_testproject_Component2
at div
at App
Consider adding an error boundary to your tree to customize error handling behavior.
Visit <https://reactjs.org/link/error-boundaries> to learn more about error boundaries.
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?
I have lots of CLJS experience, minimal JS experience, and no experience trying to wrap JS code.
There is https://clojurescript.org/reference/packaging-foreign-deps but is that still the way to go?
Apparently there is an issue for the lack of documentation: https://github.com/clojure/clojurescript-site/issues/224
Also found this decade old resource: http://lukevanderhart.com/2011/09/30/using-javascript-and-clojurescript.html
@simongray how is the JS bundled and used now?
@thheller Using this script… https://github.com/simile-widgets/timeline/blob/master/src/webapp/api/timeline-api.js
and why do you intend to bundle it together with the CLJS code? why not just keep it as a separate script?
How would I distribute it as a library then?
And honestly, I would prefer more explicit dependencies than this automagic script
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
right
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
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
hm…
so the bundler you’re talking about is ClojureScripts built-in way to handle foreign libs?
The files that end up being included look like this
bundler as in generic term for bundler. be that CLJS, shadow-cljs, webpack or really anything bunlding JS
:foreign-libs
will not help you here (especially since shadow-cljs doesn't support them)
hmmm
I really just need a way to load a bunch of JS code in advance
whatever is the shortest path there, I’ll take ity
I can give you shadow-cljs specific options but those will not work with regular CLJS
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?
if it’s just for my own project, I guess I can simply include the JS file that loads everything in the index.html
and then call the JS methods from ClojureScript
:foreign-libs
would be the way to go for regular CLJS, after adjusting the code of course.
looks a bit different for shadow-cljs, same idea but different code adjustments 😛
there is one way to make it work generally but I'm unsure the code will actually survive :advanced
so that might not work 😉
@thheller Ok. And the regular CLJS way is not supported in shadow-cljs?
: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 😛
hm
sucks
I guess I will not be making a library then.
@thheller If you don’t mind my asking, why don’t you support :foreign-libs?
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?
does supporting the one preclude supporting the other?
https://shadow-cljs.github.io/docs/UsersGuide.html#_why_not_use_cljsjs
@thheller that does assume that the only JS code worth using in CLJS comes from a Node package.
I wouldn't say so - you can use any local JS file with shadow-cljs.
Namely, this: https://shadow-cljs.github.io/docs/UsersGuide.html#_requiring_js
For your own project, but you can't use it to make a distributable library.
Ah, I see, right.
as I said there is a way to make it work with all CLJS tools
@thheller is there a guide somewhere?
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
in your case you'd use you'd put all the files from here
https://github.com/simile-widgets/timeline/tree/master/src/webapp/api/scripts
into a directory on your classpath. or rather the source-path of the library you are writing
say src/main/simongray/timeline/themes.js
and so on
then in that file you add a goog.provide("simongray.timeline.themes")
as the first line
with that you can include it in CLJS via (:require [simongray.timeline.themes])
and in this case end up using it via js/Timeline
you do this for every file and you are done. no extra :foreign-libs
or so
but since CSS is involved as well this approach doesn't really work
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
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
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}]
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 <http://goog.net|goog.net>.cookies)
nor (.remove <http://goog.net|goog.net>.cookies "/" nil)
nor (.clear <http://goog.net|goog.net>.cookies)
seem to work.
I was finally able to expire it via (.set <http://goog.net|goog.net>.cookies "__Host-Foo" "" 0 "/" nil true)
🙂
ok - thank you for the rundown