Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reagent.core/adapt-react-class missing symbol #214

Closed
alexandercarls opened this issue Jun 12, 2022 · 10 comments
Closed

reagent.core/adapt-react-class missing symbol #214

alexandercarls opened this issue Jun 12, 2022 · 10 comments

Comments

@alexandercarls
Copy link

alexandercarls commented Jun 12, 2022

version

v0.5.112

platform

  • macOS 12.2.1
  • Node.js 16.5.1

problem

The symbol adapt-react-class is not present with nbb on reagent.core.
The function is used to create Reagent components from React components.

Reagent Docs

On that note, the provided shortcut :> also does not work.

According to the nbb's API documentation it is missing as intended. Could this be added? My use case is highlighting code on the server and rendering it to static markup.

repro

The following works with ClojureScript via shadow-cljs

(ns core
  (:require
   ["react-dom/server" :as ReactDomServer]
   ["prism-react-renderer" :refer [Prism]]
   ["prism-react-renderer$default" :as Highlight]
   [reagent.core :as r]))

(defn cake [code]
  [(r/adapt-react-class Highlight) {"Prism" Prism :code code :language "javascript"} (fn [params] (r/as-element [:div "Test"]))])

(ReactDomServer/renderToString (r/as-element (cake "const b = 3;")))
;; => "<div>Test</div>"

The error is Could not resolve symbol: r/adapt-react-class

It uses function as a child component (Docs)

expected behavior

"<div>Test</div>"

@borkdude
Copy link
Collaborator

Should be there in the newest version on npm now

@alexandercarls
Copy link
Author

Thank you @borkdude.

The symbol is present now. However ReactDomServer/renderToString (as well as the reagent static version render-to-static-markup) now returns Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object..

The stack trace is not helpful. Or I am not aware on how to extract useful information there. Via *e from the REPL.

#error {:message "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.", :data {:type :sci/error, :line 1, :column 1, :message "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.", :sci.impl/callstack #object[cljs.core.Volatile {:val ({:line 1, :column 1, :ns #object[hr core], :file "/Users/alca/private/site/src/core.cljs", :sci.impl/f-meta {:ns #object[hr reagent.dom.server], :name render-to-static-markup, :arglists ([component] [component compiler]), :doc "Turns a component into an HTML string, without data-react-id attributes, etc."}} {:line 1, :column 1, :ns #object[hr core], :file "/Users/alca/private/site/src/core.cljs", :sci.impl/f-meta {:ns #object[hr reagent.dom.server], :name render-to-static-markup, :arglists ([component] [component compiler]), :doc "Turns a component into an HTML string, without data-react-id attributes, etc."}})}], :file "/Users/alca/private/site/src/core.cljs"}, :cause #object[Error Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.]}

My guess is that there is some internal fn missing. Do you have any pointer on how to verify or find that out?

@alexandercarls
Copy link
Author

alexandercarls commented Jun 12, 2022

The fn uses a deftype. Which is not yet supported according to the README. This is probably the cause.

https://github.com/reagent-project/reagent/blob/master/src/reagent/impl/template.cljs#L18,L22

@borkdude
Copy link
Collaborator

@alexandercarls I'm not sure what is the cause of the error, but deftype etc is not relevant here since the function call is made to the compiled reagent function, it is not interpreted in SCI. I'll take a look later, I can't find the issue myself either.

@borkdude
Copy link
Collaborator

@alexandercarls So I made a repro in pure JS:

prism.js:

import React from "react";
import { render } from "react-dom";
import Highlight, { defaultProps } from "prism-react-renderer";

React.createElement(Highlight, defaultProps);
$ node prism.mjs
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.

Perhaps you can try to figure it out in pure JS first and then when you have a small working example, then port it back to nbb.

@alexandercarls
Copy link
Author

@borkdude

The following works. I am not sure why the default import with Node.js doesn't extract the default value by default for the library.

Note the Highlight.default bit there.

(renamed to prism.mjs)

import React from "react";
import { renderToStaticMarkup } from "react-dom/server";
import Highlight, { defaultProps } from "prism-react-renderer";

console.log(Highlight)
console.log(Highlight.default) // correct Function for "Highlight component"

const test = React.createElement(
    Highlight.default,
    { ...defaultProps, code: 'const b = 3;', language: 'javascript' },
    () => React.createElement('div', null, 'Test')
);

console.log(renderToStaticMarkup(test));
// <div>Test</div>

Given the above. The adjustment to the function for nbb works.

(defn cake [code]
  [(r/adapt-react-class (.-default Highlight)) {"Prism" Prism :code code :language "javascript"} (fn [params] (r/as-element [:div "Test"]))])

However, this fails with shadow-cljs: Assert failed: Component must not be nil. It must be left without the default access.

Interesting.

@borkdude
Copy link
Collaborator

Interesting indeed. This sometimes happens with libraries that are compiled as typescript libraries.
In nbb you often need an extra $default compared to target browser or nodejs in shadow, but if you use target esm in shadow, they will be exactly the same. Another way to write this in nbb without adapt-react-class would be with the :> syntax:

(ns example
  (:require
   ["prism-react-renderer$default" :as Highlight :refer [Prism]]
   [reagent.core :as r]
   [reagent.dom.server :as srv]))

(defn cake [code]
  [:> Highlight/default {"Prism" Prism :code code :language "javascript"}
   (fn [_params] (r/as-element [:div "Test"]))])

(prn (srv/render-to-string [cake "const b = 3;"]))

@borkdude
Copy link
Collaborator

borkdude commented Jun 13, 2022

This is another variation of the ns form:

(ns example
  (:require
   ["prism-react-renderer$default.Prism" :as Prism]
   ["prism-react-renderer$default.default" :as Highlight]
   [reagent.core :as r]
   [reagent.dom.server :as srv]))

@alexandercarls
Copy link
Author

Thank you very much for the explanation and the debugging help. It works fine now :)

@borkdude
Copy link
Collaborator

@alexandercarls Feel free to provide an interesting example of this library in the examples dir

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants