Skip to content

Commit

Permalink
Use a shim file to load addons' dependencies on DOM
Browse files Browse the repository at this point in the history
By replacing this intermediate file we can do the lazy loading
without needing any lazy requires. This set up works with ES
modules.

We could also replace the globalShim thing with aliased files
instead for consistency.
  • Loading branch information
sebmarkbage committed Aug 4, 2016
1 parent c6f32c5 commit 9e4485e
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 57 deletions.
31 changes: 9 additions & 22 deletions grunt/config/browserify.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ var grunt = require('grunt');
var UglifyJS = require('uglify-js');
var uglifyify = require('uglifyify');
var derequire = require('derequire');
var aliasify = require('aliasify');
var globalShim = require('browserify-global-shim');
var collapser = require('bundle-collapser/plugin');

var envifyDev = envify({NODE_ENV: process.env.NODE_ENV || 'development'});
var envifyProd = envify({NODE_ENV: process.env.NODE_ENV || 'production'});

var SECRET_INTERNALS_NAME = 'React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED';
var SECRET_DOM_INTERNALS_NAME = 'ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED';

var shimSharedModules = globalShim.configure({
'./ReactCurrentOwner': SECRET_INTERNALS_NAME + '.ReactCurrentOwner',
Expand All @@ -25,25 +25,12 @@ var shimSharedModules = globalShim.configure({
'./ReactChildren': 'React.Children',
});

// Shim references to ReactDOM internals from addons.
var shimDOM = globalShim.configure({
'./ReactDOM': 'ReactDOM',
'./ReactInstanceMap': SECRET_DOM_INTERNALS_NAME + '.ReactInstanceMap',

// TestUtils pulls in a bunch of internals.
'./EventConstants': SECRET_DOM_INTERNALS_NAME + '.EventConstants',
'./EventPluginHub': SECRET_DOM_INTERNALS_NAME + '.EventPluginHub',
'./EventPluginRegistry': SECRET_DOM_INTERNALS_NAME + '.EventPluginRegistry',
'./EventPropagators': SECRET_DOM_INTERNALS_NAME + '.EventPropagators',
'./ReactDefaultInjection': SECRET_DOM_INTERNALS_NAME + '.ReactDefaultInjection',
'./ReactDOMComponentTree': SECRET_DOM_INTERNALS_NAME + '.ReactDOMComponentTree',
'./ReactBrowserEventEmitter': SECRET_DOM_INTERNALS_NAME + '.ReactBrowserEventEmitter',
'./ReactCompositeComponent': SECRET_DOM_INTERNALS_NAME + '.ReactCompositeComponent',
'./ReactInstrumentation': SECRET_DOM_INTERNALS_NAME + '.ReactInstrumentation',
'./ReactReconciler': SECRET_DOM_INTERNALS_NAME + '.ReactReconciler',
'./ReactUpdates': SECRET_DOM_INTERNALS_NAME + '.ReactUpdates',
'./SyntheticEvent': SECRET_DOM_INTERNALS_NAME + '.SyntheticEvent',
'./findDOMNode': SECRET_DOM_INTERNALS_NAME + '.findDOMNode',
var shimDOMModules = aliasify.configure({

'aliases': {
'./ReactAddonsDOMDependencies': './build/modules/ReactAddonsDOMDependenciesUMDShim.js',
}

});

var SIMPLE_TEMPLATE =
Expand Down Expand Up @@ -121,7 +108,7 @@ var addons = {
debug: false,
standalone: 'React',
packageName: 'React (with addons)',
transforms: [shimDOM],
transforms: [shimDOMModules],
globalTransforms: [envifyDev],
plugins: [collapser],
after: [derequire, simpleBannerify],
Expand All @@ -135,7 +122,7 @@ var addonsMin = {
debug: false,
standalone: 'React',
packageName: 'React (with addons)',
transforms: [shimDOM, envifyProd, uglifyify],
transforms: [shimDOMModules, envifyProd, uglifyify],
globalTransforms: [envifyProd],
plugins: [collapser],
// No need to derequire because the minifier will mangle
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"version": "16.0.0-alpha",
"devDependencies": {
"aliasify": "^2.0.0",
"art": "^0.10.1",
"async": "^1.5.0",
"babel-cli": "^6.6.5",
Expand Down
36 changes: 36 additions & 0 deletions src/addons/ReactAddonsDOMDependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactAddonsDOMDependencies
*/

'use strict';

var ReactDOM = require('ReactDOM');
var ReactInstanceMap = require('ReactInstanceMap');

exports.getReactDOM = function() {
return ReactDOM;
};

exports.getReactInstanceMap = function() {
return ReactInstanceMap;
};

if (__DEV__) {
var ReactPerf = require('ReactPerf');
var ReactTestUtils = require('ReactTestUtils');

exports.getReactPerf = function() {
return ReactPerf;
};

exports.getReactTestUtils = function() {
return ReactTestUtils;
};
}
9 changes: 5 additions & 4 deletions src/addons/ReactWithAddons.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

var LinkedStateMixin = require('LinkedStateMixin');
var React = require('React');
var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');
var ReactComponentWithPureRenderMixin =
require('ReactComponentWithPureRenderMixin');
var ReactCSSTransitionGroup = require('ReactCSSTransitionGroup');
Expand All @@ -34,18 +35,18 @@ React.addons = {
};

if (__DEV__) {
// We need to lazily require these modules for the browser build since they
// will depend on DOM internals which hasn't loaded yet.
// For the UMD build we get these lazily from the global since they're tied
// to the DOM renderer and it hasn't loaded yet.
Object.defineProperty(React.addons, 'Perf', {
enumerable: true,
get: function() {
return require('ReactPerf');
return ReactAddonsDOMDependencies.getReactPerf();
},
});
Object.defineProperty(React.addons, 'TestUtils', {
enumerable: true,
get: function() {
return require('ReactTestUtils');
return ReactAddonsDOMDependencies.getReactTestUtils();
},
});
}
Expand Down
9 changes: 2 additions & 7 deletions src/addons/transitions/ReactCSSTransitionGroupChild.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
'use strict';

var React = require('React');
// For the browser build we need to lazily load this since the DOM package
// instantiates after the addons package.
var ReactDOM = null;
var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');

var CSSCore = require('CSSCore');
var ReactTransitionEvents = require('ReactTransitionEvents');
Expand Down Expand Up @@ -56,7 +54,7 @@ var ReactCSSTransitionGroupChild = React.createClass({
},

transition: function(animationType, finishCallback, userSpecifiedDelay) {
var node = ReactDOM.findDOMNode(this);
var node = ReactAddonsDOMDependencies.getReactDOM().findDOMNode(this);

if (!node) {
if (finishCallback) {
Expand Down Expand Up @@ -126,9 +124,6 @@ var ReactCSSTransitionGroupChild = React.createClass({
},

componentWillMount: function() {
if (!ReactDOM) {
ReactDOM = require('ReactDOM');
}
this.classNameAndNodeQueue = [];
this.transitionTimeouts = [];
},
Expand Down
15 changes: 5 additions & 10 deletions src/addons/transitions/ReactTransitionGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
'use strict';

var React = require('React');
// We need to lazily require this for the browser build because the DOM
// renderer gets initialized after the main React bundle.
var ReactInstanceMap = null;
var ReactAddonsDOMDependencies = require('ReactAddonsDOMDependencies');
var ReactTransitionChildMapping = require('ReactTransitionChildMapping');

var emptyFunction = require('emptyFunction');
Expand Down Expand Up @@ -47,9 +45,6 @@ var ReactTransitionGroup = React.createClass({
},

componentWillMount: function() {
if (!ReactInstanceMap) {
ReactInstanceMap = require('ReactInstanceMap');
}
this.currentlyTransitioningKeys = {};
this.keysToEnter = [];
this.keysToLeave = [];
Expand All @@ -69,7 +64,7 @@ var ReactTransitionGroup = React.createClass({
if (__DEV__) {
nextChildMapping = ReactTransitionChildMapping.getChildMapping(
nextProps.children,
ReactInstanceMap.get(this)._debugID
ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID
);
} else {
nextChildMapping = ReactTransitionChildMapping.getChildMapping(
Expand Down Expand Up @@ -142,7 +137,7 @@ var ReactTransitionGroup = React.createClass({
if (__DEV__) {
currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children,
ReactInstanceMap.get(this)._debugID
ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID
);
} else {
currentChildMapping = ReactTransitionChildMapping.getChildMapping(
Expand Down Expand Up @@ -182,7 +177,7 @@ var ReactTransitionGroup = React.createClass({
if (__DEV__) {
currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children,
ReactInstanceMap.get(this)._debugID
ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID
);
} else {
currentChildMapping = ReactTransitionChildMapping.getChildMapping(
Expand Down Expand Up @@ -223,7 +218,7 @@ var ReactTransitionGroup = React.createClass({
if (__DEV__) {
currentChildMapping = ReactTransitionChildMapping.getChildMapping(
this.props.children,
ReactInstanceMap.get(this)._debugID
ReactAddonsDOMDependencies.getReactInstanceMap().get(this)._debugID
);
} else {
currentChildMapping = ReactTransitionChildMapping.getChildMapping(
Expand Down
18 changes: 4 additions & 14 deletions src/umd/ReactDOMUMDEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,13 @@ var ReactDOMUMDEntry = Object.assign({
}, ReactDOM);

if (__DEV__) {
// These are used by ReactTestUtils in ReactWithAddons. Ugh.
Object.assign(
ReactDOMUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
{
EventConstants: require('EventConstants'),
EventPluginHub: require('EventPluginHub'),
EventPluginRegistry: require('EventPluginRegistry'),
EventPropagators: require('EventPropagators'),
ReactDefaultInjection: require('ReactDefaultInjection'),
ReactDOMComponentTree: require('ReactDOMComponentTree'),
ReactBrowserEventEmitter: require('ReactBrowserEventEmitter'),
ReactCompositeComponent: require('ReactCompositeComponent'),
ReactInstrumentation: require('ReactInstrumentation'),
ReactReconciler: require('ReactReconciler'),
ReactUpdates: require('ReactUpdates'),
SyntheticEvent: require('SyntheticEvent'),
findDOMNode: require('findDOMNode'),
// ReactPerf and ReactTestUtils currently only work with the DOM renderer
// so we expose them from here, but only in DEV mode.
ReactPerf: require('ReactPerf'),
ReactTestUtils: require('ReactTestUtils'),
}
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/umd/ReactWithAddonsUMDEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
'use strict';

var ReactWithAddons = require('ReactWithAddons');
var ReactCurrentOwner = require('ReactCurrentOwner');
var ReactComponentTreeHook = require('ReactComponentTreeHook');

// `version` will be added here by the React module.
var ReactWithAddonsUMDEntry = Object.assign({
Expand Down
30 changes: 30 additions & 0 deletions src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactAddonsDOMDependenciesUMDShim
*/

'use strict';

exports.getReactDOM = function() {
return ReactDOM;
};

exports.getReactInstanceMap = function() {
return ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactInstanceMap;
};

if (__DEV__) {
exports.getReactPerf = function() {
return ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactPerf;
};

exports.getReactTestUtils = function() {
return ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactTestUtils;
};
}

0 comments on commit 9e4485e

Please sign in to comment.