From f7620fd21b49e0a3417dfa2e2dd0c07c978110be Mon Sep 17 00:00:00 2001 From: Juho Teperi Date: Mon, 13 Apr 2020 13:45:13 +0300 Subject: [PATCH] Remove cljsjs dependency for module processing build --- npm_react.ext.js | 166 ++++++++++++++++++ project.clj | 30 ++-- test-environments/browser-cljsjs-prod/test.sh | 2 +- test-environments/browser-cljsjs/test.sh | 2 +- test-environments/node-cljsjs/test.sh | 2 +- test/reagenttest/testreagent.cljs | 17 +- 6 files changed, 193 insertions(+), 26 deletions(-) create mode 100644 npm_react.ext.js diff --git a/npm_react.ext.js b/npm_react.ext.js new file mode 100644 index 0000000..f2ad713 --- /dev/null +++ b/npm_react.ext.js @@ -0,0 +1,166 @@ +// Extern file for React with Node module processing +// +// Compared to Cljsjs extern, this doesn't contain the public API, which +// can be optimized here. This just fixes the React +// internal methods and properties that are created dynamically. +// +// TODO: Package separately and remove these from Cljsjs externs? + +/** + * React event system creates plugins and event properties dynamically. + * These externs are needed when consuming React as a JavaScript module + * in light of new ClojureScript compiler additions (as of version 1.9.456). + * See the following link for an example. + * https://github.com/facebook/react/blob/c7129c/src/renderers/dom/shared/eventPlugins/SimpleEventPlugin.js#L43 + */ +var ResponderEventPlugin; +var SimpleEventPlugin; +var TapEventPlugin; +var EnterLeaveEventPlugin; +var ChangeEventPlugin; +var SelectEventPlugin; +var BeforeInputEventPlugin; + +var bubbled; +var captured; +var topAbort; +var topAnimationEnd; +var topAnimationIteration; +var topAnimationStart; +var topBlur; +var topCancel; +var topCanPlay; +var topCanPlayThrough; +var topClick; +var topClose; +var topContextMenu; +var topCopy; +var topCut; +var topDoubleClick; +var topDrag; +var topDragEnd; +var topDragEnter; +var topDragExit; +var topDragLeave; +var topDragOver; +var topDragStart; +var topDrop; +var topDurationChange; +var topEmptied; +var topEncrypted; +var topEnded; +var topError; +var topFocus; +var topInput; +var topInvalid; +var topKeyDown; +var topKeyPress; +var topKeyUp; +var topLoad; +var topLoadedData; +var topLoadedMetadata; +var topLoadStart; +var topMouseDown; +var topMouseMove; +var topMouseOut; +var topMouseOver; +var topMouseUp; +var topPaste; +var topPause; +var topPlay; +var topPlaying; +var topProgress; +var topRateChange; +var topReset; +var topScroll; +var topSeeked; +var topSeeking; +var topStalled; +var topSubmit; +var topSuspend; +var topTimeUpdate; +var topTouchCancel; +var topTouchEnd; +var topTouchMove; +var topTouchStart; +var topTransitionEnd; +var topVolumeChange; +var topWaiting; +var topWheel; + +// https://github.com/facebook/react/blob/master/packages/shared/isTextInputElement.js#L13-L29 +// Closure will rename these properties during optimization +// But these are used dynamically to check against element props so they must not be renamed. +var isTextInputElement = {}; +isTextInputElement.supportedInputTypes = { + color: true, + date: true, + datetime: true, + "datetime-local": true, + email: true, + month: true, + number: true, + password: true, + range: true, + search: true, + tel: true, + text: true, + time: true, + url: true, + week: true +}; + +// Context methods are created dynamically. +React.Context = function() {}; +React.Context.prototype.Provider = function() {}; +React.Context.prototype.Consumer = function() {}; + +// Value returned from createRef has dynamically set `current` property. +// var ReactRef = {}; +// ReactRef.current = {}; + + +// Rest are required due to Reagent implementation. + +// Lifecycle methods need to be declared, as Reagent creates these dynamically + +var React = {}; +React.Component = function() {}; +React.Component.prototype.componentWillMount = function() {}; +React.Component.prototype.UNSAFE_componentWillMount = function() {}; +React.Component.prototype.componentDidMount = function(element) {}; +React.Component.prototype.componentWillReceiveProps = function(nextProps) {}; +React.Component.prototype.UNSAFE_componentWillReceiveProps = function(nextProps) {}; +React.Component.prototype.shouldComponentUpdate = function(nextProps, nextState) {}; +React.Component.prototype.componentWillUpdate = function(nextProps, nextState) {}; +React.Component.prototype.UNSAFE_componentWillUpdate = function(nextProps, nextState) {}; +React.Component.prototype.componentDidUpdate = function(prevProps, prevState, rootNode) {}; +React.Component.prototype.componentWillUnmount = function() {}; +React.Component.prototype.componentDidCatch = function(error, info) {}; +React.Component.prototype.getDerivedStateFromProps = function() {}; +React.Component.prototype.getDerivedStateFromError = function() {}; +React.Component.prototype.getSnapshotBeforeUpdate = function() {}; +React.Component.prototype.getInitialState = function() {}; +React.Component.prototype.getDefaultProps = function() {}; +React.Component.prototype.getChildContext = function() {}; + +// Reagent creates render method statically. +// React.Component.prototype.render = function() {}; + +// React.Component.prototype.props; +// React.Component.prototype.state; +// React.Component.prototype.refs; +// React.Component.prototype.propTypes; +React.Component.prototype.context; +React.Component.prototype.contextTypes; +React.Component.prototype.contextType; +React.Component.prototype.mixins; +React.Component.prototype.childContextTypes; + +// Reagent also creates the attributes dynamically (from clj maps) +// but mostly the attributes match DOM built-in attributes anyway. +React.ReactAttribute = function() {}; +React.ReactAttribute.ref = {}; +React.ReactAttribute.dangerouslySetInnerHTML = {}; +React.ReactAttribute.dangerouslySetInnerHTML.__html = {}; + diff --git a/project.clj b/project.clj index a91c295..bf6b519 100644 --- a/project.clj +++ b/project.clj @@ -3,13 +3,7 @@ :license {:name "MIT"} :description "A simple ClojureScript interface to React" - :dependencies [[org.clojure/clojure "1.10.1"] - ;; If :npm-deps enabled, these are used only for externs. - ;; Without direct react dependency, other packages, - ;; like react-leaflet might have closer dependency to a other version. - [cljsjs/react "16.13.0-0"] - [cljsjs/react-dom "16.13.0-0"] - [cljsjs/react-dom-server "16.13.0-0"]] + :dependencies [[org.clojure/clojure "1.10.1" :scope "provided"]] :plugins [[lein-cljsbuild "1.1.7"] [lein-doo "0.1.11"] @@ -25,10 +19,13 @@ :profiles {:dev {:dependencies [[org.clojure/clojurescript "1.10.597"] [figwheel "0.5.19"] - [doo "0.1.11"] - [cljsjs/prop-types "15.7.2-0"]] + [doo "0.1.11"]] :source-paths ["demo" "test" "examples/todomvc/src" "examples/simple/src" "examples/geometry/src"] - :resource-paths ["site" "target/cljsbuild/client" "target/cljsbuild/client-npm"]}} + :resource-paths ["site" "target/cljsbuild/client" "target/cljsbuild/client-npm"]} + + :cljsjs {:dependencies [[cljsjs/react "16.13.0-0"] + [cljsjs/react-dom "16.13.0-0"] + [cljsjs/prop-types "15.7.2-0"]]}} :clean-targets ^{:protect false} [:target-path :compile-path "out"] @@ -131,7 +128,8 @@ :output-to "target/cljsbuild/node-test-npm/main.js" :npm-deps true :aot-cache true - :checked-arrays :warn}} + :checked-arrays :warn + :verbose true}} ;; With :advanched source-paths doesn't matter that much as ;; Cljs compiler will only read :main file. @@ -159,7 +157,9 @@ :output-dir "target/cljsbuild/prod-npm/out" ;; Outside of public, not published :closure-warnings {:global-this :off} :npm-deps true - :aot-cache true}} + :aot-cache true + :verbose true + :externs ["npm_react.ext.js"]}} {:id "prod-test" :source-paths ["test"] @@ -180,10 +180,12 @@ :optimizations :advanced :elide-asserts true :pretty-print false - ;; :pseudo-names true :output-to "target/cljsbuild/prod-test-npm/main.js" :output-dir "target/cljsbuild/prod-test-npm/out" :closure-warnings {:global-this :off} :npm-deps true :aot-cache true - :checked-arrays :warn}}]}) + :checked-arrays :warn + :verbose true + :pseudo-names true + :externs ["npm_react.ext.js"]}}]}) diff --git a/test-environments/browser-cljsjs-prod/test.sh b/test-environments/browser-cljsjs-prod/test.sh index 2f5f7e0..b99ac3d 100755 --- a/test-environments/browser-cljsjs-prod/test.sh +++ b/test-environments/browser-cljsjs-prod/test.sh @@ -1,6 +1,6 @@ #!/bin/bash set -ex rm -rf target/cljsbuild/prod-test/ -lein doo chrome-headless prod-test once +lein with-profile +cljsjs doo chrome-headless prod-test once test -f target/cljsbuild/prod-test/main.js node_modules/.bin/gzip-size target/cljsbuild/prod-test/main.js diff --git a/test-environments/browser-cljsjs/test.sh b/test-environments/browser-cljsjs/test.sh index b204423..b31f3c5 100755 --- a/test-environments/browser-cljsjs/test.sh +++ b/test-environments/browser-cljsjs/test.sh @@ -1,5 +1,5 @@ #!/bin/bash set -ex rm -rf target/cljsbuild/test/ -COVERAGE=1 lein doo chrome-headless test once +COVERAGE=1 lein with-profile +cljsjs doo chrome-headless test once test -f target/cljsbuild/test/out/cljsjs/react/development/react.inc.js diff --git a/test-environments/node-cljsjs/test.sh b/test-environments/node-cljsjs/test.sh index 153022f..0678cf9 100755 --- a/test-environments/node-cljsjs/test.sh +++ b/test-environments/node-cljsjs/test.sh @@ -1,5 +1,5 @@ #!/bin/bash set -ex rm -rf target/cljsbuild/node-test/ -lein doo node node-test once +lein with-profile +cljsjs doo node node-test once test -f target/cljsbuild/node-test/out/cljsjs/react/development/react.inc.js diff --git a/test/reagenttest/testreagent.cljs b/test/reagenttest/testreagent.cljs index f185932..d82769e 100644 --- a/test/reagenttest/testreagent.cljs +++ b/test/reagenttest/testreagent.cljs @@ -457,15 +457,14 @@ (rstr (ae [:div [:div "foo"]])))))) (def ndiv (let [cmp (fn [])] - (gobj/extend - (.-prototype cmp) - (.-prototype react/Component) - #js {:render (fn [] - (this-as - this - (r/create-element - "div" #js {:className (.. this -props -className)} - (.. this -props -children))))}) + (gobj/extend (.-prototype cmp) (.-prototype react/Component)) + (set! (.-render (.-prototype cmp)) + (fn [] + (this-as + this + (r/create-element + "div" #js {:className (.. this -props -className)} + (.. this -props -children))))) (gobj/extend cmp react/Component) cmp))