This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-01-28
Channels
- # asami (5)
- # babashka (44)
- # beginners (22)
- # biff (7)
- # clerk (86)
- # clj-kondo (5)
- # clojure (33)
- # clojure-europe (8)
- # clr (6)
- # community-development (2)
- # fulcro (20)
- # graalvm (5)
- # graphql (1)
- # hugsql (3)
- # integrant (5)
- # java (11)
- # joyride (2)
- # leiningen (4)
- # malli (12)
- # nbb (15)
- # off-topic (28)
- # pathom (23)
- # reitit (8)
- # releases (1)
- # sci (6)
- # shadow-cljs (39)
- # tools-deps (15)
- # tree-sitter (1)
Hello! I am trying to use a React component, https://www.jsdelivr.com/package/npm/@nivo/line in my Clerk notebook and write a viewer. I used the https://github.com/nextjournal/clerk/blob/main/notebooks/js_import.clj as inspiration. I feel like I’m close but now I’m not sure how to combine the React component from the ES module and Reagent via SCI to render it in the browser. Here’s what I have so far 🧵
(def nivo-line-viewer
{:transform-fn clerk/mark-presented
:render-fn
'(fn [_]
[nextjournal.clerk.render/with-dynamic-import
{:module ""}
(fn [NivoLine]
;; adapt-react-class not available :(
[(reagent/adapt-react-class NivoLine)
{:data {"put some data" "here"}}])])})
I elided much of the actual code to make it easier to read but this is what it renders
I learned that the adapt-react-class
in Reagent is not available so I might be stuck or have to take a different route
I don’t have a ton of experience in the JS world so I’m hoping someone will notice I’m doing something terribly wrong and point me in the right direction
Thanks in advance!
Try [:> NivoLine …]
That syntax lets you use a react class directly in a reagent component tree
@U098UL4QP on my phone so I can’t test it but I hope that will get it done!
Do you need to wrap this in an html call? Not sure... cc @U5H74UNSF
@U098UL4QP do you have a simple working limo + reagent example that you’re trying to port to Clerk?
(ns scratch
(:require [nextjournal.clerk :as clerk]))
(def nivo-line-viewer
{:transform-fn clerk/mark-presented
:render-fn '(fn [{:keys [data]} _]
[nextjournal.clerk.render/with-dynamic-import
{:module ""}
(fn [Nivo]
(js/console.log Nivo)
[:> Nivo {:data (clj->js data)}])])})
(clerk/with-viewer nivo-line-viewer
{:data [{:x 1 :y 1}
{:x 2 :y 3}
{:x 3 :y 2}]})
@U5H74UNSF ahhh ok this is where my React/JS experience is failing me. I do have an example of using it in a shadow-cljs project that I am trying to port. I think the prop we need is ResponsiveLine
Here's the docs that may be more useful https://nivo.rocks/line/. There's a code
tab that has a JS example
My example I'm trying to port does exist but in a private repo. This may not be that useful but this is the Reagent component https://gist.github.com/jaydeesimon/7844e272b5d43f6a9b14f28ac469f767
in any case, this message is https://clojurians.slack.com/archives/C035GRLJEP8/p1674908932720109?thread_ts=1674876035.297019&cid=C035GRLJEP8. I think this puts me in the right direction
Yup I do have it. What I'll do next is extract out a minimum working version working in Reagent and stick that in a public repo. Then it'll be easier for me or experts like you all to port that to a Clerk viewer version. I'm also gonna be afk for a bit but I'll report back on this thread. Thanks @U017QJZ9M7W @U04V15CAJ @U5H74UNSF!
I was able to throw together a working example of a rendered @nivo/line graph using shadow-cljs: https://github.com/jaydeesimon/nivoline-example, if this helps
After playing around this for a bit more trying to use dynamic import, I’m getting the feeling that the issue has something to do with the dependencies of @nivo/line and them not being available in the dynamic import context. But honestly, really not sure
@U098UL4QP what do you think of trying out the template at https://github.com/nextjournal/clerk-cljs-demo, the clerk/custom
one?
that will let you compile your own js and get those components loaded into sci without dynamic import
I’ve got a line on a way to do this with much less effort, but this is basically a tighter version of what I’ve been doing for my docs notebooks
That looks like a great idea! That was going to be my next question: how can I just take what I've got and drop Clerk in it and figure out the rendering from there? Looks like this is the answer to that question
@U017QJZ9M7W I will give that a go 👍
@U098UL4QP if you want to debug the dynamic import, try console.log the dynamic imported library - it may very well be that you need to read another field like .-default
Based on the example I think that’s true
@U098UL4QP the dynamic import gets you the namespace, basically
If you want to use ResponsiveLine
from the module, you need to do:
[:> (.-ResponsiveLine Nivo) ...]
Not [:> Nivo ...]
I'm also getting react.production.min.js:25 Uncaught TypeError: Cannot read properties of null (reading 'useRef')
when I try (.-ResponsiveLine Nivo)
Right I tried that and same as you, that's the error I get as well that I'm not sure how to make sense of TypeError: Cannot read properties of null (reading 'useRef')
:thinking_face:
Yeah the error message seems pretty common if you google it but not sure how to trace it back to a hypothesis or if it's a red herring
useRef comes from “react”, so maybe react needs to be dynamically loaded too
weird but I guess that error comes from react 🙂
I think that is only if you write a clojure function that uses useEffect, useRef etc…
js react components can use all of that stuff and :>
should be fine
:f>
didn't help indeed.
(defn my-component []
[:div
(when @nivo
(let [rl (.-ResponsiveLine @nivo)]
[:div [:f> rl {}]]))])
This code is literally in that nivo lib:
export const useMeasure = () => {
const measureRef = useRef(null)
so however react
gets resolved in the dynamic import is not working
import { useRef, useState, useEffect } from 'react'
You think useRef
itself is null? That's not what I thought when I saw the error message
no I think it’s doing something like react.useRef
, where react
is null
I had some issue before where I was bundling mathbox, and in the bundled version it replaced all “three” imports with a global THREE
but then that was a major pain when I tried to do the dynamic import thing, I had to nest the dynamic requires, and then assign the imported THREE to window.THREE
before dynamically importing mathbox
it was all so confusing that I went the other make-cljs-libraries-and-clerk-templates-with-custom-js route
yes, the issue here is that when dynamically importing things with dependencies, it gets pretty complicated, especially when you mix and match different versions of react
you can however use import maps for this, but probably not on the level of clerk viewer functions
@U04V15CAJ I wonder if there is a non-esm version of this library that bundles everything. then it would package its own version of react, which is a bummer, but might actually work, which is a plus
maybe as easy as removing the esm suffix?
haha what a mess
@U098UL4QP I would recommend a custom JS build here
it’s been very pleasant to work with Clerk that way, I’ll have something even better this week but the project that the clerk/custom
template here generates https://github.com/nextjournal/clerk-cljs-demo is pretty good imo
basically you get this template going, and then you can make these components available inside your viewers. happy to help in any way you want if you decide to go this route
Really appreciate you all spending the time to help unblock me. Looks like pointing it to a CDN won’t work in this case but thanks for helping me confirm that. @U017QJZ9M7W, I will go the custom template route as that looks like what I’m looking for. Also, it looks like the custom template case will work for any JS library which is where I’d like to be eventually
I’ll try it out in the next couple of days and report back
Also, I just wanted to express some gratitude for Clerk. It’s been a game changer for me in terms of understanding problems and communicating that understanding to other people. It’s such a great tool so I’ve been doubling down on my understanding of it. I look forward to its progress and would be happy to contribute in any way I can 🙌
@U098UL4QP if you want to hack together on this, I’ve got something that can work more easily for you I think without the whole custom template;
once this is merged https://github.com/mentat-collective/clerk-utils/pull/10, clerk-utils
will have versions of watch!
and build!
that can take care of all of the custom cljs stuff for you. If you have a Clerk project that you want to work with nivo/line
, if you point me to it I’d be happy to put up a PR getting it working
Hey @U017QJZ9M7W. This sounds great. I don’t yet have a project up with Clerk + nivo/line but I was planning to get one up today. What I can do is set that project up and have clerk-utils
be a dependency and use the sha of your sritchie/watcher
branch or main
whenever it gets merged
Then I’ll post a link to the project here and see if I can get it working. Will likely reach out for help
don’t suffer too much as I haven’t written docs yet; BUT I did convert mafs.cljs
to use the new stuff, again still in a branch https://github.com/mentat-collective/Mafs.cljs/pull/7/files
but the upshot is, you have versions of clerk/serve!
and clerk/build!
that take a :cljs-namespaces
key, and if you pass a sequence of symbols for namespaces you want to compile, everything will Just Work, no extra setup required.
I use them like this. https://github.com/mentat-collective/Mafs.cljs/blob/015e088c7f82da816b0afc09e56fec348bc7cd7e/dev/user.clj
@U017QJZ9M7W Maybe you can write a clerk README about this
here I am including a single cljs file: https://github.com/mentat-collective/Mafs.cljs/blob/015e088c7f82da816b0afc09e56fec348bc7cd7e/dev/mafs/clerk_ui.cljs and then from there I’m customizing the sci environment.
@U04V15CAJ yep, that’s today’s job:
• getting this PR finalized
• writing up how to use it
• adding a template to clerk-utils
that generates a project using it
@U098UL4QP I have been spending a bunch of time wrapping up React interfaces to make them play nice with ClojureScript, so please let me help once you get a project up!
@U04V15CAJ pretty awesome that we can point people at the sci configs project (https://github.com/babashka/sci.configs) and say “here are some ideas for what you might want to include in your Clerk environment”
Also, I just wanted to express some gratitude for Clerk. It’s been a game changer for me in terms of understanding problems and communicating that understanding to other people. It’s such a great tool so I’ve been doubling down on my understanding of it. I look forward to its progress and would be happy to contribute in any way I can 🙌