@samitouri / QOS-React-2 / commits / b79a3cbd21

Break more browser deps in core

This is part of what Sebastian suggested. We require it into every component that explicitly needs it and inject it as a default mixin for composite components in the browser environment. This change frees us up to inject everything in ReactComponent.

Pete Hunt committed Feb 20, 2014 at 16:00 UTC b79a3cbd21a82a44ac0c8863995a5f12b10a67d6
15 files changed +115 -58
src/browser/ReactBrowserComponentMixin.js renamed
+21 -5
@@ -13,14 +13,30 @@
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 - * @providesModule ReactComponentEnvironment
16 + * @providesModule ReactBrowserComponentMixin
17 */
18
19 "use strict";
20
21 -var ReactComponentBrowserEnvironment =
22 - require('ReactComponentBrowserEnvironment');
21 +var ReactMount = require('ReactMount');
22
24 -var ReactComponentEnvironment = ReactComponentBrowserEnvironment;
23 +var invariant = require('invariant');
24
26 -module.exports = ReactComponentEnvironment;
25 +var ReactBrowserComponentMixin = {
26 + /**
27 + * Returns the DOM node rendered by this component.
28 + *
29 + * @return {DOMElement} The root node of this component.
30 + * @final
31 + * @protected
32 + */
33 + getDOMNode: function() {
34 + invariant(
35 + this.isMounted(),
36 + 'getDOMNode(): A component must be mounted to have a DOM node.'
37 + );
38 + return ReactMount.getNode(this._rootNodeID);
39 + }
40 +};
41 +
42 +module.exports = ReactBrowserComponentMixin;
src/browser/ReactComponentBrowserEnvironment.js
-20
@@ -39,26 +39,6 @@ var DOC_NODE_TYPE = 9;
39 * the browser context.
40 */
41 var ReactComponentBrowserEnvironment = {
42 - /**
43 - * Mixed into every component instance.
44 - */
45 - Mixin: {
46 - /**
47 - * Returns the DOM node rendered by this component.
48 - *
49 - * @return {DOMElement} The root node of this component.
50 - * @final
51 - * @protected
52 - */
53 - getDOMNode: function() {
54 - invariant(
55 - this.isMounted(),
56 - 'getDOMNode(): A component must be mounted to have a DOM node.'
57 - );
58 - return ReactMount.getNode(this._rootNodeID);
59 - }
60 - },
61 -
42 ReactReconcileTransaction: ReactReconcileTransaction,
43
44 BackendIDOperations: ReactDOMIDOperations,
src/browser/ReactDOMComponent.js
+2
@@ -22,6 +22,7 @@
22 var CSSPropertyOperations = require('CSSPropertyOperations');
23 var DOMProperty = require('DOMProperty');
24 var DOMPropertyOperations = require('DOMPropertyOperations');
25 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
26 var ReactComponent = require('ReactComponent');
27 var ReactEventEmitter = require('ReactEventEmitter');
28 var ReactMount = require('ReactMount');
@@ -399,5 +400,6 @@ ReactDOMComponent.Mixin = {
400 mixInto(ReactDOMComponent, ReactComponent.Mixin);
401 mixInto(ReactDOMComponent, ReactDOMComponent.Mixin);
402 mixInto(ReactDOMComponent, ReactMultiChild.Mixin);
403 +mixInto(ReactDOMComponent, ReactBrowserComponentMixin);
404
405 module.exports = ReactDOMComponent;
src/browser/ReactDefaultInjection.js
+10
@@ -30,6 +30,9 @@ var CompositionEventPlugin = require('CompositionEventPlugin');
30 var DefaultEventPluginOrder = require('DefaultEventPluginOrder');
31 var EnterLeaveEventPlugin = require('EnterLeaveEventPlugin');
32 var MobileSafariClickEventPlugin = require('MobileSafariClickEventPlugin');
33 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
34 +var ReactComponentBrowserEnvironment =
35 + require('ReactComponentBrowserEnvironment');
36 var ReactEventTopLevelCallback = require('ReactEventTopLevelCallback');
37 var ReactDOM = require('ReactDOM');
38 var ReactDOMButton = require('ReactDOMButton');
@@ -89,6 +92,11 @@ function inject() {
92 body: createFullPageComponent(ReactDOM.body)
93 });
94
95 +
96 + // This needs to happen after createFullPageComponent() otherwise the mixin
97 + // gets double injected.
98 + ReactInjection.CompositeComponent.injectMixin(ReactBrowserComponentMixin);
99 +
100 ReactInjection.DOMProperty.injectDOMPropertyConfig(DefaultDOMPropertyConfig);
101
102 ReactInjection.Updates.injectBatchingStrategy(
@@ -101,6 +109,8 @@ function inject() {
109 ServerReactRootIndex.createReactRootIndex
110 );
111
112 + ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);
113 +
114 if (__DEV__) {
115 var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
116 if ((/[?&]react_perf\b/).test(url)) {
src/browser/ReactTextComponent.js
+2
@@ -20,6 +20,7 @@
20 "use strict";
21
22 var DOMPropertyOperations = require('DOMPropertyOperations');
23 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
24 var ReactComponent = require('ReactComponent');
25
26 var escapeTextForBrowser = require('escapeTextForBrowser');
@@ -45,6 +46,7 @@ var ReactTextComponent = function(initialText) {
46 };
47
48 mixInto(ReactTextComponent, ReactComponent.Mixin);
49 +mixInto(ReactTextComponent, ReactBrowserComponentMixin);
50 mixInto(ReactTextComponent, {
51
52 /**
src/browser/dom/components/ReactDOMButton.js
+2 -1
@@ -19,6 +19,7 @@
19 "use strict";
20
21 var AutoFocusMixin = require('AutoFocusMixin');
22 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
23 var ReactCompositeComponent = require('ReactCompositeComponent');
24 var ReactDOM = require('ReactDOM');
25
@@ -47,7 +48,7 @@ var mouseListenerNames = keyMirror({
48 var ReactDOMButton = ReactCompositeComponent.createClass({
49 displayName: 'ReactDOMButton',
50
50 - mixins: [AutoFocusMixin],
51 + mixins: [AutoFocusMixin, ReactBrowserComponentMixin],
52
53 render: function() {
54 var props = {};
src/browser/dom/components/ReactDOMForm.js
+3
@@ -18,6 +18,7 @@
18
19 "use strict";
20
21 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
22 var ReactCompositeComponent = require('ReactCompositeComponent');
23 var ReactDOM = require('ReactDOM');
24 var ReactEventEmitter = require('ReactEventEmitter');
@@ -35,6 +36,8 @@ var form = ReactDOM.form;
36 var ReactDOMForm = ReactCompositeComponent.createClass({
37 displayName: 'ReactDOMForm',
38
39 + mixins: [ReactBrowserComponentMixin],
40 +
41 render: function() {
42 // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
43 // `jshint` fails to parse JSX so in order for linting to work in the open
src/browser/dom/components/ReactDOMImg.js
+3
@@ -18,6 +18,7 @@
18
19 "use strict";
20
21 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
22 var ReactCompositeComponent = require('ReactCompositeComponent');
23 var ReactDOM = require('ReactDOM');
24 var ReactEventEmitter = require('ReactEventEmitter');
@@ -36,6 +37,8 @@ var ReactDOMImg = ReactCompositeComponent.createClass({
37 displayName: 'ReactDOMImg',
38 tagName: 'IMG',
39
40 + mixins: [ReactBrowserComponentMixin],
41 +
42 render: function() {
43 return img(this.props);
44 },
src/browser/dom/components/ReactDOMInput.js
+2 -1
@@ -21,6 +21,7 @@
21 var AutoFocusMixin = require('AutoFocusMixin');
22 var DOMPropertyOperations = require('DOMPropertyOperations');
23 var LinkedValueUtils = require('LinkedValueUtils');
24 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
25 var ReactCompositeComponent = require('ReactCompositeComponent');
26 var ReactDOM = require('ReactDOM');
27 var ReactMount = require('ReactMount');
@@ -52,7 +53,7 @@ var instancesByReactID = {};
53 var ReactDOMInput = ReactCompositeComponent.createClass({
54 displayName: 'ReactDOMInput',
55
55 - mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
56 + mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
57
58 getInitialState: function() {
59 var defaultValue = this.props.defaultValue;
src/browser/dom/components/ReactDOMOption.js
+3
@@ -18,6 +18,7 @@
18
19 "use strict";
20
21 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
22 var ReactCompositeComponent = require('ReactCompositeComponent');
23 var ReactDOM = require('ReactDOM');
24
@@ -30,6 +31,8 @@ var option = ReactDOM.option;
31 var ReactDOMOption = ReactCompositeComponent.createClass({
32 displayName: 'ReactDOMOption',
33
34 + mixins: [ReactBrowserComponentMixin],
35 +
36 componentWillMount: function() {
37 // TODO (yungsters): Remove support for `selected` in <option>.
38 if (this.props.selected != null) {
src/browser/dom/components/ReactDOMSelect.js
+2 -1
@@ -20,6 +20,7 @@
20
21 var AutoFocusMixin = require('AutoFocusMixin');
22 var LinkedValueUtils = require('LinkedValueUtils');
23 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
24 var ReactCompositeComponent = require('ReactCompositeComponent');
25 var ReactDOM = require('ReactDOM');
26
@@ -103,7 +104,7 @@ function updateOptions(component, propValue) {
104 var ReactDOMSelect = ReactCompositeComponent.createClass({
105 displayName: 'ReactDOMSelect',
106
106 - mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
107 + mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
108
109 propTypes: {
110 defaultValue: selectValueType,
src/browser/dom/components/ReactDOMTextarea.js
+2 -1
@@ -21,6 +21,7 @@
21 var AutoFocusMixin = require('AutoFocusMixin');
22 var DOMPropertyOperations = require('DOMPropertyOperations');
23 var LinkedValueUtils = require('LinkedValueUtils');
24 +var ReactBrowserComponentMixin = require('ReactBrowserComponentMixin');
25 var ReactCompositeComponent = require('ReactCompositeComponent');
26 var ReactDOM = require('ReactDOM');
27
@@ -48,7 +49,7 @@ var textarea = ReactDOM.textarea;
49 var ReactDOMTextarea = ReactCompositeComponent.createClass({
50 displayName: 'ReactDOMTextarea',
51
51 - mixins: [AutoFocusMixin, LinkedValueUtils.Mixin],
52 + mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],
53
54 getInitialState: function() {
55 var defaultValue = this.props.defaultValue;
src/core/ReactComponent.js
+45 -28
@@ -18,7 +18,6 @@
18
19 "use strict";
20
21 -var ReactComponentEnvironment = require('ReactComponentEnvironment');
21 var ReactCurrentOwner = require('ReactCurrentOwner');
22 var ReactOwner = require('ReactOwner');
23 var ReactUpdates = require('ReactUpdates');
@@ -53,6 +52,28 @@ var ownerHasPropertyWarning = {};
52
53 var NUMERIC_PROPERTY_REGEX = /^\d+$/;
54
55 +var injected = false;
56 +
57 +/**
58 + * Optionally injectable environment dependent cleanup hook. (server vs.
59 + * browser etc). Example: A browser system caches DOM nodes based on component
60 + * ID and must remove that cache entry when this instance is unmounted.
61 + *
62 + * @private
63 + */
64 +var unmountIDFromEnvironment = null;
65 +
66 +/**
67 + * The "image" of a component tree, is the platform specific (typically
68 + * serialized) data that represents a tree of lower level UI building blocks.
69 + * On the web, this "image" is HTML markup which describes a construction of
70 + * low level `div` and `span` nodes. Other platforms may have different
71 + * encoding of this "image". This must be injected.
72 + *
73 + * @private
74 + */
75 +var mountImageIntoNode = null;
76 +
77 /**
78 * Warn if the component doesn't have an explicit key assigned to it.
79 * This component is in an array. The array could grow and shrink or be
@@ -177,6 +198,23 @@ function validateChildKeys(component) {
198 */
199 var ReactComponent = {
200
201 + injection: {
202 + injectEnvironment: function(ReactComponentEnvironment) {
203 + invariant(
204 + !injected,
205 + 'ReactComponent: injectEnvironment() can only be called once.'
206 + );
207 + mountImageIntoNode = ReactComponentEnvironment.mountImageIntoNode;
208 + unmountIDFromEnvironment =
209 + ReactComponentEnvironment.unmountIDFromEnvironment;
210 + ReactComponent.BackendIDOperations =
211 + ReactComponentEnvironment.BackendIDOperations;
212 + ReactComponent.ReactReconcileTransaction =
213 + ReactComponentEnvironment.ReactReconcileTransaction;
214 + injected = true;
215 + }
216 + },
217 +
218 /**
219 * @param {?object} object
220 * @return {boolean} True if `object` is a valid component.
@@ -209,27 +247,7 @@ var ReactComponent = {
247 *
248 * @internal
249 */
212 - BackendIDOperations: ReactComponentEnvironment.BackendIDOperations,
213 -
214 - /**
215 - * Optionally injectable environment dependent cleanup hook. (server vs.
216 - * browser etc). Example: A browser system caches DOM nodes based on component
217 - * ID and must remove that cache entry when this instance is unmounted.
218 - *
219 - * @private
220 - */
221 - unmountIDFromEnvironment: ReactComponentEnvironment.unmountIDFromEnvironment,
222 -
223 - /**
224 - * The "image" of a component tree, is the platform specific (typically
225 - * serialized) data that represents a tree of lower level UI building blocks.
226 - * On the web, this "image" is HTML markup which describes a construction of
227 - * low level `div` and `span` nodes. Other platforms may have different
228 - * encoding of this "image". This must be injected.
229 - *
230 - * @private
231 - */
232 - mountImageIntoNode: ReactComponentEnvironment.mountImageIntoNode,
250 + BackendIDOperations: null,
251
252 /**
253 * React references `ReactReconcileTransaction` using this property in order
@@ -237,8 +255,7 @@ var ReactComponent = {
255 *
256 * @internal
257 */
240 - ReactReconcileTransaction:
241 - ReactComponentEnvironment.ReactReconcileTransaction,
258 + ReactReconcileTransaction: null,
259
260 /**
261 * Base functionality for every ReactComponent constructor. Mixed into the
@@ -246,7 +263,7 @@ var ReactComponent = {
263 *
264 * @lends {ReactComponent.prototype}
265 */
249 - Mixin: merge(ReactComponentEnvironment.Mixin, {
266 + Mixin: {
267
268 /**
269 * Checks whether or not this component is mounted.
@@ -396,7 +413,7 @@ var ReactComponent = {
413 if (props.ref != null) {
414 ReactOwner.removeComponentAsRefFrom(this, props.ref, this._owner);
415 }
399 - ReactComponent.unmountIDFromEnvironment(this._rootNodeID);
416 + unmountIDFromEnvironment(this._rootNodeID);
417 this._rootNodeID = null;
418 this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
419 },
@@ -513,7 +530,7 @@ var ReactComponent = {
530 transaction,
531 shouldReuseMarkup) {
532 var markup = this.mountComponent(rootID, transaction, 0);
516 - ReactComponent.mountImageIntoNode(markup, container, shouldReuseMarkup);
533 + mountImageIntoNode(markup, container, shouldReuseMarkup);
534 },
535
536 /**
@@ -543,7 +560,7 @@ var ReactComponent = {
560 }
561 return owner.refs[ref];
562 }
546 - })
563 + }
564 };
565
566 module.exports = ReactComponent;
src/core/ReactCompositeComponent.js
+14 -1
@@ -61,6 +61,9 @@ var SpecPolicy = keyMirror({
61 DEFINE_MANY_MERGED: null
62 });
63
64 +
65 +var injectedMixins = [];
66 +
67 /**
68 * Composite components are higher-level components that compose other composite
69 * or native components.
@@ -1405,6 +1408,10 @@ var ReactCompositeComponent = {
1408 Constructor.ConvenienceConstructor = ConvenienceConstructor;
1409 ConvenienceConstructor.originalSpec = spec;
1410
1411 + injectedMixins.forEach(
1412 + mixSpecIntoComponent.bind(null, ConvenienceConstructor)
1413 + );
1414 +
1415 mixSpecIntoComponent(ConvenienceConstructor, spec);
1416
1417 invariant(
@@ -1445,7 +1452,13 @@ var ReactCompositeComponent = {
1452 return ConvenienceConstructor;
1453 },
1454
1448 - isValidClass: isValidClass
1455 + isValidClass: isValidClass,
1456 +
1457 + injection: {
1458 + injectMixin: function(mixin) {
1459 + injectedMixins.push(mixin);
1460 + }
1461 + }
1462 };
1463
1464 module.exports = ReactCompositeComponent;
src/core/ReactInjection.js
+4
@@ -20,6 +20,8 @@
20
21 var DOMProperty = require('DOMProperty');
22 var EventPluginHub = require('EventPluginHub');
23 +var ReactComponent = require('ReactComponent');
24 +var ReactCompositeComponent = require('ReactCompositeComponent');
25 var ReactDOM = require('ReactDOM');
26 var ReactEventEmitter = require('ReactEventEmitter');
27 var ReactPerf = require('ReactPerf');
@@ -27,6 +29,8 @@ var ReactRootIndex = require('ReactRootIndex');
29 var ReactUpdates = require('ReactUpdates');
30
31 var ReactInjection = {
32 + Component: ReactComponent.injection,
33 + CompositeComponent: ReactCompositeComponent.injection,
34 DOMProperty: DOMProperty.injection,
35 EventPluginHub: EventPluginHub.injection,
36 DOM: ReactDOM.injection,