From 41a687faa76d0d68b6490e84af310bcd4d2a4f4e Mon Sep 17 00:00:00 2001 From: Dan Holmsand Date: Wed, 9 Apr 2014 16:50:15 +0200 Subject: [PATCH] Add import-react macro --- demo/demo.cljs | 4 +++- project.clj | 4 +--- src/reagent/core.cljs | 4 +--- src/reagent/impl/component.cljs | 4 ++-- src/reagent/impl/template.cljs | 19 +++++++++--------- src/reagent/impl/util.cljs | 10 ++++------ src/reagent/interop.clj | 35 ++++++++++++++++++++++++++++++++- 7 files changed, 55 insertions(+), 25 deletions(-) diff --git a/demo/demo.cljs b/demo/demo.cljs index 4e5f765..b7d941b 100644 --- a/demo/demo.cljs +++ b/demo/demo.cljs @@ -1,6 +1,6 @@ (ns demo (:require [reagent.core :as reagent :refer [atom]] - [reagent.interop :refer-macros [.' .! fvar]] + [reagent.interop :as i :refer-macros [.' .! fvar]] [clojure.string :as string] [reagentdemo.page :as page :refer [page-map page link prefix]] [reagentdemo.common :as common :refer [demo-component]] @@ -8,6 +8,8 @@ [reagentdemo.news :as news] [reagent.debug :refer-macros [dbg println]])) +(i/import-react) + (swap! page-map assoc "index.html" (fvar intro/main) "news/index.html" (fvar news/main)) diff --git a/project.clj b/project.clj index 38a46e3..3f349bb 100644 --- a/project.clj +++ b/project.clj @@ -13,7 +13,6 @@ {:client {:compiler {:optimizations :advanced :elide-asserts true - :preamble ^:replace ["reagent/react.min.js"] :pretty-print false}}}}} :test {:cljsbuild {:builds @@ -37,7 +36,6 @@ "examples/geometry/src"] :notify-command ["node" "./bin/gen-site.js"] :compiler - {:preamble ["reagent/react.js"] - :output-dir "target/client" + {:output-dir "target/client" :output-to "target/cljs-client.js" :pretty-print true}}}}) diff --git a/src/reagent/core.cljs b/src/reagent/core.cljs index 90b51ad..f8ce354 100644 --- a/src/reagent/core.cljs +++ b/src/reagent/core.cljs @@ -9,8 +9,6 @@ [reagent.debug :refer-macros [dbg prn]] [reagent.interop :refer-macros [.' .!]])) -(def React util/React) - (def is-client util/is-client) (defn as-component @@ -40,7 +38,7 @@ Returns the mounted component instance." (defn render-component-to-string "Turns a component into an HTML string." ([component] - (.' React renderComponentToString (as-component component)))) + (.' js/React renderComponentToString (as-component component)))) (defn ^:export force-update-all [] (util/force-update-all)) diff --git a/src/reagent/impl/component.cljs b/src/reagent/impl/component.cljs index d370e8c..81ea403 100644 --- a/src/reagent/impl/component.cljs +++ b/src/reagent/impl/component.cljs @@ -1,6 +1,6 @@ (ns reagent.impl.component - (:require [reagent.impl.util :as util :refer [React]] + (:require [reagent.impl.util :as util] [reagent.impl.batching :as batch] [reagent.ratom :as ratom] [reagent.interop :refer-macros [.' .!]] @@ -183,7 +183,7 @@ (assert (map? body)) (let [spec (cljsify body) _ (.! spec :asComponent (dont-bind as-component)) - res (.' React createClass spec) + res (.' js/React createClass spec) f (fn [& args] (as-component (apply vector res args)))] (util/cache-react-class f res) diff --git a/src/reagent/impl/template.cljs b/src/reagent/impl/template.cljs index a7e10f2..4bb1316 100644 --- a/src/reagent/impl/template.cljs +++ b/src/reagent/impl/template.cljs @@ -1,20 +1,19 @@ (ns reagent.impl.template (:require [clojure.string :as string] - [reagent.impl.util :as util :refer [is-client React]] + [reagent.impl.util :as util :refer [is-client]] [reagent.impl.component :as comp] [reagent.impl.batching :as batch] [reagent.ratom :as ratom] [reagent.interop :refer-macros [.' .!]] [reagent.debug :refer-macros [dbg prn println log dev?]])) + ;; From Weavejester's Hiccup, via pump: (def ^{:doc "Regular expression that parses a CSS-style id and class from a tag name."} re-tag #"([^\s\.#]+)(?:#([^\s\.#]+))?(?:\.([^\s#]+))?") -(def DOM (.' React :DOM)) - (def attr-aliases {:class "className" :for "htmlFor" :charset "charSet"}) @@ -117,8 +116,10 @@ (.! :value nil) (.! :onChange #(input-handle-change this on-change %)))))) -(def input-components #{(.' DOM :input) - (.' DOM :textarea)}) +(defn input-component? [x] + (let [DOM (.' js/React :DOM)] + (or (identical? x (.' DOM :input)) + (identical? x (.' DOM :textarea))))) ;;; Wrapping of native components @@ -151,7 +152,7 @@ (.! :componentWillUnmount #(this-as c (batch/dispose c))))) (defn wrap-component [comp extras name] - (let [input? (input-components comp) + (let [input? (input-component? comp) input-setup (if input? input-render-setup) spec #js{:render #(this-as C (wrapped-render C comp extras input-setup)) @@ -160,14 +161,14 @@ :displayName (or name "ComponentWrapper")}] (when input? (add-input-methods spec)) - (.' React createClass spec))) + (.' js/React createClass spec))) ;;; Conversion from Hiccup forms (defn parse-tag [hiccup-tag] (let [[tag id class] (->> hiccup-tag name (re-matches re-tag) next) - comp (aget DOM tag) + comp (aget (.' js/React :DOM) tag) class' (when class (string/replace class #"\." " "))] (assert comp (str "Unknown tag: '" hiccup-tag "'")) @@ -197,7 +198,7 @@ (let [cached-class (util/cached-react-class tag)] (if-not (nil? cached-class) cached-class - (if (.' React isValidClass tag) + (if (.' js/React isValidClass tag) (util/cache-react-class tag (wrap-component tag nil nil)) (fn-to-class tag))))))) diff --git a/src/reagent/impl/util.cljs b/src/reagent/impl/util.cljs index 38b19b9..a2581df 100644 --- a/src/reagent/impl/util.cljs +++ b/src/reagent/impl/util.cljs @@ -6,8 +6,6 @@ (def is-client (and (exists? js/window) (-> js/window (.' :document) nil? not))) -(def React js/React) - ;;; Props accessors (defn extract-props [v] @@ -128,11 +126,11 @@ (defn re-render-component [comp container] (try - (.' React renderComponent (comp) container) + (.' js/React renderComponent (comp) container) (catch js/Object e (do (try - (.' React unmountComponentAtNode container) + (.' js/React unmountComponentAtNode container) (catch js/Object e (log e))) (when-let [n (get-react-node container)] @@ -141,7 +139,7 @@ (throw e))))) (defn render-component [comp container callback] - (.' React renderComponent (comp) container + (.' js/React renderComponent (comp) container (fn [] (let [id (get-root-id container)] (when-not (nil? id) @@ -154,7 +152,7 @@ (let [id (get-root-id container)] (when-not (nil? id) (swap! roots dissoc id))) - (.' React unmountComponentAtNode container)) + (.' js/React unmountComponentAtNode container)) (defn force-update-all [] (binding [*always-update* true] diff --git a/src/reagent/interop.clj b/src/reagent/interop.clj index 24cdc55..682e4b4 100644 --- a/src/reagent/interop.clj +++ b/src/reagent/interop.clj @@ -1,5 +1,6 @@ (ns reagent.interop - (:require [clojure.string :as string :refer [join]])) + (:require [clojure.string :as string :refer [join]] + [clojure.java.io :as io])) (defn- js-call [f args] (let [argstr (->> (repeat (count args) "~{}") @@ -48,6 +49,38 @@ (assert field (str "Field name must start with - in " field)) `(aset ~object ~@names ~value))) +(def react-import-ns (atom nil)) + +(defmacro import-react + [] + "Import React.js. + This can be used instead of adding :preamble in project.clj + (or adding react.js in a script tag). This may be more convenient when + using :optimizations :none, since that doesn't take :preamble into account. + Imports minimized version of React if :elide-asserts is true." + (if-not (or (nil? @react-import-ns) + (= *ns* @react-import-ns)) + ;; React was already imported in another namespace; so we avoid + ;; duplicate imports. + true + (let [srcfile (if *assert* "reagent/react.js" + "reagent/react.min.js") + src (slurp (io/resource srcfile))] + (if (nil? @react-import-ns) + (reset! react-import-ns *ns*)) + `(js/eval ~(str "if (typeof React != 'undefined' && + typeof console != 'undefined') { + console.log('WARNING: React is already defined'); + }" + src "; \n" + "console.log('importing');" + "if (typeof module != 'undefined' && + typeof global != 'undefined' && + module.exports && module.exports.DOM) { + global.React = module.exports; + } \n + //@ sourceURL=" srcfile "\n"))))) + (defmacro fvar [f]