Search code examples
reactjsclojurescriptreact-markdown

How to use react-markdown library with helix (Clojurescript)?


My Goal is to render markdown files on my cljs webpage.

What I'm using:

  • org.clojure/clojurescript 1.11.60
  • lilactown/helix 0.1.6
  • nodejs 18.9.1 and yarn 1.22.19

What I've tried:

;; blog.cljs
(ns mypage.blog
  (:require [helix.core :refer [defnc $]]
            [helix.hooks :as hooks]
            [helix.dom :as d]
            ["react-markdown" :as ReactMarkdown]))

(defnc blog []
  (d/div {:class "blog-section"}
    (ReactMarkdown {:source "# Header\nSome text..."})))

;; other ideas that also don't work:
;; ($ ReactMarkdown {:source "# Header\nSome text..."})
;; ($ ReactMarkdown "#Header\nsome text...")
;; (ReactMarkdown "# Header\nSome text...")
;; app.cljs
(ns mypage.app
  (:require [helix.core :refer [defnc $]]
            [helix.hooks :as hooks]
            [helix.dom :as d]
            ["react-dom" :as rdom]
            [mypage.blog :refer [blog]]))

(defnc app []
  (d/div {:class "app"}
    ($ blog)))

(defn ^:export init []
  (rdom/render ($ app) (js/document.getElementById "app")))

The code does compile without any errors. However when open the page in the browser I find a blank page and the following error in the js console:

Uncaught TypeError: module$node_modules$react_markdown$index is not a function
    eliashaukssoncom$blog$blog_render blog.cljs:9
    React 15
    eliashaukssoncom$app$init app.cljs:25
    <anonymous> shadow.module.main.append.js:4
    globalEval main.js:472
    evalLoad main.js:1534
    <anonymous> main.js:1848
blog.cljs:9:10
    eliashaukssoncom$blog$blog_render blog.cljs:9
    React 10
    performSyncWorkOnRoot self-hosted:1406
    React 5
    eliashaukssoncom$app$init app.cljs:25
    <anonymous> shadow.module.main.append.js:4
    globalEval main.js:472
    evalLoad main.js:1534
    <anonymous> main.js:1848


The above error occurred in the <eliashaukssoncom.blog/blog> component:

eliashaukssoncom$blog$blog_render@http://localhost:3000/js/cljs-runtime/eliashaukssoncom.blog.js:5:112
RenderedRoute@http://localhost:3000/js/cljs-runtime/module$node_modules$react_router$dist$umd$react_router_development.js:18:17
Routes@http://localhost:3000/js/cljs-runtime/module$node_modules$react_router$dist$umd$react_router_development.js:26:11
Router@http://localhost:3000/js/cljs-runtime/module$node_modules$react_router$dist$umd$react_router_development.js:23:437
shadow$provide.module$node_modules$react_router_dom$dist$umd$react_router_dom_development/</exports.BrowserRouter@http://localhost:3000/js/cljs-runtime/module$node_modules$react_router_dom$dist$umd$react_router_dom_development.js:37:377
div
eliashaukssoncom$app$app_render@http://localhost:3000/js/cljs-runtime/eliashaukssoncom.app.js:6:112

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.

An error occurred when calling (eliashaukssoncom.app/init)

TypeError: module$node_modules$react_markdown$index is not a function
    eliashaukssoncom$blog$blog_render blog.cljs:9
    React 12
    eliashaukssoncom$app$init app.cljs:25
    <anonymous> shadow.module.main.append.js:4
    globalEval main.js:472
    evalLoad main.js:1534
    <anonymous> main.js:1848
main.js:1426:15
    reportError http://localhost:3000/js/main.js:1426
    evalLoad http://localhost:3000/js/main.js:1536
    <anonymous> http://localhost:3000/js/main.js:1848

If found this blogpost, which makes use of the :> element from reagent to achieve the result I need. However I haven't found a way to replicate that with helix.

Any help is appreciated. Thanks in advance.


Solution

  • Based on the docs I'm guessing the correct solution to be

    ;; blog.cljs
    (ns mypage.blog
      (:require [helix.core :refer [defnc $]]
                [helix.hooks :as hooks]
                [helix.dom :as d]
                ["react-markdown$default" :as ReactMarkdown]))
    
    (defnc blog []
      (d/div {:class "blog-section"}
        ($ ReactMarkdown {:children "# Header\nSome text..."})))
    

    This is however just a guess since I don't use any of the libs. Just basing this on translated API examples.

    The blog post you referenced is from Sep 13, 2019 and that is an eternity in the JS world. The react-markdown lib likely has gone through a million changes since then and the :source prop just no longer exists.