I have a reasonably large React + Relay codebase that is being built using Webpack. Is it possible to gradually introduce ClojureScript + Reagent into this somehow?
I was thinking of starting with some of the smaller functional components in our code base and swapping them out. This would mean that the Reagent component would somehow need to receive props from the parent.
Any thoughts or tooling around doing this? A quick Google only seems to turn up articles around including JavaScript libraries in your ClojureScript app, not the other way around.
You could create a reagent component, export it, and then import it in your JS code.
Since you already have webpack/react in your js project, you need to exclude those from your cljs project:
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.9.229"]
[org.clojure/core.async "0.2.391"
:exclusions [org.clojure/tools.reader]]
[reagent "0.6.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server]]]
Now you have to trick Reagent into thinking that those react files you've just excluded are still here. Create these three files:
src/cljsjs/react.cljs
(ns cljsjs.react)
src/cljsjs/react/dom.cljs
(ns cljsjs.react.dom)
src/cljsjs/react/dom/server.cljs
(ns cljsjs.react.dom.server)
Yes, just one line with namespace declaration in each file.
Now you can write your component:
reagent_component/core.cljs:
(ns reagent-component.core
(:require [reagent.core :as r]))
(def counter (r/atom 5))
(def ^:export test66
(r/create-class
{:reagent-render
(fn [props]
(let [{:keys [name]} props]
[:div
{:on-click (fn [] (swap! counter inc))}
name ", I am counting " (clojure.string/join ", " (map inc (range @counter)))])
)}))
Your cljsbuild section in project.clj
might look like this:
:cljsbuild {:builds
[{:id "min"
:source-paths ["src"]
:compiler {:output-to "resources/public/js/compiled/reagent_component_min.js"
:output-dir "resources/public/js/compiled/min"
:main reagent-component.core
:optimizations :advanced
:asset-path "js/compiled/out"
}}]}
For the purpouse of brevity I've given you only the min
section of the cljsbuild.
lein cljsbuild once min
will produce resources/public/js/compiled/reagent_component_min.js
file, which must be copied into your Webpack project.
New entry is added to your webpack.config before your main entry point:
entry: [`${APP_DIR}/reagent_component_min.js`, `${APP_DIR}/main.js`],
This file (reagent_component_min.js) should be excluded from babelification:
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components|reagent_component_min.js)/,
loader: 'babel-loader',
query: {
presets: ['latest']
}
}
]
}
and in your javascript you use it like this:
import React from 'react';
import ReactDOM from 'react-dom';
const comp = reagent_component.core.test66;
const element = <div>Hello, world
{React.createElement(comp, {name: 'akond'})}
</div>;
ReactDOM.render(
element,
document.getElementById('app')
);
Yes, babel jsx plugin does not recognize <comp name="..."/>
. That's why React.createElement is called. I didn't figure out how to make it look better, but it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With