From e0595bb66f437d85b71f2c9fc2733e43b9fb1b54 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Tue, 12 Jul 2016 18:58:50 -0700 Subject: [PATCH 01/16] revert "Disable DebugTools in production (#7189)" --- src/renderers/dom/shared/ReactDOMDebugTool.js | 8 ++++--- .../dom/shared/ReactDOMInstrumentation.js | 9 ++------ src/renderers/shared/ReactDebugTool.js | 22 ++++++++++--------- src/renderers/shared/ReactInstrumentation.js | 9 ++------ 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/renderers/dom/shared/ReactDOMDebugTool.js b/src/renderers/dom/shared/ReactDOMDebugTool.js index aae63af9164c9..107f0052d2c42 100644 --- a/src/renderers/dom/shared/ReactDOMDebugTool.js +++ b/src/renderers/dom/shared/ReactDOMDebugTool.js @@ -11,9 +11,9 @@ 'use strict'; +var ReactDebugTool = require('ReactDebugTool'); var ReactDOMNullInputValuePropDevtool = require('ReactDOMNullInputValuePropDevtool'); var ReactDOMUnknownPropertyDevtool = require('ReactDOMUnknownPropertyDevtool'); -var ReactDebugTool = require('ReactDebugTool'); var warning = require('warning'); @@ -66,7 +66,9 @@ var ReactDOMDebugTool = { }, }; -ReactDOMDebugTool.addDevtool(ReactDOMUnknownPropertyDevtool); -ReactDOMDebugTool.addDevtool(ReactDOMNullInputValuePropDevtool); +if (__DEV__) { + ReactDOMDebugTool.addDevtool(ReactDOMUnknownPropertyDevtool); + ReactDOMDebugTool.addDevtool(ReactDOMNullInputValuePropDevtool); +} module.exports = ReactDOMDebugTool; diff --git a/src/renderers/dom/shared/ReactDOMInstrumentation.js b/src/renderers/dom/shared/ReactDOMInstrumentation.js index 4f31a7818dd36..b290c6c553cf0 100644 --- a/src/renderers/dom/shared/ReactDOMInstrumentation.js +++ b/src/renderers/dom/shared/ReactDOMInstrumentation.js @@ -11,11 +11,6 @@ 'use strict'; -var debugTool = null; +var ReactDOMDebugTool = require('ReactDOMDebugTool'); -if (__DEV__) { - var ReactDOMDebugTool = require('ReactDOMDebugTool'); - debugTool = ReactDOMDebugTool; -} - -module.exports = {debugTool}; +module.exports = {debugTool: ReactDOMDebugTool}; diff --git a/src/renderers/shared/ReactDebugTool.js b/src/renderers/shared/ReactDebugTool.js index e8c5d2f16d659..c7da57e35a1d5 100644 --- a/src/renderers/shared/ReactDebugTool.js +++ b/src/renderers/shared/ReactDebugTool.js @@ -11,11 +11,11 @@ 'use strict'; -var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool'); -var ReactHostOperationHistoryDevtool = require('ReactHostOperationHistoryDevtool'); -var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); -var ReactChildrenMutationWarningDevtool = require('ReactChildrenMutationWarningDevtool'); var ExecutionEnvironment = require('ExecutionEnvironment'); +var ReactChildrenMutationWarningDevtool = require('ReactChildrenMutationWarningDevtool'); +var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); +var ReactHostOperationHistoryDevtool = require('ReactHostOperationHistoryDevtool'); +var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool'); var performanceNow = require('performanceNow'); var warning = require('warning'); @@ -325,12 +325,14 @@ var ReactDebugTool = { }, }; -ReactDebugTool.addDevtool(ReactInvalidSetStateWarningDevTool); -ReactDebugTool.addDevtool(ReactComponentTreeDevtool); -ReactDebugTool.addDevtool(ReactChildrenMutationWarningDevtool); -var url = (ExecutionEnvironment.canUseDOM && window.location.href) || ''; -if ((/[?&]react_perf\b/).test(url)) { - ReactDebugTool.beginProfiling(); +if (__DEV__) { + ReactDebugTool.addDevtool(ReactInvalidSetStateWarningDevTool); + ReactDebugTool.addDevtool(ReactComponentTreeDevtool); + ReactDebugTool.addDevtool(ReactChildrenMutationWarningDevtool); + var url = (ExecutionEnvironment.canUseDOM && window.location.href) || ''; + if ((/[?&]react_perf\b/).test(url)) { + ReactDebugTool.beginProfiling(); + } } module.exports = ReactDebugTool; diff --git a/src/renderers/shared/ReactInstrumentation.js b/src/renderers/shared/ReactInstrumentation.js index 08419bc0e2961..066da6aaae823 100644 --- a/src/renderers/shared/ReactInstrumentation.js +++ b/src/renderers/shared/ReactInstrumentation.js @@ -11,11 +11,6 @@ 'use strict'; -var debugTool = null; +var ReactDebugTool = require('ReactDebugTool'); -if (__DEV__) { - var ReactDebugTool = require('ReactDebugTool'); - debugTool = ReactDebugTool; -} - -module.exports = {debugTool}; +module.exports = {debugTool: ReactDebugTool}; From 127c1885527d7c9c9352224c3834ada988a9e7d4 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Tue, 12 Jul 2016 19:04:49 -0700 Subject: [PATCH 02/16] revert "Inline dev-only requires (#7188)" --- .../classic/types/checkReactTypeSpec.js | 23 +++---------------- .../stack/reconciler/ReactChildReconciler.js | 21 ++--------------- 2 files changed, 5 insertions(+), 39 deletions(-) diff --git a/src/isomorphic/classic/types/checkReactTypeSpec.js b/src/isomorphic/classic/types/checkReactTypeSpec.js index 84211727fa977..196d387a9cbbb 100644 --- a/src/isomorphic/classic/types/checkReactTypeSpec.js +++ b/src/isomorphic/classic/types/checkReactTypeSpec.js @@ -11,27 +11,13 @@ 'use strict'; +var ReactComponentTreeDevtoolDev = require('ReactComponentTreeDevtoolDev'); var ReactPropTypeLocationNames = require('ReactPropTypeLocationNames'); var ReactPropTypesSecret = require('ReactPropTypesSecret'); var invariant = require('invariant'); var warning = require('warning'); -var ReactComponentTreeDevtool; - -if ( - typeof process !== 'undefined' && - process.env && - process.env.NODE_ENV === 'test' -) { - // Temporary hack. - // Inline requires don't work well with Jest: - // https://github.com/facebook/react/issues/7240 - // Remove the inline requires when we don't need them anymore: - // https://github.com/facebook/react/pull/7178 - ReactComponentTreeDevtool = require('ReactComponentTreeDevtool') -} - var loggedTypeFailures = {}; /** @@ -88,13 +74,10 @@ function checkReactTypeSpec(typeSpecs, values, location, componentName, element, var componentStackInfo = ''; if (__DEV__) { - if (!ReactComponentTreeDevtool) { - ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); - } if (debugID !== null) { - componentStackInfo = ReactComponentTreeDevtool.getStackAddendumByID(debugID); + componentStackInfo = ReactComponentTreeDevtoolDev.getStackAddendumByID(debugID); } else if (element !== null) { - componentStackInfo = ReactComponentTreeDevtool.getCurrentStackAddendum(element); + componentStackInfo = ReactComponentTreeDevtoolDev.getCurrentStackAddendum(element); } } diff --git a/src/renderers/shared/stack/reconciler/ReactChildReconciler.js b/src/renderers/shared/stack/reconciler/ReactChildReconciler.js index 0d94b766d8ded..8ebeebd074cf0 100644 --- a/src/renderers/shared/stack/reconciler/ReactChildReconciler.js +++ b/src/renderers/shared/stack/reconciler/ReactChildReconciler.js @@ -11,6 +11,7 @@ 'use strict'; +var ReactComponentTreeDevtoolDev = require('ReactComponentTreeDevtoolDev'); var ReactReconciler = require('ReactReconciler'); var instantiateReactComponent = require('instantiateReactComponent'); @@ -19,35 +20,17 @@ var shouldUpdateReactComponent = require('shouldUpdateReactComponent'); var traverseAllChildren = require('traverseAllChildren'); var warning = require('warning'); -var ReactComponentTreeDevtool; - -if ( - typeof process !== 'undefined' && - process.env && - process.env.NODE_ENV === 'test' -) { - // Temporary hack. - // Inline requires don't work well with Jest: - // https://github.com/facebook/react/issues/7240 - // Remove the inline requires when we don't need them anymore: - // https://github.com/facebook/react/pull/7178 - ReactComponentTreeDevtool = require('ReactComponentTreeDevtool') -} - function instantiateChild(childInstances, child, name, selfDebugID) { // We found a component instance. var keyUnique = (childInstances[name] === undefined); if (__DEV__) { - if (!ReactComponentTreeDevtool) { - ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); - } warning( keyUnique, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.%s', KeyEscapeUtils.unescape(name), - ReactComponentTreeDevtool.getStackAddendumByID(selfDebugID) + ReactComponentTreeDevtoolDev.getStackAddendumByID(selfDebugID) ); } if (child != null && keyUnique) { From a1cf7a9620799a8e03799adbf5038cb17dd12a13 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Sat, 2 Jul 2016 01:58:04 -0700 Subject: [PATCH 03/16] moved all requires to top level --- src/addons/ReactWithAddons.js | 6 ++++-- src/isomorphic/React.js | 2 +- src/isomorphic/classic/element/ReactDOMFactories.js | 2 +- src/renderers/dom/ReactDOM.js | 2 +- src/renderers/shared/ReactDebugTool.js | 5 +++++ 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/addons/ReactWithAddons.js b/src/addons/ReactWithAddons.js index 94102c5c2e8b6..db8280a886404 100644 --- a/src/addons/ReactWithAddons.js +++ b/src/addons/ReactWithAddons.js @@ -17,6 +17,8 @@ var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); var ReactCSSTransitionGroup = require('ReactCSSTransitionGroup'); var ReactFragment = require('ReactFragment'); +var ReactPerf = require('ReactPerf'); +var ReactTestUtils = require('ReactTestUtils'); var ReactTransitionGroup = require('ReactTransitionGroup'); var shallowCompare = require('shallowCompare'); @@ -34,8 +36,8 @@ React.addons = { }; if (__DEV__) { - React.addons.Perf = require('ReactPerf'); - React.addons.TestUtils = require('ReactTestUtils'); + React.addons.Perf = ReactPerf; + React.addons.TestUtils = ReactTestUtils; } module.exports = React; diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index c791b30e08cf0..d9c878892261d 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -17,6 +17,7 @@ var ReactPureComponent = require('ReactPureComponent'); var ReactClass = require('ReactClass'); var ReactDOMFactories = require('ReactDOMFactories'); var ReactElement = require('ReactElement'); +var ReactElementValidator = require('ReactElementValidator'); var ReactPropTypes = require('ReactPropTypes'); var ReactVersion = require('ReactVersion'); @@ -28,7 +29,6 @@ var createFactory = ReactElement.createFactory; var cloneElement = ReactElement.cloneElement; if (__DEV__) { - var ReactElementValidator = require('ReactElementValidator'); createElement = ReactElementValidator.createElement; createFactory = ReactElementValidator.createFactory; cloneElement = ReactElementValidator.cloneElement; diff --git a/src/isomorphic/classic/element/ReactDOMFactories.js b/src/isomorphic/classic/element/ReactDOMFactories.js index 44b2a6f997fd3..422aaae77a015 100644 --- a/src/isomorphic/classic/element/ReactDOMFactories.js +++ b/src/isomorphic/classic/element/ReactDOMFactories.js @@ -12,6 +12,7 @@ 'use strict'; var ReactElement = require('ReactElement'); +var ReactElementValidator = require('ReactElementValidator'); var mapObject = require('mapObject'); @@ -23,7 +24,6 @@ var mapObject = require('mapObject'); */ function createDOMFactory(tag) { if (__DEV__) { - var ReactElementValidator = require('ReactElementValidator'); return ReactElementValidator.createFactory(tag); } return ReactElement.createFactory(tag); diff --git a/src/renderers/dom/ReactDOM.js b/src/renderers/dom/ReactDOM.js index b546e46948300..afd46fa0a4b60 100644 --- a/src/renderers/dom/ReactDOM.js +++ b/src/renderers/dom/ReactDOM.js @@ -13,6 +13,7 @@ 'use strict'; +var ExecutionEnvironment = require('ExecutionEnvironment'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactDefaultInjection = require('ReactDefaultInjection'); var ReactMount = require('ReactMount'); @@ -66,7 +67,6 @@ if ( } if (__DEV__) { - var ExecutionEnvironment = require('ExecutionEnvironment'); if (ExecutionEnvironment.canUseDOM && window.top === window.self) { // First check if devtools is not installed diff --git a/src/renderers/shared/ReactDebugTool.js b/src/renderers/shared/ReactDebugTool.js index c7da57e35a1d5..af55f09a3975b 100644 --- a/src/renderers/shared/ReactDebugTool.js +++ b/src/renderers/shared/ReactDebugTool.js @@ -17,6 +17,11 @@ var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); var ReactHostOperationHistoryDevtool = require('ReactHostOperationHistoryDevtool'); var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool'); +var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool'); +var ReactHostOperationHistoryDevtool = require('ReactHostOperationHistoryDevtool'); +var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); +var ReactChildrenMutationWarningDevtool = require('ReactChildrenMutationWarningDevtool'); + var performanceNow = require('performanceNow'); var warning = require('warning'); From 621a294885eaa27f59df10d16eca8c3cc486b815 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Sat, 2 Jul 2016 22:46:36 -0700 Subject: [PATCH 04/16] added transform-es6-modulify babel pass --- scripts/babel/transform-es6-modulify.js | 59 +++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 scripts/babel/transform-es6-modulify.js diff --git a/scripts/babel/transform-es6-modulify.js b/scripts/babel/transform-es6-modulify.js new file mode 100644 index 0000000000000..f142a79282e64 --- /dev/null +++ b/scripts/babel/transform-es6-modulify.js @@ -0,0 +1,59 @@ +/** + * Copyright (c) 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. + */ +'use strict'; + +module.exports = function(babel) { + const t = babel.types; + + return { + visitor: { + CallExpression: function(path, file) { + // TODO: support RHS member expression and LHS destructuring + if ( + !t.isIdentifier(path.node.callee, {name: 'require'}) || + !t.isVariableDeclarator(path.parent) || // not an assignment + path.scope.path.type !== 'Program' // is top-level + ) { + return; + } + + // instead of calling `replaceWith`, this handles cases like + // `var m0 = require('m0'), m1 = require('m1');` + // we don't have this pattern in the code base but + // it happens when Babel inserts requires + path.parentPath.parentPath.insertBefore( + t.importDeclaration( + [t.importDefaultSpecifier(path.parent.id)], + path.node.arguments[0] + ) + ); + path.parentPath.remove(); + }, + + AssignmentExpression: function(path, file) { + if ( + !path.get('left').matchesPattern('module.exports') || + path.scope.path.type !== 'Program' // is top-level + ) { + return; + } + + // TODO: use FunctionDeclaration and ClassDeclaration + // and don't make everything an Expression + let rhs = path.node.right; + + path.parentPath.replaceWith( + t.exportDefaultDeclaration( + rhs + ) + ); + }, + }, + }; +}; From 10b1079e3e11559d20cada459e8ef694fb6e8e65 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Sat, 2 Jul 2016 22:47:01 -0700 Subject: [PATCH 05/16] added rollup config --- package.json | 9 ++++++- scripts/rollup/rollup.config.dev.js | 35 ++++++++++++++++++++++++++ scripts/rollup/rollup.config.prod.js | 37 ++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 scripts/rollup/rollup.config.dev.js create mode 100644 scripts/rollup/rollup.config.prod.js diff --git a/package.json b/package.json index 85bc4a1101a54..e65fea42ddb35 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,11 @@ "loose-envify": "^1.1.0", "object-assign": "^4.1.0", "platform": "^1.1.0", + "rollup": "^0.33.0", + "rollup-plugin-babel": "^2.6.1", + "rollup-plugin-node-resolve": "^1.7.1", + "rollup-plugin-replace": "^1.1.1", + "rollup-plugin-uglify": "^1.0.1", "run-sequence": "^1.1.4", "through2": "^2.0.0", "tmp": "~0.0.28", @@ -81,7 +86,9 @@ "lint": "grunt lint", "postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json", "test": "jest", - "flow": "flow" + "flow": "flow", + "rollup:dev": "rollup -c scripts/rollup/rollup.config.dev.js", + "rollup:prod": "rollup -c scripts/rollup/rollup.config.prod.js" }, "jest": { "modulePathIgnorePatterns": [ diff --git a/scripts/rollup/rollup.config.dev.js b/scripts/rollup/rollup.config.dev.js new file mode 100644 index 0000000000000..cbec66400a1df --- /dev/null +++ b/scripts/rollup/rollup.config.dev.js @@ -0,0 +1,35 @@ +/** + * Copyright (c) 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. + */ +'use strict'; + +var babel = require('rollup-plugin-babel'); +var replace = require('rollup-plugin-replace'); +var resolve = require('rollup-plugin-node-resolve'); + +var babelEs6ModulifyPlugin = require('../babel/transform-es6-modulify'); + +module.exports = { + dest: 'build/react.rollup.dev.js', + entry: 'build/modules/ReactUMDEntry.js', + moduleName: 'React', + format: 'umd', + plugins: [ + babel({ + babelrc: false, + plugins: [babelEs6ModulifyPlugin], + }), + replace({ + 'process.env.NODE_ENV': JSON.stringify('development'), + }), + resolve({ + main: true, + }), + ], + sourceMap: false, +}; diff --git a/scripts/rollup/rollup.config.prod.js b/scripts/rollup/rollup.config.prod.js new file mode 100644 index 0000000000000..34be1e522821a --- /dev/null +++ b/scripts/rollup/rollup.config.prod.js @@ -0,0 +1,37 @@ +/** + * Copyright (c) 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. + */ +'use strict'; + +var babel = require('rollup-plugin-babel'); +var replace = require('rollup-plugin-replace'); +var resolve = require('rollup-plugin-node-resolve'); +var uglify = require('rollup-plugin-uglify'); + +var babelEs6ModulifyPlugin = require('../babel/transform-es6-modulify'); + +module.exports = { + dest: 'build/react.rollup.prod.js', + entry: 'build/modules/ReactUMDEntry.js', + moduleName: 'React', + format: 'umd', + plugins: [ + babel({ + babelrc: false, + plugins: [babelEs6ModulifyPlugin], + }), + replace({ + 'process.env.NODE_ENV': JSON.stringify('production'), + }), + resolve({ + main: true, + }), + uglify(), + ], + sourceMap: false, +}; From f35bc47a5d61507233857797089e07abd60228b9 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Mon, 11 Jul 2016 01:00:49 -0700 Subject: [PATCH 06/16] updated babel plugin (better error message) --- .../__tests__/transform-es6-modulify-test.js | 184 ++++++++++++++++++ scripts/babel/transform-es6-modulify.js | 93 +++++++-- 2 files changed, 258 insertions(+), 19 deletions(-) create mode 100644 scripts/babel/__tests__/transform-es6-modulify-test.js diff --git a/scripts/babel/__tests__/transform-es6-modulify-test.js b/scripts/babel/__tests__/transform-es6-modulify-test.js new file mode 100644 index 0000000000000..cf6efd4cfdf18 --- /dev/null +++ b/scripts/babel/__tests__/transform-es6-modulify-test.js @@ -0,0 +1,184 @@ +/** + * Copyright (c) 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. + */ +/* eslint-disable quotes */ +'use strict'; + +const babel = require('babel-core'); +const babelEs6ModulifyPlugin = require('../transform-es6-modulify'); + +function transform(input) { + return babel.transform(input, { + plugins: [babelEs6ModulifyPlugin], + }).code; +} + +function compare(input, output) { + var compiled = transform(input); + expect(compiled).toEqual(output); +} + +describe('transform-es6-modulify', () => { + // var ... = require('...'); -> import ... from '...'; + it('should rewrite `require` to `import`', () => { + compare( + "var React = require('react');", + + "import React from 'react';" + ); + + compare( + "var React = require('react');", + + "import React from 'react';" + ); + }); + + it('rewrites multi requires inserted by Babel', () => { + compare( +`var _prodInvariant = require('./reactProdInvariant'), + _assign = require('object-assign');`, + +`import _prodInvariant from './reactProdInvariant'; +import _assign from 'object-assign';` + ); + }); + + it('should throw when the RHS is a MemberExpression', () => { + expect(() => { + transform("var createElement = require('react').createElement;"); + }).toThrowError(/Invalid require: `require\(\)` must be in a form of `var ... = require\(...\);`/); + }); + + it('should throw for non-top level requires', () => { + expect(() => { + transform( +` +if (3 > 2) { + var React = require('react'); +} +` + ); + }).toThrowError(/Invalid require: `require\(\)` must be on the top-level/); + }); + + it('should throw when `require()` is not in a VariableDeclarator', () => { + expect(() => { + transform( +` +var React; +React = require('react'); +`); + }).toThrowError(/Invalid require: `require\(\)` must be directly in a variable declarator/); + + expect(() => { + transform("var React = require('react') || null;"); + }).toThrowError(/Invalid require: `require\(\)` must be directly in a variable declarator/); + + expect(() => { + transform("require('inject-something');"); + }).toThrowError(/Invalid require: `require\(\)` must be directly in a variable declarator/); + }); + + it('should throw when the parameter passed to `require()` is not a literal string', () => { + expect(() => { + transform("var React = require('re' + 'act');"); + }).toThrowError(/Invalid require: `require\(\)` must take a literal string as argument/); + }); + + it('should throw when it sees destructuring', () => { + expect(() => { + transform("var {createElement} = require('react');"); + }).toThrowError(/Invalid require: left hand side of `require\(\)` must be an identifier/); + }); + + + // module.exports = ...; -> exports default ...; + it('should rewrite `module.exports` to `export default`', () => { + compare( + "module.exports = {};", + + "export default {};" + ); + + compare( + "module.exports = React;", + + "export default React;" + ); + + compare( + "module.exports = 3 > 2 ? React : ReactDOM;", + + "export default 3 > 2 ? React : ReactDOM;" + ); + + compare( + "module.exports = class Foo {};", + + "export default (class Foo {})" + ); + + compare( + "module.exports = class {};", + + "export default (class {})" + ); + + compare( + "module.exports = function foo() {};", + + "export default (function foo() {})" + ); + + compare( + "module.exports = function() {};", + + "export default (function () {})" + ); + }); + + it('should throw when it sees module.exports.foo = ...', () => { + expect(() => { + transform("module.exports.createElement = createElement;"); + }).toThrowError(/Invalid exports: `module.exports` must be in a form of `module.exports = ...;`/); + }); + + it('should throw when it sees module.exports on the right hand side', () => { + expect(() => { + transform('foo = module.exports;'); + }).toThrowError(/Invalid exports: `module.exports` must be in a form of `module.exports = ...;`/); + + expect(() => { + transform(`var foo = module.exports;`); + }).toThrowError(/Invalid exports: `module.exports` must be in a form of `module.exports = ...;`/); + }); + + it('should throw for non-top level exports', () => { + expect(() => { + transform( +` +if (3 > 2) { + module.exports = React; +} +` + ); + }).toThrowError(/Invalid exports: `module.exports = ...` must be on the top-level/); + }); + + it('should throw when there are more than one module.exports', () => { + expect(() => { + transform( +` +module.exports = React; +module.exports = ReactDOM; +` + ); + }).toThrowError(/Invalid exports: `module.exports = ...` can only happen once in a module/); + }); +}); diff --git a/scripts/babel/transform-es6-modulify.js b/scripts/babel/transform-es6-modulify.js index f142a79282e64..fa3659fa3478b 100644 --- a/scripts/babel/transform-es6-modulify.js +++ b/scripts/babel/transform-es6-modulify.js @@ -8,25 +8,63 @@ */ 'use strict'; +var basename = require('path').basename; + +function getFileLoc(path, file) { + if (file.file.opts.filename === 'unknown') { + return ''; + } + var startLinePos = path.node.loc.start.line; + var fileName = file.file.opts.filename; + var moduleName = basename(fileName); + return ( + 'Check line ' + startLinePos + ' at `' + fileName + + '` and the original `' + moduleName + '` module under `/src`.' + ); +} + module.exports = function(babel) { - const t = babel.types; + var t = babel.types; return { visitor: { CallExpression: function(path, file) { - // TODO: support RHS member expression and LHS destructuring - if ( - !t.isIdentifier(path.node.callee, {name: 'require'}) || - !t.isVariableDeclarator(path.parent) || // not an assignment - path.scope.path.type !== 'Program' // is top-level - ) { + if (!t.isIdentifier(path.node.callee, {name: 'require'})) { return; } + var sourceLocText = getFileLoc(path, file); + if (t.isMemberExpression(path.parent)) { + // `var createElement = require('react').createElement;` + throw new Error( + 'Invalid require: `require()` must be in a form of `var ... = require(...);`. ' + sourceLocText + ); + } else if (!t.isVariableDeclarator(path.parent)) { + // is not directly in a VariableDeclarator + throw new Error( + 'Invalid require: `require()` must be directly in a variable declarator. ' + sourceLocText + ); + } else if (!t.isProgram(path.scope.block)) { + // is not on the top-level + throw new Error( + 'Invalid require: `require()` must be on the top-level. ' + sourceLocText + ); + } else if (!t.isStringLiteral(path.node.arguments[0])) { + // the argument is not a StringLiteral + throw new Error( + 'Invalid require: `require()` must take a literal string as argument. ' + sourceLocText + ); + } else if (!t.isIdentifier(path.parent.id)) { + // LHS is not an Identifier; presumably an ObjectPattern (destructuring) + throw new Error( + 'Invalid require: left hand side of `require()` must be an identifier. ' + sourceLocText + ); + } + // instead of calling `replaceWith`, this handles cases like // `var m0 = require('m0'), m1 = require('m1');` // we don't have this pattern in the code base but - // it happens when Babel inserts requires + // it happens when Babel inserts `require`s path.parentPath.parentPath.insertBefore( t.importDeclaration( [t.importDefaultSpecifier(path.parent.id)], @@ -36,22 +74,39 @@ module.exports = function(babel) { path.parentPath.remove(); }, - AssignmentExpression: function(path, file) { + MemberExpression: function(path, file) { + if (!path.matchesPattern('module.exports')) { + return; + } + + var sourceLocText = getFileLoc(path, file); if ( - !path.get('left').matchesPattern('module.exports') || - path.scope.path.type !== 'Program' // is top-level + !t.isAssignmentExpression(path.parent) || + path.node !== path.parent.left ) { - return; + // `module.exports` is on the RHS, or the LHS looks like `module.exports.foo` + throw new Error( + 'Invalid exports: `module.exports` must be in a form of `module.exports = ...;`. ' + sourceLocText + ); + } else if (!t.isProgram(path.scope.block)) { + // is not on the top-level + throw new Error( + 'Invalid exports: `module.exports = ...` must be on the top-level. ' + sourceLocText + ); } - // TODO: use FunctionDeclaration and ClassDeclaration - // and don't make everything an Expression - let rhs = path.node.right; + this.numberOfExports = this.numberOfExports ? this.numberOfExports + 1 : 1; + if (this.numberOfExports > 1) { + throw new Error( + 'Invalid exports: `module.exports = ...` can only happen once in a module. ' + sourceLocText + ); + } - path.parentPath.replaceWith( - t.exportDefaultDeclaration( - rhs - ) + path.parentPath.parentPath.replaceWith( + // for now, it's not necessary to convert the RHS to + // a FunctionDeclaration or a ClassDeclaration since we only export default + // (i.e., only named exports resolve the `id` field for naming) + t.exportDefaultDeclaration(path.parent.right) ); }, }, From ad995f0b4d32fd05daed4f7c17d2b84d6453f055 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Tue, 12 Jul 2016 14:39:19 -0700 Subject: [PATCH 07/16] replaced browserify with rollup --- Gruntfile.js | 22 ++-- grunt/config/browserify.js | 117 ------------------ grunt/config/rollup.js | 103 +++++++++++++++ grunt/tasks/rollup.js | 60 +++++++++ package.json | 10 +- packages/react/package.json | 5 - .../__tests__/transform-es6-modulify-test.js | 16 +-- scripts/babel/transform-es6-modulify.js | 4 +- scripts/rollup/rollup.config.dev.js | 35 ------ scripts/rollup/rollup.config.prod.js | 37 ------ 10 files changed, 186 insertions(+), 223 deletions(-) delete mode 100644 grunt/config/browserify.js create mode 100644 grunt/config/rollup.js create mode 100644 grunt/tasks/rollup.js delete mode 100644 scripts/rollup/rollup.config.dev.js delete mode 100644 scripts/rollup/rollup.config.prod.js diff --git a/Gruntfile.js b/Gruntfile.js index e2f2faa59c296..369c6a7ef110e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -11,7 +11,7 @@ module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), - browserify: require('./grunt/config/browserify'), + rollup: require('./grunt/config/rollup'), npm: require('./grunt/config/npm'), clean: [ './build', @@ -69,8 +69,8 @@ module.exports = function(grunt) { spawnGulp(['react:clean'], null, this.async()); }); - // Our own browserify-based tasks to build a single JS file build. - grunt.registerMultiTask('browserify', require('./grunt/tasks/browserify')); + // Our own Rollup-based tasks to build a single JS file build. + grunt.registerMultiTask('rollup', require('./grunt/tasks/rollup')); grunt.registerMultiTask('npm', require('./grunt/tasks/npm')); @@ -98,20 +98,20 @@ module.exports = function(grunt) { grunt.registerTask('build:basic', [ 'build-modules', 'version-check', - 'browserify:basic', + 'rollup:basic', ]); grunt.registerTask('build:addons', [ 'build-modules', - 'browserify:addons', + 'rollup:addons', ]); grunt.registerTask('build:min', [ 'build-modules', 'version-check', - 'browserify:min', + 'rollup:min', ]); grunt.registerTask('build:addons-min', [ 'build-modules', - 'browserify:addonsMin', + 'rollup:addonsMin', ]); grunt.registerTask('build:npm-react', [ 'version-check', @@ -133,10 +133,10 @@ module.exports = function(grunt) { 'delete-build-modules', 'build-modules', 'version-check', - 'browserify:basic', - 'browserify:addons', - 'browserify:min', - 'browserify:addonsMin', + 'rollup:basic', + 'rollup:addons', + 'rollup:min', + 'rollup:addonsMin', 'build:react-dom', 'npm-react:release', 'npm-react:pack', diff --git a/grunt/config/browserify.js b/grunt/config/browserify.js deleted file mode 100644 index bfcb01ddda4e6..0000000000000 --- a/grunt/config/browserify.js +++ /dev/null @@ -1,117 +0,0 @@ -/*eslint-disable no-multi-str */ - -'use strict'; - -var envify = require('loose-envify/custom'); -var grunt = require('grunt'); -var UglifyJS = require('uglify-js'); -var uglifyify = require('uglifyify'); -var derequire = require('derequire'); -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 SIMPLE_TEMPLATE = - grunt.file.read('./grunt/data/header-template-short.txt'); - -var LICENSE_TEMPLATE = - grunt.file.read('./grunt/data/header-template-extended.txt'); - -function minify(src) { - return UglifyJS.minify(src, {fromString: true}).code; -} - -// TODO: move this out to another build step maybe. -function bannerify(src) { - var version = grunt.config.data.pkg.version; - var packageName = this.data.packageName || this.data.standalone; - return ( - grunt.template.process( - LICENSE_TEMPLATE, - {data: {package: packageName, version: version}} - ) + - src - ); -} - -function simpleBannerify(src) { - var version = grunt.config.data.pkg.version; - var packageName = this.data.packageName || this.data.standalone; - return ( - grunt.template.process( - SIMPLE_TEMPLATE, - {data: {package: packageName, version: version}} - ) + - src - ); -} - -// Our basic config which we'll add to to make our other builds -var basic = { - entries: [ - './build/modules/ReactUMDEntry.js', - ], - outfile: './build/react.js', - debug: false, - standalone: 'React', - // Apply as global transform so that we also envify fbjs and any other deps - globalTransforms: [envifyDev], - plugins: [collapser], - after: [derequire, simpleBannerify], -}; - -var min = { - entries: [ - './build/modules/ReactUMDEntry.js', - ], - outfile: './build/react.min.js', - debug: false, - standalone: 'React', - // Envify twice. The first ensures that when we uglifyify, we have the right - // conditions to exclude requires. The global transform runs on deps. - transforms: [envifyProd, uglifyify], - globalTransforms: [envifyProd], - plugins: [collapser], - // No need to derequire because the minifier will mangle - // the "require" calls. - - after: [minify, bannerify], -}; - -var addons = { - entries: [ - './build/modules/ReactWithAddonsUMDEntry.js', - ], - outfile: './build/react-with-addons.js', - debug: false, - standalone: 'React', - packageName: 'React (with addons)', - globalTransforms: [envifyDev], - plugins: [collapser], - after: [derequire, simpleBannerify], -}; - -var addonsMin = { - entries: [ - './build/modules/ReactWithAddonsUMDEntry.js', - ], - outfile: './build/react-with-addons.min.js', - debug: false, - standalone: 'React', - packageName: 'React (with addons)', - transforms: [envifyProd, uglifyify], - globalTransforms: [envifyProd], - plugins: [collapser], - // No need to derequire because the minifier will mangle - // the "require" calls. - - after: [minify, bannerify], -}; - -module.exports = { - basic: basic, - min: min, - addons: addons, - addonsMin: addonsMin, -}; diff --git a/grunt/config/rollup.js b/grunt/config/rollup.js new file mode 100644 index 0000000000000..f7a0e6b89503f --- /dev/null +++ b/grunt/config/rollup.js @@ -0,0 +1,103 @@ +/** + * Copyright (c) 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. + */ +'use strict'; + +var grunt = require('grunt'); +var rollupBabel = require('rollup-plugin-babel'); +var rollupReplace = require('rollup-plugin-replace'); +var rollupResolve = require('rollup-plugin-node-resolve'); +var UglifyJS = require('uglify-js'); + +var babelEs6ModulifyTransform = require('../../scripts/babel/transform-es6-modulify'); + +var SIMPLE_TEMPLATE = + grunt.file.read('./grunt/data/header-template-short.txt'); + +var LICENSE_TEMPLATE = + grunt.file.read('./grunt/data/header-template-extended.txt'); + +function minify(src) { + return UglifyJS.minify(src, {fromString: true}).code; +} + +function bannerify(src) { + var version = grunt.config.data.pkg.version; + var packageName = this.data.packageName || this.data.moduleName; + return ( + grunt.template.process( + LICENSE_TEMPLATE, + {data: {package: packageName, version: version}} + ) + + src + ); +} + +function simpleBannerify(src) { + var version = grunt.config.data.pkg.version; + var packageName = this.data.packageName || this.data.moduleName; + return ( + grunt.template.process( + SIMPLE_TEMPLATE, + {data: {package: packageName, version: version}} + ) + + src + ); +} + +function getPlugins(replaceConfig) { + return [ + rollupBabel({ + babelrc: false, + plugins: [babelEs6ModulifyTransform], + }), + rollupReplace(replaceConfig), + rollupResolve({ + main: true, + }), + ]; +} + +var buildConfigs = { + basic: { + after: [simpleBannerify], + dest: 'build/react.js', + entry: 'build/modules/ReactUMDEntry.js', + format: 'umd', + moduleName: 'React', + plugins: getPlugins({'process.env.NODE_ENV': JSON.stringify('development')}), + }, + min: { + after: [minify, bannerify], + dest: 'build/react.min.js', + entry: 'build/modules/ReactUMDEntry.js', + format: 'umd', + moduleName: 'React', + plugins: getPlugins({'process.env.NODE_ENV': JSON.stringify('production')}), + }, + addons: { + after: [simpleBannerify], + dest: 'build/react-with-addons.js', + entry: 'build/modules/ReactWithAddonsUMDEntry.js', + format: 'umd', + moduleName: 'React', + packageName: 'React (with addons)', + plugins: getPlugins({'process.env.NODE_ENV': JSON.stringify('development')}), + }, + addonsMin: { + after: [minify, bannerify], + dest: 'build/react-with-addons.min.js', + entry: 'build/modules/ReactWithAddonsUMDEntry.js', + format: 'umd', + moduleName: 'React', + packageName: 'React (with addons)', + plugins: getPlugins({'process.env.NODE_ENV': JSON.stringify('production')}), + }, +}; + +module.exports = buildConfigs; diff --git a/grunt/tasks/rollup.js b/grunt/tasks/rollup.js new file mode 100644 index 0000000000000..afec14833338d --- /dev/null +++ b/grunt/tasks/rollup.js @@ -0,0 +1,60 @@ +/** + * Copyright (c) 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. + */ +'use strict'; + +var grunt = require('grunt'); +var rollup = require('rollup'); + +module.exports = function() { + /* + config fields: + { + after: Array<(code: string) => string>, + dest: string, + entry: string, + format: string, + moduleName: string, + packageName?: string, + plugins: Array, + } + */ + + var config = this.data; + config.after = config.after || []; + + // This task is async... + var done = this.async(); + + var ctx = this; + + rollup.rollup({ + entry: config.entry, + plugins: config.plugins, + }).then(function(bundle) { + var code = bundle.generate({ + exports: 'default', + dest: config.dest, + format: config.format, + moduleName: config.moduleName, + sourceMap: false, + useStrict: 'true', + }).code; + + code = config.after.reduce(function(src, postProcessor) { + // minify and bannerify + return postProcessor.call(ctx, src); + }, code); + + grunt.file.write(config.dest, code); + done(); + }).catch(function(err) { + grunt.log.error(err); + done(); + }); +}; diff --git a/package.json b/package.json index e65fea42ddb35..6cf24beba8819 100644 --- a/package.json +++ b/package.json @@ -32,13 +32,10 @@ "babel-preset-react": "^6.5.0", "babel-traverse": "^6.9.0", "babylon": "6.8.0", - "browserify": "^13.0.0", - "bundle-collapser": "^1.1.1", "coffee-script": "^1.8.0", "core-js": "^2.2.1", "coveralls": "^2.11.6", "del": "^2.0.2", - "derequire": "^2.0.3", "eslint": "1.10.3", "eslint-plugin-react": "4.1.0", "eslint-plugin-react-internal": "file:eslint-rules", @@ -70,8 +67,7 @@ "through2": "^2.0.0", "tmp": "~0.0.28", "typescript": "~1.8.10", - "uglify-js": "^2.5.0", - "uglifyify": "^3.0.1" + "uglify-js": "^2.5.0" }, "devEngines": { "node": "4.x || 5.x || 6.x", @@ -86,9 +82,7 @@ "lint": "grunt lint", "postinstall": "node node_modules/fbjs-scripts/node/check-dev-engines.js package.json", "test": "jest", - "flow": "flow", - "rollup:dev": "rollup -c scripts/rollup/rollup.config.dev.js", - "rollup:prod": "rollup -c scripts/rollup/rollup.config.prod.js" + "flow": "flow" }, "jest": { "modulePathIgnorePatterns": [ diff --git a/packages/react/package.json b/packages/react/package.json index 0c7f04eed8dec..516bf8567aaa9 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -26,10 +26,5 @@ "fbjs": "^0.8.1", "loose-envify": "^1.1.0", "object-assign": "^4.1.0" - }, - "browserify": { - "transform": [ - "loose-envify" - ] } } diff --git a/scripts/babel/__tests__/transform-es6-modulify-test.js b/scripts/babel/__tests__/transform-es6-modulify-test.js index cf6efd4cfdf18..f106ea35a980e 100644 --- a/scripts/babel/__tests__/transform-es6-modulify-test.js +++ b/scripts/babel/__tests__/transform-es6-modulify-test.js @@ -52,7 +52,7 @@ import _assign from 'object-assign';` it('should throw when the RHS is a MemberExpression', () => { expect(() => { transform("var createElement = require('react').createElement;"); - }).toThrowError(/Invalid require: `require\(\)` must be in a form of `var ... = require\(...\);`/); + }).toThrowError(/Invalid require: `require\(\)` must be in the form of `var ... = require\(...\);`/); }); it('should throw for non-top level requires', () => { @@ -121,42 +121,42 @@ React = require('react'); compare( "module.exports = class Foo {};", - "export default (class Foo {})" + "export default (class Foo {});" ); compare( "module.exports = class {};", - "export default (class {})" + "export default (class {});" ); compare( "module.exports = function foo() {};", - "export default (function foo() {})" + "export default (function foo() {});" ); compare( "module.exports = function() {};", - "export default (function () {})" + "export default (function () {});" ); }); it('should throw when it sees module.exports.foo = ...', () => { expect(() => { transform("module.exports.createElement = createElement;"); - }).toThrowError(/Invalid exports: `module.exports` must be in a form of `module.exports = ...;`/); + }).toThrowError(/Invalid exports: `module.exports` must be in the form of `module.exports = ...;`/); }); it('should throw when it sees module.exports on the right hand side', () => { expect(() => { transform('foo = module.exports;'); - }).toThrowError(/Invalid exports: `module.exports` must be in a form of `module.exports = ...;`/); + }).toThrowError(/Invalid exports: `module.exports` must be in the form of `module.exports = ...;`/); expect(() => { transform(`var foo = module.exports;`); - }).toThrowError(/Invalid exports: `module.exports` must be in a form of `module.exports = ...;`/); + }).toThrowError(/Invalid exports: `module.exports` must be in the form of `module.exports = ...;`/); }); it('should throw for non-top level exports', () => { diff --git a/scripts/babel/transform-es6-modulify.js b/scripts/babel/transform-es6-modulify.js index fa3659fa3478b..5d801059a5c6d 100644 --- a/scripts/babel/transform-es6-modulify.js +++ b/scripts/babel/transform-es6-modulify.js @@ -37,7 +37,7 @@ module.exports = function(babel) { if (t.isMemberExpression(path.parent)) { // `var createElement = require('react').createElement;` throw new Error( - 'Invalid require: `require()` must be in a form of `var ... = require(...);`. ' + sourceLocText + 'Invalid require: `require()` must be in the form of `var ... = require(...);`. ' + sourceLocText ); } else if (!t.isVariableDeclarator(path.parent)) { // is not directly in a VariableDeclarator @@ -86,7 +86,7 @@ module.exports = function(babel) { ) { // `module.exports` is on the RHS, or the LHS looks like `module.exports.foo` throw new Error( - 'Invalid exports: `module.exports` must be in a form of `module.exports = ...;`. ' + sourceLocText + 'Invalid exports: `module.exports` must be in the form of `module.exports = ...;`. ' + sourceLocText ); } else if (!t.isProgram(path.scope.block)) { // is not on the top-level diff --git a/scripts/rollup/rollup.config.dev.js b/scripts/rollup/rollup.config.dev.js deleted file mode 100644 index cbec66400a1df..0000000000000 --- a/scripts/rollup/rollup.config.dev.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 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. - */ -'use strict'; - -var babel = require('rollup-plugin-babel'); -var replace = require('rollup-plugin-replace'); -var resolve = require('rollup-plugin-node-resolve'); - -var babelEs6ModulifyPlugin = require('../babel/transform-es6-modulify'); - -module.exports = { - dest: 'build/react.rollup.dev.js', - entry: 'build/modules/ReactUMDEntry.js', - moduleName: 'React', - format: 'umd', - plugins: [ - babel({ - babelrc: false, - plugins: [babelEs6ModulifyPlugin], - }), - replace({ - 'process.env.NODE_ENV': JSON.stringify('development'), - }), - resolve({ - main: true, - }), - ], - sourceMap: false, -}; diff --git a/scripts/rollup/rollup.config.prod.js b/scripts/rollup/rollup.config.prod.js deleted file mode 100644 index 34be1e522821a..0000000000000 --- a/scripts/rollup/rollup.config.prod.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 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. - */ -'use strict'; - -var babel = require('rollup-plugin-babel'); -var replace = require('rollup-plugin-replace'); -var resolve = require('rollup-plugin-node-resolve'); -var uglify = require('rollup-plugin-uglify'); - -var babelEs6ModulifyPlugin = require('../babel/transform-es6-modulify'); - -module.exports = { - dest: 'build/react.rollup.prod.js', - entry: 'build/modules/ReactUMDEntry.js', - moduleName: 'React', - format: 'umd', - plugins: [ - babel({ - babelrc: false, - plugins: [babelEs6ModulifyPlugin], - }), - replace({ - 'process.env.NODE_ENV': JSON.stringify('production'), - }), - resolve({ - main: true, - }), - uglify(), - ], - sourceMap: false, -}; From fb513eec3a708e22837a1ec554778d0d5db01a80 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Tue, 12 Jul 2016 17:59:16 -0700 Subject: [PATCH 08/16] removed simple banner --- grunt/config/rollup.js | 21 +++---------------- grunt/data/header-template-short.txt | 3 --- ...plate-extended.txt => header-template.txt} | 0 grunt/tasks/react-dom.js | 2 +- 4 files changed, 4 insertions(+), 22 deletions(-) delete mode 100644 grunt/data/header-template-short.txt rename grunt/data/{header-template-extended.txt => header-template.txt} (100%) diff --git a/grunt/config/rollup.js b/grunt/config/rollup.js index f7a0e6b89503f..3438fc778ceca 100644 --- a/grunt/config/rollup.js +++ b/grunt/config/rollup.js @@ -16,11 +16,8 @@ var UglifyJS = require('uglify-js'); var babelEs6ModulifyTransform = require('../../scripts/babel/transform-es6-modulify'); -var SIMPLE_TEMPLATE = - grunt.file.read('./grunt/data/header-template-short.txt'); - var LICENSE_TEMPLATE = - grunt.file.read('./grunt/data/header-template-extended.txt'); + grunt.file.read('./grunt/data/header-template.txt'); function minify(src) { return UglifyJS.minify(src, {fromString: true}).code; @@ -38,18 +35,6 @@ function bannerify(src) { ); } -function simpleBannerify(src) { - var version = grunt.config.data.pkg.version; - var packageName = this.data.packageName || this.data.moduleName; - return ( - grunt.template.process( - SIMPLE_TEMPLATE, - {data: {package: packageName, version: version}} - ) + - src - ); -} - function getPlugins(replaceConfig) { return [ rollupBabel({ @@ -65,7 +50,7 @@ function getPlugins(replaceConfig) { var buildConfigs = { basic: { - after: [simpleBannerify], + after: [bannerify], dest: 'build/react.js', entry: 'build/modules/ReactUMDEntry.js', format: 'umd', @@ -81,7 +66,7 @@ var buildConfigs = { plugins: getPlugins({'process.env.NODE_ENV': JSON.stringify('production')}), }, addons: { - after: [simpleBannerify], + after: [bannerify], dest: 'build/react-with-addons.js', entry: 'build/modules/ReactWithAddonsUMDEntry.js', format: 'umd', diff --git a/grunt/data/header-template-short.txt b/grunt/data/header-template-short.txt deleted file mode 100644 index ec08497d13a90..0000000000000 --- a/grunt/data/header-template-short.txt +++ /dev/null @@ -1,3 +0,0 @@ - /** - * <%= package %> v<%= version %> - */ diff --git a/grunt/data/header-template-extended.txt b/grunt/data/header-template.txt similarity index 100% rename from grunt/data/header-template-extended.txt rename to grunt/data/header-template.txt diff --git a/grunt/tasks/react-dom.js b/grunt/tasks/react-dom.js index 77a68d0656ace..999e629a5e9f6 100644 --- a/grunt/tasks/react-dom.js +++ b/grunt/tasks/react-dom.js @@ -4,7 +4,7 @@ var grunt = require('grunt'); var UglifyJS = require('uglify-js'); var LICENSE_TEMPLATE = - grunt.file.read('./grunt/data/header-template-extended.txt'); + grunt.file.read('./grunt/data/header-template.txt'); function build(name, filename) { var srcFile = `vendor/${filename}.js`; From 14bb0ce466f6206166085174a265a06e4d9bcb3f Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Tue, 12 Jul 2016 18:25:29 -0700 Subject: [PATCH 09/16] bumped rollup --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6cf24beba8819..9ba6a54ccc2a4 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "loose-envify": "^1.1.0", "object-assign": "^4.1.0", "platform": "^1.1.0", - "rollup": "^0.33.0", + "rollup": "^0.34.1", "rollup-plugin-babel": "^2.6.1", "rollup-plugin-node-resolve": "^1.7.1", "rollup-plugin-replace": "^1.1.1", From 252209ac11f6e2e5c91dafa8837980720ab21da6 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Tue, 12 Jul 2016 19:13:40 -0700 Subject: [PATCH 10/16] fixed 2 files --- src/renderers/shared/ReactDebugTool.js | 5 ----- src/shared/utils/flattenChildren.js | 22 +++------------------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/renderers/shared/ReactDebugTool.js b/src/renderers/shared/ReactDebugTool.js index af55f09a3975b..c7da57e35a1d5 100644 --- a/src/renderers/shared/ReactDebugTool.js +++ b/src/renderers/shared/ReactDebugTool.js @@ -17,11 +17,6 @@ var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); var ReactHostOperationHistoryDevtool = require('ReactHostOperationHistoryDevtool'); var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool'); -var ReactInvalidSetStateWarningDevTool = require('ReactInvalidSetStateWarningDevTool'); -var ReactHostOperationHistoryDevtool = require('ReactHostOperationHistoryDevtool'); -var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); -var ReactChildrenMutationWarningDevtool = require('ReactChildrenMutationWarningDevtool'); - var performanceNow = require('performanceNow'); var warning = require('warning'); diff --git a/src/shared/utils/flattenChildren.js b/src/shared/utils/flattenChildren.js index e0e1ed870959c..73d84a17ca312 100644 --- a/src/shared/utils/flattenChildren.js +++ b/src/shared/utils/flattenChildren.js @@ -12,25 +12,12 @@ 'use strict'; +var ReactComponentTreeDevtoolDev = require('ReactComponentTreeDevtoolDev'); var KeyEscapeUtils = require('KeyEscapeUtils'); + var traverseAllChildren = require('traverseAllChildren'); var warning = require('warning'); -var ReactComponentTreeDevtool; - -if ( - typeof process !== 'undefined' && - process.env && - process.env.NODE_ENV === 'test' -) { - // Temporary hack. - // Inline requires don't work well with Jest: - // https://github.com/facebook/react/issues/7240 - // Remove the inline requires when we don't need them anymore: - // https://github.com/facebook/react/pull/7178 - ReactComponentTreeDevtool = require('ReactComponentTreeDevtool') -} - /** * @param {function} traverseContext Context passed through traversal. * @param {?ReactComponent} child React child component. @@ -48,16 +35,13 @@ function flattenSingleChildIntoContext( const result = traverseContext; const keyUnique = (result[name] === undefined); if (__DEV__) { - if (!ReactComponentTreeDevtool) { - ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); - } warning( keyUnique, 'flattenChildren(...): Encountered two children with the same key, ' + '`%s`. Child keys must be unique; when two children share a key, only ' + 'the first child will be used.%s', KeyEscapeUtils.unescape(name), - ReactComponentTreeDevtool.getStackAddendumByID(selfDebugID) + ReactComponentTreeDevtoolDev.getStackAddendumByID(selfDebugID) ); } if (keyUnique && child != null) { From 7131b5bf4b32ad4cb0b340bc381c3fc9ed73d170 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Mon, 25 Jul 2016 16:29:57 -0700 Subject: [PATCH 11/16] improved babel transform's error message --- scripts/babel/transform-es6-modulify.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/babel/transform-es6-modulify.js b/scripts/babel/transform-es6-modulify.js index 5d801059a5c6d..2e9ea38d998fc 100644 --- a/scripts/babel/transform-es6-modulify.js +++ b/scripts/babel/transform-es6-modulify.js @@ -8,6 +8,14 @@ */ 'use strict'; + +/* + * This Babel transform should _ONLY_ be used with Rollup. + * It transforms our CommonJS require/export statements to ES6 imports/exports + * so that we can use Rollup to bundle our modules to UMD. + * + * NOTE It requires all require/export statements to be on the top-level. + */ var basename = require('path').basename; function getFileLoc(path, file) { @@ -18,7 +26,7 @@ function getFileLoc(path, file) { var fileName = file.file.opts.filename; var moduleName = basename(fileName); return ( - 'Check line ' + startLinePos + ' at `' + fileName + + 'Check line ' + startLinePos + ' at `/build/modules/' + fileName + '` and the original `' + moduleName + '` module under `/src`.' ); } From 74f339a56c484ea7ef9dda7b51ddcd1f4dc731d5 Mon Sep 17 00:00:00 2001 From: Keyan Zhang Date: Mon, 25 Jul 2016 16:34:06 -0700 Subject: [PATCH 12/16] big refactoring. - move implementation of dev-only modules under a __DEV__ block. this ensures good DCE result for webpack/browserify users and FB's packager. - an explicit 'Dev' postfix is added to their module names modules renamed: - ReactElementValidator.js -> ReactElementValidatorDev.js - ReactComponentTreeDevtool.js -> ReactComponentTreeDevtoolDev.js - validateDOMNesting.js -> validateDOMNestingDev.js - ReactDOMDebugTool.js -> ReactDOMDebugToolDev.js - ReactDOMNullInputValuePropDevtool.js -> ReactDOMNullInputValuePropDevtoolDev.js - ReactDOMUnknownPropertyDevtool.js -> ReactDOMUnknownPropertyDevtoolDev.js - ReactDebugTool.js -> ReactDebugToolDev.js - ReactInstrumentation.js -> ReactInstrumentationDev.js - ReactPerf.js -> ReactPerfDev.js - ReactChildrenMutationWarningDevtool.js -> ReactChildrenMutationWarningDevtoolDev.js - ReactHostOperationHistoryDevtool.js -> ReactHostOperationHistoryDevtoolDev.js - ReactInvalidSetStateWarningDevTool.js -> ReactInvalidSetStateWarningDevToolDev.js - canDefineProperty.js -> canDefinePropertyDev.js --- src/addons/ReactWithAddons.js | 4 +- src/isomorphic/React.js | 8 +- .../classic/element/ReactDOMFactories.js | 4 +- .../classic/element/ReactElement.js | 4 +- .../classic/element/ReactElementValidator.js | 269 ----------- .../element/ReactElementValidatorDev.js | 273 +++++++++++ ...st.js => ReactElementValidatorDev-test.js} | 2 +- .../devtools/ReactComponentTreeDevtool.js | 262 ---------- .../devtools/ReactComponentTreeDevtoolDev.js | 266 ++++++++++ src/isomorphic/modern/class/ReactComponent.js | 4 +- src/renderers/dom/client/ReactMount.js | 10 +- .../dom/client/ReactReconcileTransaction.js | 6 +- ...-test.js => validateDOMNestingDev-test.js} | 10 +- .../dom/client/utils/DOMChildrenOperations.js | 18 +- ...DOMNesting.js => validateDOMNestingDev.js} | 12 +- .../dom/client/wrappers/LinkedValueUtils.js | 48 +- .../dom/server/ReactServerRendering.js | 4 +- .../server/ReactServerRenderingTransaction.js | 6 +- .../dom/shared/CSSPropertyOperations.js | 4 +- .../dom/shared/DOMPropertyOperations.js | 10 +- src/renderers/dom/shared/ReactDOMComponent.js | 34 +- .../dom/shared/ReactDOMContainerInfo.js | 4 +- src/renderers/dom/shared/ReactDOMDebugTool.js | 74 --- .../dom/shared/ReactDOMDebugToolDev.js | 76 +++ .../dom/shared/ReactDOMInstrumentation.js | 4 +- .../dom/shared/ReactDOMTextComponent.js | 10 +- .../__tests__/ReactDOMComponent-test.js | 2 +- .../__tests__/ReactDOMDebugTool-test.js | 32 +- ...st.js => ReactDOMTextComponentDev-test.js} | 0 .../ReactDOMNullInputValuePropDevtool.js | 50 -- .../ReactDOMNullInputValuePropDevtoolDev.js | 54 +++ ...s => ReactDOMUnknownPropertyDevtoolDev.js} | 114 ++--- src/renderers/native/ReactNativeMount.js | 8 +- .../native/ReactNativeReconcileTransaction.js | 6 +- .../native/ReactNativeTextComponent.js | 6 +- src/renderers/shared/ReactDebugTool.js | 338 ------------- src/renderers/shared/ReactDebugToolDev.js | 332 +++++++++++++ ...entation.js => ReactInstrumentationDev.js} | 6 +- src/renderers/shared/ReactPerf.js | 450 ----------------- src/renderers/shared/ReactPerfDev.js | 456 ++++++++++++++++++ ...Tool-test.js => ReactDebugToolDev-test.js} | 42 +- ...ReactPerf-test.js => ReactPerfDev-test.js} | 112 ++--- .../ReactChildrenMutationWarningDevtool.js | 66 --- .../ReactChildrenMutationWarningDevtoolDev.js | 70 +++ .../ReactHostOperationHistoryDevtool.js | 39 -- .../ReactHostOperationHistoryDevtoolDev.js | 43 ++ ... ReactInvalidSetStateWarningDevToolDev.js} | 30 +- ...s => ReactComponentTreeDevtoolDev-test.js} | 44 +- ...actComponentTreeDevtoolDev-test.native.js} | 30 +- ...actHostOperationHistoryDevtoolDev-test.js} | 76 +-- .../reconciler/ReactCompositeComponent.js | 60 +-- .../stack/reconciler/ReactMultiChild.js | 6 +- .../stack/reconciler/ReactReconciler.js | 32 +- .../stack/reconciler/ReactUpdateQueue.js | 4 +- .../reconciler/instantiateReactComponent.js | 6 +- src/renderers/testing/ReactTestMount.js | 4 +- ...ineProperty.js => canDefinePropertyDev.js} | 8 +- src/test/ReactComponentTreeTestUtils.js | 26 +- src/test/ReactTestUtils.js | 10 +- 59 files changed, 2007 insertions(+), 1981 deletions(-) delete mode 100644 src/isomorphic/classic/element/ReactElementValidator.js create mode 100644 src/isomorphic/classic/element/ReactElementValidatorDev.js rename src/isomorphic/classic/element/__tests__/{ReactElementValidator-test.js => ReactElementValidatorDev-test.js} (99%) delete mode 100644 src/isomorphic/devtools/ReactComponentTreeDevtool.js create mode 100644 src/isomorphic/devtools/ReactComponentTreeDevtoolDev.js rename src/renderers/dom/client/__tests__/{validateDOMNesting-test.js => validateDOMNestingDev-test.js} (91%) rename src/renderers/dom/client/{validateDOMNesting.js => validateDOMNestingDev.js} (97%) delete mode 100644 src/renderers/dom/shared/ReactDOMDebugTool.js create mode 100644 src/renderers/dom/shared/ReactDOMDebugToolDev.js rename src/renderers/dom/shared/__tests__/{ReactDOMTextComponent-test.js => ReactDOMTextComponentDev-test.js} (100%) delete mode 100644 src/renderers/dom/shared/devtools/ReactDOMNullInputValuePropDevtool.js create mode 100644 src/renderers/dom/shared/devtools/ReactDOMNullInputValuePropDevtoolDev.js rename src/renderers/dom/shared/devtools/{ReactDOMUnknownPropertyDevtool.js => ReactDOMUnknownPropertyDevtoolDev.js} (58%) delete mode 100644 src/renderers/shared/ReactDebugTool.js create mode 100644 src/renderers/shared/ReactDebugToolDev.js rename src/renderers/shared/{ReactInstrumentation.js => ReactInstrumentationDev.js} (69%) delete mode 100644 src/renderers/shared/ReactPerf.js create mode 100644 src/renderers/shared/ReactPerfDev.js rename src/renderers/shared/__tests__/{ReactDebugTool-test.js => ReactDebugToolDev-test.js} (65%) rename src/renderers/shared/__tests__/{ReactPerf-test.js => ReactPerfDev-test.js} (83%) delete mode 100644 src/renderers/shared/devtools/ReactChildrenMutationWarningDevtool.js create mode 100644 src/renderers/shared/devtools/ReactChildrenMutationWarningDevtoolDev.js delete mode 100644 src/renderers/shared/devtools/ReactHostOperationHistoryDevtool.js create mode 100644 src/renderers/shared/devtools/ReactHostOperationHistoryDevtoolDev.js rename src/renderers/shared/devtools/{ReactInvalidSetStateWarningDevTool.js => ReactInvalidSetStateWarningDevToolDev.js} (57%) rename src/renderers/shared/devtools/__tests__/{ReactComponentTreeDevtool-test.js => ReactComponentTreeDevtoolDev-test.js} (96%) rename src/renderers/shared/devtools/__tests__/{ReactComponentTreeDevtool-test.native.js => ReactComponentTreeDevtoolDev-test.native.js} (97%) rename src/renderers/shared/devtools/__tests__/{ReactHostOperationHistoryDevtool-test.js => ReactHostOperationHistoryDevtoolDev-test.js} (89%) rename src/shared/utils/{canDefineProperty.js => canDefinePropertyDev.js} (76%) diff --git a/src/addons/ReactWithAddons.js b/src/addons/ReactWithAddons.js index db8280a886404..155772e608132 100644 --- a/src/addons/ReactWithAddons.js +++ b/src/addons/ReactWithAddons.js @@ -17,7 +17,7 @@ var ReactComponentWithPureRenderMixin = require('ReactComponentWithPureRenderMixin'); var ReactCSSTransitionGroup = require('ReactCSSTransitionGroup'); var ReactFragment = require('ReactFragment'); -var ReactPerf = require('ReactPerf'); +var ReactPerfDev = require('ReactPerfDev'); var ReactTestUtils = require('ReactTestUtils'); var ReactTransitionGroup = require('ReactTransitionGroup'); @@ -36,7 +36,7 @@ React.addons = { }; if (__DEV__) { - React.addons.Perf = ReactPerf; + React.addons.Perf = ReactPerfDev; React.addons.TestUtils = ReactTestUtils; } diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index d9c878892261d..0223fa2554d15 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -17,7 +17,7 @@ var ReactPureComponent = require('ReactPureComponent'); var ReactClass = require('ReactClass'); var ReactDOMFactories = require('ReactDOMFactories'); var ReactElement = require('ReactElement'); -var ReactElementValidator = require('ReactElementValidator'); +var ReactElementValidatorDev = require('ReactElementValidatorDev'); var ReactPropTypes = require('ReactPropTypes'); var ReactVersion = require('ReactVersion'); @@ -29,9 +29,9 @@ var createFactory = ReactElement.createFactory; var cloneElement = ReactElement.cloneElement; if (__DEV__) { - createElement = ReactElementValidator.createElement; - createFactory = ReactElementValidator.createFactory; - cloneElement = ReactElementValidator.cloneElement; + createElement = ReactElementValidatorDev.createElement; + createFactory = ReactElementValidatorDev.createFactory; + cloneElement = ReactElementValidatorDev.cloneElement; } var __spread = Object.assign; diff --git a/src/isomorphic/classic/element/ReactDOMFactories.js b/src/isomorphic/classic/element/ReactDOMFactories.js index 422aaae77a015..c7a6cc1fb0f89 100644 --- a/src/isomorphic/classic/element/ReactDOMFactories.js +++ b/src/isomorphic/classic/element/ReactDOMFactories.js @@ -12,7 +12,7 @@ 'use strict'; var ReactElement = require('ReactElement'); -var ReactElementValidator = require('ReactElementValidator'); +var ReactElementValidatorDev = require('ReactElementValidatorDev'); var mapObject = require('mapObject'); @@ -24,7 +24,7 @@ var mapObject = require('mapObject'); */ function createDOMFactory(tag) { if (__DEV__) { - return ReactElementValidator.createFactory(tag); + return ReactElementValidatorDev.createFactory(tag); } return ReactElement.createFactory(tag); } diff --git a/src/isomorphic/classic/element/ReactElement.js b/src/isomorphic/classic/element/ReactElement.js index 710bcaa532546..bdaba78d7e2c9 100644 --- a/src/isomorphic/classic/element/ReactElement.js +++ b/src/isomorphic/classic/element/ReactElement.js @@ -14,7 +14,7 @@ var ReactCurrentOwner = require('ReactCurrentOwner'); var warning = require('warning'); -var canDefineProperty = require('canDefineProperty'); +var canDefinePropertyDev = require('canDefinePropertyDev'); var hasOwnProperty = Object.prototype.hasOwnProperty; // The Symbol used to tag the ReactElement type. If there is no native Symbol @@ -103,7 +103,7 @@ var ReactElement = function(type, key, ref, self, source, owner, props) { // the validation flag non-enumerable (where possible, which should // include every environment we run tests in), so the test framework // ignores it. - if (canDefineProperty) { + if (canDefinePropertyDev) { Object.defineProperty(element._store, 'validated', { configurable: false, enumerable: false, diff --git a/src/isomorphic/classic/element/ReactElementValidator.js b/src/isomorphic/classic/element/ReactElementValidator.js deleted file mode 100644 index 4d4121f9810c3..0000000000000 --- a/src/isomorphic/classic/element/ReactElementValidator.js +++ /dev/null @@ -1,269 +0,0 @@ -/** - * Copyright 2014-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 ReactElementValidator - */ - -/** - * ReactElementValidator provides a wrapper around a element factory - * which validates the props passed to the element. This is intended to be - * used only in DEV and could be replaced by a static type checker for languages - * that support it. - */ - -'use strict'; - -var ReactCurrentOwner = require('ReactCurrentOwner'); -var ReactComponentTreeDevtool = require('ReactComponentTreeDevtool'); -var ReactElement = require('ReactElement'); -var ReactPropTypeLocations = require('ReactPropTypeLocations'); - -var checkReactTypeSpec = require('checkReactTypeSpec'); - -var canDefineProperty = require('canDefineProperty'); -var getIteratorFn = require('getIteratorFn'); -var warning = require('warning'); - -function getDeclarationErrorAddendum() { - if (ReactCurrentOwner.current) { - var name = ReactCurrentOwner.current.getName(); - if (name) { - return ' Check the render method of `' + name + '`.'; - } - } - return ''; -} - -/** - * Warn if there's no key explicitly set on dynamic arrays of children or - * object keys are not valid. This allows us to keep track of children between - * updates. - */ -var ownerHasKeyUseWarning = {}; - -function getCurrentComponentErrorInfo(parentType) { - var info = getDeclarationErrorAddendum(); - - if (!info) { - var parentName = typeof parentType === 'string' ? - parentType : parentType.displayName || parentType.name; - if (parentName) { - info = ` Check the top-level render call using <${parentName}>.`; - } - } - return info; -} - -/** - * Warn if the element doesn't have an explicit key assigned to it. - * This element is in an array. The array could grow and shrink or be - * reordered. All children that haven't already been validated are required to - * have a "key" property assigned to it. Error statuses are cached so a warning - * will only be shown once. - * - * @internal - * @param {ReactElement} element Element that requires a key. - * @param {*} parentType element's parent's type. - */ -function validateExplicitKey(element, parentType) { - if (!element._store || element._store.validated || element.key != null) { - return; - } - element._store.validated = true; - - var memoizer = ownerHasKeyUseWarning.uniqueKey || ( - ownerHasKeyUseWarning.uniqueKey = {} - ); - - var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); - if (memoizer[currentComponentErrorInfo]) { - return; - } - memoizer[currentComponentErrorInfo] = true; - - // Usually the current owner is the offender, but if it accepts children as a - // property, it may be the creator of the child that's responsible for - // assigning it a key. - var childOwner = ''; - if (element && - element._owner && - element._owner !== ReactCurrentOwner.current) { - // Give the component that originally created this child. - childOwner = - ` It was passed a child from ${element._owner.getName()}.`; - } - - warning( - false, - 'Each child in an array or iterator should have a unique "key" prop.' + - '%s%s See https://fb.me/react-warning-keys for more information.%s', - currentComponentErrorInfo, - childOwner, - ReactComponentTreeDevtool.getCurrentStackAddendum(element) - ); -} - -/** - * Ensure that every element either is passed in a static location, in an - * array with an explicit keys property defined, or in an object literal - * with valid key property. - * - * @internal - * @param {ReactNode} node Statically passed child of any type. - * @param {*} parentType node's parent's type. - */ -function validateChildKeys(node, parentType) { - if (typeof node !== 'object') { - return; - } - if (Array.isArray(node)) { - for (var i = 0; i < node.length; i++) { - var child = node[i]; - if (ReactElement.isValidElement(child)) { - validateExplicitKey(child, parentType); - } - } - } else if (ReactElement.isValidElement(node)) { - // This element was passed in a valid location. - if (node._store) { - node._store.validated = true; - } - } else if (node) { - var iteratorFn = getIteratorFn(node); - // Entry iterators provide implicit keys. - if (iteratorFn) { - if (iteratorFn !== node.entries) { - var iterator = iteratorFn.call(node); - var step; - while (!(step = iterator.next()).done) { - if (ReactElement.isValidElement(step.value)) { - validateExplicitKey(step.value, parentType); - } - } - } - } - } -} - -/** - * Given an element, validate that its props follow the propTypes definition, - * provided by the type. - * - * @param {ReactElement} element - */ -function validatePropTypes(element) { - var componentClass = element.type; - if (typeof componentClass !== 'function') { - return; - } - var name = componentClass.displayName || componentClass.name; - if (componentClass.propTypes) { - checkReactTypeSpec( - componentClass.propTypes, - element.props, - ReactPropTypeLocations.prop, - name, - element, - null - ); - } - if (typeof componentClass.getDefaultProps === 'function') { - warning( - componentClass.getDefaultProps.isReactClassApproved, - 'getDefaultProps is only used on classic React.createClass ' + - 'definitions. Use a static property named `defaultProps` instead.' - ); - } -} - -var ReactElementValidator = { - - createElement: function(type, props, children) { - var validType = typeof type === 'string' || typeof type === 'function' || - (type !== null && typeof type === 'object'); - // We warn in this case but don't throw. We expect the element creation to - // succeed and there will likely be errors in render. - warning( - validType, - 'React.createElement: type should not be null, undefined, boolean, or ' + - 'number. It should be a string (for DOM elements) or a ReactClass ' + - '(for composite components).%s', - getDeclarationErrorAddendum() - ); - - var element = ReactElement.createElement.apply(this, arguments); - - // The result can be nullish if a mock or a custom function is used. - // TODO: Drop this when these are no longer allowed as the type argument. - if (element == null) { - return element; - } - - // Skip key warning if the type isn't valid since our key validation logic - // doesn't expect a non-string/function type and can throw confusing errors. - // We don't want exception behavior to differ between dev and prod. - // (Rendering will throw with a helpful message and as soon as the type is - // fixed, the key warnings will appear.) - if (validType) { - for (var i = 2; i < arguments.length; i++) { - validateChildKeys(arguments[i], type); - } - } - - validatePropTypes(element); - - return element; - }, - - createFactory: function(type) { - var validatedFactory = ReactElementValidator.createElement.bind( - null, - type - ); - // Legacy hook TODO: Warn if this is accessed - validatedFactory.type = type; - - if (__DEV__) { - if (canDefineProperty) { - Object.defineProperty( - validatedFactory, - 'type', - { - enumerable: false, - get: function() { - warning( - false, - 'Factory.type is deprecated. Access the class directly ' + - 'before passing it to createFactory.' - ); - Object.defineProperty(this, 'type', { - value: type, - }); - return type; - }, - } - ); - } - } - - - return validatedFactory; - }, - - cloneElement: function(element, props, children) { - var newElement = ReactElement.cloneElement.apply(this, arguments); - for (var i = 2; i < arguments.length; i++) { - validateChildKeys(arguments[i], newElement.type); - } - validatePropTypes(newElement); - return newElement; - }, - -}; - -module.exports = ReactElementValidator; diff --git a/src/isomorphic/classic/element/ReactElementValidatorDev.js b/src/isomorphic/classic/element/ReactElementValidatorDev.js new file mode 100644 index 0000000000000..3b0289fb3d106 --- /dev/null +++ b/src/isomorphic/classic/element/ReactElementValidatorDev.js @@ -0,0 +1,273 @@ +/** + * Copyright 2014-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 ReactElementValidatorDev + */ + +/** + * ReactElementValidator provides a wrapper around a element factory + * which validates the props passed to the element. This is intended to be + * used only in DEV and could be replaced by a static type checker for languages + * that support it. + */ + +'use strict'; + +var ReactCurrentOwner = require('ReactCurrentOwner'); +var ReactComponentTreeDevtoolDev = require('ReactComponentTreeDevtoolDev'); +var ReactElement = require('ReactElement'); +var ReactPropTypeLocations = require('ReactPropTypeLocations'); + +var checkReactTypeSpec = require('checkReactTypeSpec'); + +var canDefinePropertyDev = require('canDefinePropertyDev'); +var getIteratorFn = require('getIteratorFn'); +var warning = require('warning'); + +var ReactElementValidatorDev = {}; + +if (__DEV__) { + var getDeclarationErrorAddendum = function() { + if (ReactCurrentOwner.current) { + var name = ReactCurrentOwner.current.getName(); + if (name) { + return ' Check the render method of `' + name + '`.'; + } + } + return ''; + }; + + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + var ownerHasKeyUseWarning = {}; + + var getCurrentComponentErrorInfo = function(parentType) { + var info = getDeclarationErrorAddendum(); + + if (!info) { + var parentName = typeof parentType === 'string' ? + parentType : parentType.displayName || parentType.name; + if (parentName) { + info = ` Check the top-level render call using <${parentName}>.`; + } + } + return info; + }; + + /** + * Warn if the element doesn't have an explicit key assigned to it. + * This element is in an array. The array could grow and shrink or be + * reordered. All children that haven't already been validated are required to + * have a "key" property assigned to it. Error statuses are cached so a warning + * will only be shown once. + * + * @internal + * @param {ReactElement} element Element that requires a key. + * @param {*} parentType element's parent's type. + */ + var validateExplicitKey = function(element, parentType) { + if (!element._store || element._store.validated || element.key != null) { + return; + } + element._store.validated = true; + + var memoizer = ownerHasKeyUseWarning.uniqueKey || ( + ownerHasKeyUseWarning.uniqueKey = {} + ); + + var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); + if (memoizer[currentComponentErrorInfo]) { + return; + } + memoizer[currentComponentErrorInfo] = true; + + // Usually the current owner is the offender, but if it accepts children as a + // property, it may be the creator of the child that's responsible for + // assigning it a key. + var childOwner = ''; + if (element && + element._owner && + element._owner !== ReactCurrentOwner.current) { + // Give the component that originally created this child. + childOwner = + ` It was passed a child from ${element._owner.getName()}.`; + } + + warning( + false, + 'Each child in an array or iterator should have a unique "key" prop.' + + '%s%s See https://fb.me/react-warning-keys for more information.%s', + currentComponentErrorInfo, + childOwner, + ReactComponentTreeDevtoolDev.getCurrentStackAddendum(element) + ); + }; + + /** + * Ensure that every element either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. + * + * @internal + * @param {ReactNode} node Statically passed child of any type. + * @param {*} parentType node's parent's type. + */ + var validateChildKeys = function(node, parentType) { + if (typeof node !== 'object') { + return; + } + if (Array.isArray(node)) { + for (var i = 0; i < node.length; i++) { + var child = node[i]; + if (ReactElement.isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (ReactElement.isValidElement(node)) { + // This element was passed in a valid location. + if (node._store) { + node._store.validated = true; + } + } else if (node) { + var iteratorFn = getIteratorFn(node); + // Entry iterators provide implicit keys. + if (iteratorFn) { + if (iteratorFn !== node.entries) { + var iterator = iteratorFn.call(node); + var step; + while (!(step = iterator.next()).done) { + if (ReactElement.isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); + } + } + } + } + } + }; + + /** + * Given an element, validate that its props follow the propTypes definition, + * provided by the type. + * + * @param {ReactElement} element + */ + var validatePropTypes = function(element) { + var componentClass = element.type; + if (typeof componentClass !== 'function') { + return; + } + var name = componentClass.displayName || componentClass.name; + if (componentClass.propTypes) { + checkReactTypeSpec( + componentClass.propTypes, + element.props, + ReactPropTypeLocations.prop, + name, + element, + null + ); + } + if (typeof componentClass.getDefaultProps === 'function') { + warning( + componentClass.getDefaultProps.isReactClassApproved, + 'getDefaultProps is only used on classic React.createClass ' + + 'definitions. Use a static property named `defaultProps` instead.' + ); + } + }; + + ReactElementValidatorDev = { + + createElement: function(type, props, children) { + var validType = typeof type === 'string' || typeof type === 'function' || + (type !== null && typeof type === 'object'); + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + warning( + validType, + 'React.createElement: type should not be null, undefined, boolean, or ' + + 'number. It should be a string (for DOM elements) or a ReactClass ' + + '(for composite components).%s', + getDeclarationErrorAddendum() + ); + + var element = ReactElement.createElement.apply(this, arguments); + + // The result can be nullish if a mock or a custom function is used. + // TODO: Drop this when these are no longer allowed as the type argument. + if (element == null) { + return element; + } + + // Skip key warning if the type isn't valid since our key validation logic + // doesn't expect a non-string/function type and can throw confusing errors. + // We don't want exception behavior to differ between dev and prod. + // (Rendering will throw with a helpful message and as soon as the type is + // fixed, the key warnings will appear.) + if (validType) { + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], type); + } + } + + validatePropTypes(element); + + return element; + }, + + createFactory: function(type) { + var validatedFactory = ReactElementValidatorDev.createElement.bind( + null, + type + ); + // Legacy hook TODO: Warn if this is accessed + validatedFactory.type = type; + + if (__DEV__) { + if (canDefinePropertyDev) { + Object.defineProperty( + validatedFactory, + 'type', + { + enumerable: false, + get: function() { + warning( + false, + 'Factory.type is deprecated. Access the class directly ' + + 'before passing it to createFactory.' + ); + Object.defineProperty(this, 'type', { + value: type, + }); + return type; + }, + } + ); + } + } + + + return validatedFactory; + }, + + cloneElement: function(element, props, children) { + var newElement = ReactElement.cloneElement.apply(this, arguments); + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], newElement.type); + } + validatePropTypes(newElement); + return newElement; + }, + + }; +} + +module.exports = ReactElementValidatorDev; diff --git a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js b/src/isomorphic/classic/element/__tests__/ReactElementValidatorDev-test.js similarity index 99% rename from src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js rename to src/isomorphic/classic/element/__tests__/ReactElementValidatorDev-test.js index fe7acf3e60930..c5a8ce09b0de7 100644 --- a/src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js +++ b/src/isomorphic/classic/element/__tests__/ReactElementValidatorDev-test.js @@ -18,7 +18,7 @@ var React; var ReactDOM; var ReactTestUtils; -describe('ReactElementValidator', function() { +describe('ReactElementValidatorDev', function() { function normalizeCodeLocInfo(str) { return str.replace(/\(at .+?:\d+\)/g, '(at **)'); } diff --git a/src/isomorphic/devtools/ReactComponentTreeDevtool.js b/src/isomorphic/devtools/ReactComponentTreeDevtool.js deleted file mode 100644 index 622bad984749f..0000000000000 --- a/src/isomorphic/devtools/ReactComponentTreeDevtool.js +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright 2016-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 ReactComponentTreeDevtool - */ - -'use strict'; - -var ReactCurrentOwner = require('ReactCurrentOwner'); - -var invariant = require('invariant'); -var warning = require('warning'); - -var tree = {}; -var unmountedIDs = {}; -var rootIDs = {}; - -function updateTree(id, update) { - if (!tree[id]) { - tree[id] = { - element: null, - parentID: null, - ownerID: null, - text: null, - childIDs: [], - displayName: 'Unknown', - isMounted: false, - updateCount: 0, - }; - } - update(tree[id]); -} - -function purgeDeep(id) { - var item = tree[id]; - if (item) { - var {childIDs} = item; - delete tree[id]; - childIDs.forEach(purgeDeep); - } -} - -function describeComponentFrame(name, source, ownerName) { - return '\n in ' + name + ( - source ? - ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + - source.lineNumber + ')' : - ownerName ? - ' (created by ' + ownerName + ')' : - '' - ); -} - -function describeID(id) { - var name = ReactComponentTreeDevtool.getDisplayName(id); - var element = ReactComponentTreeDevtool.getElement(id); - var ownerID = ReactComponentTreeDevtool.getOwnerID(id); - var ownerName; - if (ownerID) { - ownerName = ReactComponentTreeDevtool.getDisplayName(ownerID); - } - warning( - element, - 'ReactComponentTreeDevtool: Missing React element for debugID %s when ' + - 'building stack', - id - ); - return describeComponentFrame(name, element && element._source, ownerName); -} - -var ReactComponentTreeDevtool = { - onSetDisplayName(id, displayName) { - updateTree(id, item => item.displayName = displayName); - }, - - onSetChildren(id, nextChildIDs) { - updateTree(id, item => { - item.childIDs = nextChildIDs; - - nextChildIDs.forEach(nextChildID => { - var nextChild = tree[nextChildID]; - invariant( - nextChild, - 'Expected devtool events to fire for the child ' + - 'before its parent includes it in onSetChildren().' - ); - invariant( - nextChild.displayName != null, - 'Expected onSetDisplayName() to fire for the child ' + - 'before its parent includes it in onSetChildren().' - ); - invariant( - nextChild.childIDs != null || nextChild.text != null, - 'Expected onSetChildren() or onSetText() to fire for the child ' + - 'before its parent includes it in onSetChildren().' - ); - invariant( - nextChild.isMounted, - 'Expected onMountComponent() to fire for the child ' + - 'before its parent includes it in onSetChildren().' - ); - if (nextChild.parentID == null) { - nextChild.parentID = id; - // TODO: This shouldn't be necessary but mounting a new root during in - // componentWillMount currently causes not-yet-mounted components to - // be purged from our tree data so their parent ID is missing. - } - invariant( - nextChild.parentID === id, - 'Expected onSetParent() and onSetChildren() to be consistent (%s ' + - 'has parents %s and %s).', - nextChildID, - nextChild.parentID, - id - ); - }); - }); - }, - - onSetOwner(id, ownerID) { - updateTree(id, item => item.ownerID = ownerID); - }, - - onSetParent(id, parentID) { - updateTree(id, item => item.parentID = parentID); - }, - - onSetText(id, text) { - updateTree(id, item => item.text = text); - }, - - onBeforeMountComponent(id, element) { - updateTree(id, item => item.element = element); - }, - - onBeforeUpdateComponent(id, element) { - updateTree(id, item => item.element = element); - }, - - onMountComponent(id) { - updateTree(id, item => item.isMounted = true); - }, - - onMountRootComponent(id) { - rootIDs[id] = true; - }, - - onUpdateComponent(id) { - updateTree(id, item => item.updateCount++); - }, - - onUnmountComponent(id) { - updateTree(id, item => item.isMounted = false); - unmountedIDs[id] = true; - delete rootIDs[id]; - }, - - purgeUnmountedComponents() { - if (ReactComponentTreeDevtool._preventPurging) { - // Should only be used for testing. - return; - } - - for (var id in unmountedIDs) { - purgeDeep(id); - } - unmountedIDs = {}; - }, - - isMounted(id) { - var item = tree[id]; - return item ? item.isMounted : false; - }, - - getCurrentStackAddendum(topElement) { - var info = ''; - if (topElement) { - var type = topElement.type; - var name = typeof type === 'function' ? - type.displayName || type.name : - type; - var owner = topElement._owner; - info += describeComponentFrame( - name || 'Unknown', - topElement._source, - owner && owner.getName() - ); - } - - var currentOwner = ReactCurrentOwner.current; - var id = currentOwner && currentOwner._debugID; - - info += ReactComponentTreeDevtool.getStackAddendumByID(id); - return info; - }, - - getStackAddendumByID(id) { - var info = ''; - while (id) { - info += describeID(id); - id = ReactComponentTreeDevtool.getParentID(id); - } - return info; - }, - - getChildIDs(id) { - var item = tree[id]; - return item ? item.childIDs : []; - }, - - getDisplayName(id) { - var item = tree[id]; - return item ? item.displayName : 'Unknown'; - }, - - getElement(id) { - var item = tree[id]; - return item ? item.element : null; - }, - - getOwnerID(id) { - var item = tree[id]; - return item ? item.ownerID : null; - }, - - getParentID(id) { - var item = tree[id]; - return item ? item.parentID : null; - }, - - getSource(id) { - var item = tree[id]; - var element = item ? item.element : null; - var source = element != null ? element._source : null; - return source; - }, - - getText(id) { - var item = tree[id]; - return item ? item.text : null; - }, - - getUpdateCount(id) { - var item = tree[id]; - return item ? item.updateCount : 0; - }, - - getRootIDs() { - return Object.keys(rootIDs); - }, - - getRegisteredIDs() { - return Object.keys(tree); - }, -}; - -module.exports = ReactComponentTreeDevtool; diff --git a/src/isomorphic/devtools/ReactComponentTreeDevtoolDev.js b/src/isomorphic/devtools/ReactComponentTreeDevtoolDev.js new file mode 100644 index 0000000000000..0fa62a0ddd6aa --- /dev/null +++ b/src/isomorphic/devtools/ReactComponentTreeDevtoolDev.js @@ -0,0 +1,266 @@ +/** + * Copyright 2016-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 ReactComponentTreeDevtoolDev + */ + +'use strict'; + +var ReactCurrentOwner = require('ReactCurrentOwner'); + +var invariant = require('invariant'); +var warning = require('warning'); + +var ReactComponentTreeDevtoolDev = {}; + +if (__DEV__) { + var tree = {}; + var unmountedIDs = {}; + var rootIDs = {}; + + var updateTree = function(id, update) { + if (!tree[id]) { + tree[id] = { + element: null, + parentID: null, + ownerID: null, + text: null, + childIDs: [], + displayName: 'Unknown', + isMounted: false, + updateCount: 0, + }; + } + update(tree[id]); + }; + + var purgeDeep = function(id) { + var item = tree[id]; + if (item) { + var {childIDs} = item; + delete tree[id]; + childIDs.forEach(purgeDeep); + } + }; + + var describeComponentFrame = function(name, source, ownerName) { + return '\n in ' + name + ( + source ? + ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + + source.lineNumber + ')' : + ownerName ? + ' (created by ' + ownerName + ')' : + '' + ); + }; + + var describeID = function(id) { + var name = ReactComponentTreeDevtoolDev.getDisplayName(id); + var element = ReactComponentTreeDevtoolDev.getElement(id); + var ownerID = ReactComponentTreeDevtoolDev.getOwnerID(id); + var ownerName; + if (ownerID) { + ownerName = ReactComponentTreeDevtoolDev.getDisplayName(ownerID); + } + warning( + element, + 'ReactComponentTreeDevtool: Missing React element for debugID %s when ' + + 'building stack', + id + ); + return describeComponentFrame(name, element && element._source, ownerName); + }; + + ReactComponentTreeDevtoolDev = { + onSetDisplayName(id, displayName) { + updateTree(id, item => item.displayName = displayName); + }, + + onSetChildren(id, nextChildIDs) { + updateTree(id, item => { + item.childIDs = nextChildIDs; + + nextChildIDs.forEach(nextChildID => { + var nextChild = tree[nextChildID]; + invariant( + nextChild, + 'Expected devtool events to fire for the child ' + + 'before its parent includes it in onSetChildren().' + ); + invariant( + nextChild.displayName != null, + 'Expected onSetDisplayName() to fire for the child ' + + 'before its parent includes it in onSetChildren().' + ); + invariant( + nextChild.childIDs != null || nextChild.text != null, + 'Expected onSetChildren() or onSetText() to fire for the child ' + + 'before its parent includes it in onSetChildren().' + ); + invariant( + nextChild.isMounted, + 'Expected onMountComponent() to fire for the child ' + + 'before its parent includes it in onSetChildren().' + ); + if (nextChild.parentID == null) { + nextChild.parentID = id; + // TODO: This shouldn't be necessary but mounting a new root during in + // componentWillMount currently causes not-yet-mounted components to + // be purged from our tree data so their parent ID is missing. + } + invariant( + nextChild.parentID === id, + 'Expected onSetParent() and onSetChildren() to be consistent (%s ' + + 'has parents %s and %s).', + nextChildID, + nextChild.parentID, + id + ); + }); + }); + }, + + onSetOwner(id, ownerID) { + updateTree(id, item => item.ownerID = ownerID); + }, + + onSetParent(id, parentID) { + updateTree(id, item => item.parentID = parentID); + }, + + onSetText(id, text) { + updateTree(id, item => item.text = text); + }, + + onBeforeMountComponent(id, element) { + updateTree(id, item => item.element = element); + }, + + onBeforeUpdateComponent(id, element) { + updateTree(id, item => item.element = element); + }, + + onMountComponent(id) { + updateTree(id, item => item.isMounted = true); + }, + + onMountRootComponent(id) { + rootIDs[id] = true; + }, + + onUpdateComponent(id) { + updateTree(id, item => item.updateCount++); + }, + + onUnmountComponent(id) { + updateTree(id, item => item.isMounted = false); + unmountedIDs[id] = true; + delete rootIDs[id]; + }, + + purgeUnmountedComponents() { + if (ReactComponentTreeDevtoolDev._preventPurging) { + // Should only be used for testing. + return; + } + + for (var id in unmountedIDs) { + purgeDeep(id); + } + unmountedIDs = {}; + }, + + isMounted(id) { + var item = tree[id]; + return item ? item.isMounted : false; + }, + + getCurrentStackAddendum(topElement) { + var info = ''; + if (topElement) { + var type = topElement.type; + var name = typeof type === 'function' ? + type.displayName || type.name : + type; + var owner = topElement._owner; + info += describeComponentFrame( + name || 'Unknown', + topElement._source, + owner && owner.getName() + ); + } + + var currentOwner = ReactCurrentOwner.current; + var id = currentOwner && currentOwner._debugID; + + info += ReactComponentTreeDevtoolDev.getStackAddendumByID(id); + return info; + }, + + getStackAddendumByID(id) { + var info = ''; + while (id) { + info += describeID(id); + id = ReactComponentTreeDevtoolDev.getParentID(id); + } + return info; + }, + + getChildIDs(id) { + var item = tree[id]; + return item ? item.childIDs : []; + }, + + getDisplayName(id) { + var item = tree[id]; + return item ? item.displayName : 'Unknown'; + }, + + getElement(id) { + var item = tree[id]; + return item ? item.element : null; + }, + + getOwnerID(id) { + var item = tree[id]; + return item ? item.ownerID : null; + }, + + getParentID(id) { + var item = tree[id]; + return item ? item.parentID : null; + }, + + getSource(id) { + var item = tree[id]; + var element = item ? item.element : null; + var source = element != null ? element._source : null; + return source; + }, + + getText(id) { + var item = tree[id]; + return item ? item.text : null; + }, + + getUpdateCount(id) { + var item = tree[id]; + return item ? item.updateCount : 0; + }, + + getRootIDs() { + return Object.keys(rootIDs); + }, + + getRegisteredIDs() { + return Object.keys(tree); + }, + }; +} + +module.exports = ReactComponentTreeDevtoolDev; diff --git a/src/isomorphic/modern/class/ReactComponent.js b/src/isomorphic/modern/class/ReactComponent.js index b93da63e94cf9..81547ba92b6c6 100644 --- a/src/isomorphic/modern/class/ReactComponent.js +++ b/src/isomorphic/modern/class/ReactComponent.js @@ -13,7 +13,7 @@ var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue'); -var canDefineProperty = require('canDefineProperty'); +var canDefinePropertyDev = require('canDefinePropertyDev'); var emptyObject = require('emptyObject'); var invariant = require('invariant'); var warning = require('warning'); @@ -111,7 +111,7 @@ if (__DEV__) { ], }; var defineDeprecationWarning = function(methodName, info) { - if (canDefineProperty) { + if (canDefinePropertyDev) { Object.defineProperty(ReactComponent.prototype, methodName, { get: function() { warning( diff --git a/src/renderers/dom/client/ReactMount.js b/src/renderers/dom/client/ReactMount.js index 9a0d15ba272af..69cb3b24486c2 100644 --- a/src/renderers/dom/client/ReactMount.js +++ b/src/renderers/dom/client/ReactMount.js @@ -21,7 +21,7 @@ var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags'); var ReactElement = require('ReactElement'); var ReactFeatureFlags = require('ReactFeatureFlags'); var ReactInstanceMap = require('ReactInstanceMap'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var ReactMarkupChecksum = require('ReactMarkupChecksum'); var ReactReconciler = require('ReactReconciler'); var ReactUpdateQueue = require('ReactUpdateQueue'); @@ -171,11 +171,11 @@ function batchedMountComponentIntoNode( */ function unmountComponentFromNode(instance, container, safely) { if (__DEV__) { - ReactInstrumentation.debugTool.onBeginFlush(); + ReactInstrumentationDev.debugTool.onBeginFlush(); } ReactReconciler.unmountComponent(instance, safely); if (__DEV__) { - ReactInstrumentation.debugTool.onEndFlush(); + ReactInstrumentationDev.debugTool.onEndFlush(); } if (container.nodeType === DOC_NODE_TYPE) { @@ -357,7 +357,7 @@ var ReactMount = { if (__DEV__) { // The instance here is TopLevelWrapper so we report mount for its child. - ReactInstrumentation.debugTool.onMountRootComponent( + ReactInstrumentationDev.debugTool.onMountRootComponent( componentInstance._renderedComponent._debugID ); } @@ -705,7 +705,7 @@ var ReactMount = { if (__DEV__) { var hostNode = ReactDOMComponentTree.getInstanceFromNode(container.firstChild); if (hostNode._debugID !== 0) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( hostNode._debugID, 'mount', markup.toString() diff --git a/src/renderers/dom/client/ReactReconcileTransaction.js b/src/renderers/dom/client/ReactReconcileTransaction.js index 833e415f8023d..ff6b32101359a 100644 --- a/src/renderers/dom/client/ReactReconcileTransaction.js +++ b/src/renderers/dom/client/ReactReconcileTransaction.js @@ -15,7 +15,7 @@ var CallbackQueue = require('CallbackQueue'); var PooledClass = require('PooledClass'); var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter'); var ReactInputSelection = require('ReactInputSelection'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var Transaction = require('Transaction'); var ReactUpdateQueue = require('ReactUpdateQueue'); @@ -94,8 +94,8 @@ var TRANSACTION_WRAPPERS = [ if (__DEV__) { TRANSACTION_WRAPPERS.push({ - initialize: ReactInstrumentation.debugTool.onBeginFlush, - close: ReactInstrumentation.debugTool.onEndFlush, + initialize: ReactInstrumentationDev.debugTool.onBeginFlush, + close: ReactInstrumentationDev.debugTool.onEndFlush, }); } diff --git a/src/renderers/dom/client/__tests__/validateDOMNesting-test.js b/src/renderers/dom/client/__tests__/validateDOMNestingDev-test.js similarity index 91% rename from src/renderers/dom/client/__tests__/validateDOMNesting-test.js rename to src/renderers/dom/client/__tests__/validateDOMNestingDev-test.js index dec17ae4ba288..3bda33290e45f 100644 --- a/src/renderers/dom/client/__tests__/validateDOMNesting-test.js +++ b/src/renderers/dom/client/__tests__/validateDOMNestingDev-test.js @@ -11,7 +11,7 @@ 'use strict'; -var validateDOMNesting; +var validateDOMNestingDev; // https://html.spec.whatwg.org/multipage/syntax.html#special var specialTags = [ @@ -36,11 +36,11 @@ var formattingTags = [ function isTagStackValid(stack) { var ancestorInfo = null; for (var i = 0; i < stack.length; i++) { - if (!validateDOMNesting.isTagValidInContext(stack[i], ancestorInfo)) { + if (!validateDOMNestingDev.isTagValidInContext(stack[i], ancestorInfo)) { return false; } ancestorInfo = - validateDOMNesting.updatedAncestorInfo(ancestorInfo, stack[i], null); + validateDOMNestingDev.updatedAncestorInfo(ancestorInfo, stack[i], null); } return true; } @@ -49,7 +49,7 @@ describe('ReactContextValidator', function() { beforeEach(function() { jest.resetModuleRegistry(); - validateDOMNesting = require('validateDOMNesting'); + validateDOMNestingDev = require('validateDOMNestingDev'); }); it('allows any tag with no context', function() { @@ -57,7 +57,7 @@ describe('ReactContextValidator', function() { // tag so we must err on the side of leniency. var allTags = [].concat(specialTags, formattingTags, ['mysterytag']); allTags.forEach(function(tag) { - expect(validateDOMNesting.isTagValidInContext(tag, null)).toBe(true); + expect(validateDOMNestingDev.isTagValidInContext(tag, null)).toBe(true); }); }); diff --git a/src/renderers/dom/client/utils/DOMChildrenOperations.js b/src/renderers/dom/client/utils/DOMChildrenOperations.js index a4541646d1900..f799fd7b00210 100644 --- a/src/renderers/dom/client/utils/DOMChildrenOperations.js +++ b/src/renderers/dom/client/utils/DOMChildrenOperations.js @@ -15,7 +15,7 @@ var DOMLazyTree = require('DOMLazyTree'); var Danger = require('Danger'); var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var createMicrosoftUnsafeLocalFunction = require('createMicrosoftUnsafeLocalFunction'); var setInnerHTML = require('setInnerHTML'); @@ -123,7 +123,7 @@ function replaceDelimitedText(openingComment, closingComment, stringText) { } if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( ReactDOMComponentTree.getInstanceFromNode(openingComment)._debugID, 'replace text', stringText @@ -136,7 +136,7 @@ if (__DEV__) { dangerouslyReplaceNodeWithMarkup = function(oldChild, markup, prevInstance) { Danger.dangerouslyReplaceNodeWithMarkup(oldChild, markup); if (prevInstance._debugID !== 0) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( prevInstance._debugID, 'replace with', markup.toString() @@ -144,7 +144,7 @@ if (__DEV__) { } else { var nextInstance = ReactDOMComponentTree.getInstanceFromNode(markup.node); if (nextInstance._debugID !== 0) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( nextInstance._debugID, 'mount', markup.toString() @@ -186,7 +186,7 @@ var DOMChildrenOperations = { getNodeAfter(parentNode, update.afterNode) ); if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( parentNodeDebugID, 'insert child', {toIndex: update.toIndex, content: update.content.toString()} @@ -200,7 +200,7 @@ var DOMChildrenOperations = { getNodeAfter(parentNode, update.afterNode) ); if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( parentNodeDebugID, 'move child', {fromIndex: update.fromIndex, toIndex: update.toIndex} @@ -213,7 +213,7 @@ var DOMChildrenOperations = { update.content ); if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( parentNodeDebugID, 'replace children', update.content.toString() @@ -226,7 +226,7 @@ var DOMChildrenOperations = { update.content ); if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( parentNodeDebugID, 'replace text', update.content.toString() @@ -236,7 +236,7 @@ var DOMChildrenOperations = { case ReactMultiChildUpdateTypes.REMOVE_NODE: removeChild(parentNode, update.fromNode); if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( parentNodeDebugID, 'remove child', {fromIndex: update.fromIndex} diff --git a/src/renderers/dom/client/validateDOMNesting.js b/src/renderers/dom/client/validateDOMNestingDev.js similarity index 97% rename from src/renderers/dom/client/validateDOMNesting.js rename to src/renderers/dom/client/validateDOMNestingDev.js index 9422a079e1462..0647416f07f49 100644 --- a/src/renderers/dom/client/validateDOMNesting.js +++ b/src/renderers/dom/client/validateDOMNestingDev.js @@ -6,7 +6,7 @@ * 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 validateDOMNesting + * @providesModule validateDOMNestingDev */ 'use strict'; @@ -14,7 +14,7 @@ var emptyFunction = require('emptyFunction'); var warning = require('warning'); -var validateDOMNesting = emptyFunction; +var validateDOMNestingDev = emptyFunction; if (__DEV__) { // This validation code was written based on the HTML5 parsing spec: @@ -322,7 +322,7 @@ if (__DEV__) { var didWarn = {}; - validateDOMNesting = function(childTag, childInstance, ancestorInfo) { + validateDOMNestingDev = function(childTag, childInstance, ancestorInfo) { ancestorInfo = ancestorInfo || emptyAncestorInfo; var parentInfo = ancestorInfo.current; var parentTag = parentInfo && parentInfo.tag; @@ -418,10 +418,10 @@ if (__DEV__) { } }; - validateDOMNesting.updatedAncestorInfo = updatedAncestorInfo; + validateDOMNestingDev.updatedAncestorInfo = updatedAncestorInfo; // For testing - validateDOMNesting.isTagValidInContext = function(tag, ancestorInfo) { + validateDOMNestingDev.isTagValidInContext = function(tag, ancestorInfo) { ancestorInfo = ancestorInfo || emptyAncestorInfo; var parentInfo = ancestorInfo.current; var parentTag = parentInfo && parentInfo.tag; @@ -432,4 +432,4 @@ if (__DEV__) { }; } -module.exports = validateDOMNesting; +module.exports = validateDOMNestingDev; diff --git a/src/renderers/dom/client/wrappers/LinkedValueUtils.js b/src/renderers/dom/client/wrappers/LinkedValueUtils.js index d13630d6f563a..b73b76e902d79 100644 --- a/src/renderers/dom/client/wrappers/LinkedValueUtils.js +++ b/src/renderers/dom/client/wrappers/LinkedValueUtils.js @@ -103,29 +103,6 @@ function getDeclarationErrorAddendum(owner) { * this outside of the ReactDOM controlled form components. */ var LinkedValueUtils = { - checkPropTypes: function(tagName, props, owner) { - for (var propName in propTypes) { - if (propTypes.hasOwnProperty(propName)) { - var error = propTypes[propName]( - props, - propName, - tagName, - ReactPropTypeLocations.prop, - null, - ReactPropTypesSecret - ); - } - if (error instanceof Error && !(error.message in loggedTypeFailures)) { - // Only monitor this failure once because there tends to be a lot of the - // same error. - loggedTypeFailures[error.message] = true; - - var addendum = getDeclarationErrorAddendum(owner); - warning(false, 'Failed form propType: %s%s', error.message, addendum); - } - } - }, - /** * @param {object} inputProps Props for form component * @return {*} current value of the input either from value prop or link. @@ -168,4 +145,29 @@ var LinkedValueUtils = { }, }; +if (__DEV__) { + LinkedValueUtils.checkPropTypes = function(tagName, props, owner) { + for (var propName in propTypes) { + if (propTypes.hasOwnProperty(propName)) { + var error = propTypes[propName]( + props, + propName, + tagName, + ReactPropTypeLocations.prop, + null, + ReactPropTypesSecret + ); + } + if (error instanceof Error && !(error.message in loggedTypeFailures)) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error.message] = true; + + var addendum = getDeclarationErrorAddendum(owner); + warning(false, 'Failed form propType: %s%s', error.message, addendum); + } + } + }; +} + module.exports = LinkedValueUtils; diff --git a/src/renderers/dom/server/ReactServerRendering.js b/src/renderers/dom/server/ReactServerRendering.js index fefb9af9d5cd5..d2f2dc6217da6 100644 --- a/src/renderers/dom/server/ReactServerRendering.js +++ b/src/renderers/dom/server/ReactServerRendering.js @@ -13,7 +13,7 @@ var ReactDOMContainerInfo = require('ReactDOMContainerInfo'); var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy'); var ReactElement = require('ReactElement'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var ReactMarkupChecksum = require('ReactMarkupChecksum'); var ReactReconciler = require('ReactReconciler'); var ReactServerBatchingStrategy = require('ReactServerBatchingStrategy'); @@ -50,7 +50,7 @@ function renderToStringImpl(element, makeStaticMarkup) { emptyObject ); if (__DEV__) { - ReactInstrumentation.debugTool.onUnmountComponent( + ReactInstrumentationDev.debugTool.onUnmountComponent( componentInstance._debugID ); } diff --git a/src/renderers/dom/server/ReactServerRenderingTransaction.js b/src/renderers/dom/server/ReactServerRenderingTransaction.js index ddb93b6311dd0..79a26447654c1 100644 --- a/src/renderers/dom/server/ReactServerRenderingTransaction.js +++ b/src/renderers/dom/server/ReactServerRenderingTransaction.js @@ -13,7 +13,7 @@ var PooledClass = require('PooledClass'); var Transaction = require('Transaction'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var ReactServerUpdateQueue = require('ReactServerUpdateQueue'); @@ -26,8 +26,8 @@ var TRANSACTION_WRAPPERS = []; if (__DEV__) { TRANSACTION_WRAPPERS.push({ - initialize: ReactInstrumentation.debugTool.onBeginFlush, - close: ReactInstrumentation.debugTool.onEndFlush, + initialize: ReactInstrumentationDev.debugTool.onBeginFlush, + close: ReactInstrumentationDev.debugTool.onEndFlush, }); } diff --git a/src/renderers/dom/shared/CSSPropertyOperations.js b/src/renderers/dom/shared/CSSPropertyOperations.js index c3222c202f147..54be9df0b0873 100644 --- a/src/renderers/dom/shared/CSSPropertyOperations.js +++ b/src/renderers/dom/shared/CSSPropertyOperations.js @@ -13,7 +13,7 @@ var CSSProperty = require('CSSProperty'); var ExecutionEnvironment = require('ExecutionEnvironment'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var camelizeStyleName = require('camelizeStyleName'); var dangerousStyleValue = require('dangerousStyleValue'); @@ -193,7 +193,7 @@ var CSSPropertyOperations = { */ setValueForStyles: function(node, styles, component) { if (__DEV__) { - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( component._debugID, 'update styles', styles diff --git a/src/renderers/dom/shared/DOMPropertyOperations.js b/src/renderers/dom/shared/DOMPropertyOperations.js index d0cce18dcf9b2..869bed91a7765 100644 --- a/src/renderers/dom/shared/DOMPropertyOperations.js +++ b/src/renderers/dom/shared/DOMPropertyOperations.js @@ -14,7 +14,7 @@ var DOMProperty = require('DOMProperty'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); var ReactDOMInstrumentation = require('ReactDOMInstrumentation'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var quoteAttributeValueForBrowser = require('quoteAttributeValueForBrowser'); var warning = require('warning'); @@ -171,7 +171,7 @@ var DOMPropertyOperations = { ReactDOMInstrumentation.debugTool.onSetValueForProperty(node, name, value); var payload = {}; payload[name] = value; - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( ReactDOMComponentTree.getInstanceFromNode(node)._debugID, 'update attribute', payload @@ -192,7 +192,7 @@ var DOMPropertyOperations = { if (__DEV__) { var payload = {}; payload[name] = value; - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( ReactDOMComponentTree.getInstanceFromNode(node)._debugID, 'update attribute', payload @@ -210,7 +210,7 @@ var DOMPropertyOperations = { node.removeAttribute(name); if (__DEV__) { ReactDOMInstrumentation.debugTool.onDeleteValueForProperty(node, name); - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( ReactDOMComponentTree.getInstanceFromNode(node)._debugID, 'remove attribute', name @@ -247,7 +247,7 @@ var DOMPropertyOperations = { if (__DEV__) { ReactDOMInstrumentation.debugTool.onDeleteValueForProperty(node, name); - ReactInstrumentation.debugTool.onHostOperation( + ReactInstrumentationDev.debugTool.onHostOperation( ReactDOMComponentTree.getInstanceFromNode(node)._debugID, 'remove attribute', name diff --git a/src/renderers/dom/shared/ReactDOMComponent.js b/src/renderers/dom/shared/ReactDOMComponent.js index c4de8639b74ca..215bcc50335f8 100644 --- a/src/renderers/dom/shared/ReactDOMComponent.js +++ b/src/renderers/dom/shared/ReactDOMComponent.js @@ -32,7 +32,7 @@ var ReactDOMInput = require('ReactDOMInput'); var ReactDOMOption = require('ReactDOMOption'); var ReactDOMSelect = require('ReactDOMSelect'); var ReactDOMTextarea = require('ReactDOMTextarea'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var ReactMultiChild = require('ReactMultiChild'); var ReactServerRenderingTransaction = require('ReactServerRenderingTransaction'); @@ -43,7 +43,7 @@ var isEventSupported = require('isEventSupported'); var keyOf = require('keyOf'); var shallowEqual = require('shallowEqual'); var inputValueTracking = require('inputValueTracking'); -var validateDOMNesting = require('validateDOMNesting'); +var validateDOMNestingDev = require('validateDOMNestingDev'); var warning = require('warning'); var Flags = ReactDOMComponentFlags; @@ -265,7 +265,7 @@ if (__DEV__) { if (content == null) { if (hasExistingContent) { - ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID); + ReactInstrumentationDev.debugTool.onUnmountComponent(this._contentDebugID); } this._contentDebugID = null; return; @@ -274,17 +274,17 @@ if (__DEV__) { this._contentDebugID = contentDebugID; var text = '' + content; - ReactInstrumentation.debugTool.onSetDisplayName(contentDebugID, '#text'); - ReactInstrumentation.debugTool.onSetParent(contentDebugID, debugID); - ReactInstrumentation.debugTool.onSetText(contentDebugID, text); + ReactInstrumentationDev.debugTool.onSetDisplayName(contentDebugID, '#text'); + ReactInstrumentationDev.debugTool.onSetParent(contentDebugID, debugID); + ReactInstrumentationDev.debugTool.onSetText(contentDebugID, text); if (hasExistingContent) { - ReactInstrumentation.debugTool.onBeforeUpdateComponent(contentDebugID, content); - ReactInstrumentation.debugTool.onUpdateComponent(contentDebugID); + ReactInstrumentationDev.debugTool.onBeforeUpdateComponent(contentDebugID, content); + ReactInstrumentationDev.debugTool.onUpdateComponent(contentDebugID); } else { - ReactInstrumentation.debugTool.onBeforeMountComponent(contentDebugID, content); - ReactInstrumentation.debugTool.onMountComponent(contentDebugID); - ReactInstrumentation.debugTool.onSetChildren(debugID, [contentDebugID]); + ReactInstrumentationDev.debugTool.onBeforeMountComponent(contentDebugID, content); + ReactInstrumentationDev.debugTool.onMountComponent(contentDebugID); + ReactInstrumentationDev.debugTool.onSetChildren(debugID, [contentDebugID]); } }; } @@ -612,10 +612,10 @@ ReactDOMComponent.Mixin = { if (parentInfo) { // parentInfo should always be present except for the top-level // component when server rendering - validateDOMNesting(this._tag, this, parentInfo); + validateDOMNestingDev(this._tag, this, parentInfo); } this._ancestorInfo = - validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this); + validateDOMNestingDev.updatedAncestorInfo(parentInfo, this._tag, this); } var mountImage; @@ -715,7 +715,7 @@ ReactDOMComponent.Mixin = { if (__DEV__) { if (this._debugID) { - var callback = () => ReactInstrumentation.debugTool.onComponentHasMounted(this._debugID); + var callback = () => ReactInstrumentationDev.debugTool.onComponentHasMounted(this._debugID); transaction.getReactMountReady().enqueue(callback, this); } } @@ -952,7 +952,7 @@ ReactDOMComponent.Mixin = { if (__DEV__) { if (this._debugID) { - var callback = () => ReactInstrumentation.debugTool.onComponentHasUpdated(this._debugID); + var callback = () => ReactInstrumentationDev.debugTool.onComponentHasUpdated(this._debugID); transaction.getReactMountReady().enqueue(callback, this); } } @@ -1130,7 +1130,7 @@ ReactDOMComponent.Mixin = { } else if (lastHasContentOrHtml && !nextHasContentOrHtml) { this.updateTextContent(''); if (__DEV__) { - ReactInstrumentation.debugTool.onSetChildren(this._debugID, []); + ReactInstrumentationDev.debugTool.onSetChildren(this._debugID, []); } } @@ -1146,7 +1146,7 @@ ReactDOMComponent.Mixin = { this.updateMarkup('' + nextHtml); } if (__DEV__) { - ReactInstrumentation.debugTool.onSetChildren(this._debugID, []); + ReactInstrumentationDev.debugTool.onSetChildren(this._debugID, []); } } else if (nextChildren != null) { if (__DEV__) { diff --git a/src/renderers/dom/shared/ReactDOMContainerInfo.js b/src/renderers/dom/shared/ReactDOMContainerInfo.js index 0f74f733a7acb..dea344080ce6c 100644 --- a/src/renderers/dom/shared/ReactDOMContainerInfo.js +++ b/src/renderers/dom/shared/ReactDOMContainerInfo.js @@ -11,7 +11,7 @@ 'use strict'; -var validateDOMNesting = require('validateDOMNesting'); +var validateDOMNestingDev = require('validateDOMNestingDev'); var DOC_NODE_TYPE = 9; @@ -28,7 +28,7 @@ function ReactDOMContainerInfo(topLevelWrapper, node) { }; if (__DEV__) { info._ancestorInfo = node ? - validateDOMNesting.updatedAncestorInfo(null, info._tag, null) : null; + validateDOMNestingDev.updatedAncestorInfo(null, info._tag, null) : null; } return info; } diff --git a/src/renderers/dom/shared/ReactDOMDebugTool.js b/src/renderers/dom/shared/ReactDOMDebugTool.js deleted file mode 100644 index 107f0052d2c42..0000000000000 --- a/src/renderers/dom/shared/ReactDOMDebugTool.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * 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 ReactDOMDebugTool - */ - -'use strict'; - -var ReactDebugTool = require('ReactDebugTool'); -var ReactDOMNullInputValuePropDevtool = require('ReactDOMNullInputValuePropDevtool'); -var ReactDOMUnknownPropertyDevtool = require('ReactDOMUnknownPropertyDevtool'); - -var warning = require('warning'); - -var eventHandlers = []; -var handlerDoesThrowForEvent = {}; - -function emitEvent(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) { - eventHandlers.forEach(function(handler) { - try { - if (handler[handlerFunctionName]) { - handler[handlerFunctionName](arg1, arg2, arg3, arg4, arg5); - } - } catch (e) { - warning( - handlerDoesThrowForEvent[handlerFunctionName], - 'exception thrown by devtool while handling %s: %s', - handlerFunctionName, - e + '\n' + e.stack - ); - handlerDoesThrowForEvent[handlerFunctionName] = true; - } - }); -} - -var ReactDOMDebugTool = { - addDevtool(devtool) { - ReactDebugTool.addDevtool(devtool); - eventHandlers.push(devtool); - }, - removeDevtool(devtool) { - ReactDebugTool.removeDevtool(devtool); - for (var i = 0; i < eventHandlers.length; i++) { - if (eventHandlers[i] === devtool) { - eventHandlers.splice(i, 1); - i--; - } - } - }, - onCreateMarkupForProperty(name, value) { - emitEvent('onCreateMarkupForProperty', name, value); - }, - onSetValueForProperty(node, name, value) { - emitEvent('onSetValueForProperty', node, name, value); - }, - onDeleteValueForProperty(node, name) { - emitEvent('onDeleteValueForProperty', node, name); - }, - onTestEvent() { - emitEvent('onTestEvent'); - }, -}; - -if (__DEV__) { - ReactDOMDebugTool.addDevtool(ReactDOMUnknownPropertyDevtool); - ReactDOMDebugTool.addDevtool(ReactDOMNullInputValuePropDevtool); -} - -module.exports = ReactDOMDebugTool; diff --git a/src/renderers/dom/shared/ReactDOMDebugToolDev.js b/src/renderers/dom/shared/ReactDOMDebugToolDev.js new file mode 100644 index 0000000000000..f13a47f4c57a4 --- /dev/null +++ b/src/renderers/dom/shared/ReactDOMDebugToolDev.js @@ -0,0 +1,76 @@ +/** + * 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 ReactDOMDebugToolDev + */ + +'use strict'; + +var ReactDebugToolDev = require('ReactDebugToolDev'); +var ReactDOMNullInputValuePropDevtoolDev = require('ReactDOMNullInputValuePropDevtoolDev'); +var ReactDOMUnknownPropertyDevtoolDev = require('ReactDOMUnknownPropertyDevtoolDev'); + +var warning = require('warning'); + +var ReactDOMDebugToolDev = {}; + +if (__DEV__) { + var eventHandlers = []; + var handlerDoesThrowForEvent = {}; + + var emitEvent = function(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) { + eventHandlers.forEach(function(handler) { + try { + if (handler[handlerFunctionName]) { + handler[handlerFunctionName](arg1, arg2, arg3, arg4, arg5); + } + } catch (e) { + warning( + handlerDoesThrowForEvent[handlerFunctionName], + 'exception thrown by devtool while handling %s: %s', + handlerFunctionName, + e + '\n' + e.stack + ); + handlerDoesThrowForEvent[handlerFunctionName] = true; + } + }); + }; + + var ReactDOMDebugToolDev = { + addDevtool(devtool) { + ReactDebugToolDev.addDevtool(devtool); + eventHandlers.push(devtool); + }, + removeDevtool(devtool) { + ReactDebugToolDev.removeDevtool(devtool); + for (var i = 0; i < eventHandlers.length; i++) { + if (eventHandlers[i] === devtool) { + eventHandlers.splice(i, 1); + i--; + } + } + }, + onCreateMarkupForProperty(name, value) { + emitEvent('onCreateMarkupForProperty', name, value); + }, + onSetValueForProperty(node, name, value) { + emitEvent('onSetValueForProperty', node, name, value); + }, + onDeleteValueForProperty(node, name) { + emitEvent('onDeleteValueForProperty', node, name); + }, + onTestEvent() { + emitEvent('onTestEvent'); + }, + }; + + ReactDOMDebugToolDev.addDevtool(ReactDOMUnknownPropertyDevtoolDev); + ReactDOMDebugToolDev.addDevtool(ReactDOMNullInputValuePropDevtoolDev); +} + +module.exports = ReactDOMDebugToolDev; diff --git a/src/renderers/dom/shared/ReactDOMInstrumentation.js b/src/renderers/dom/shared/ReactDOMInstrumentation.js index b290c6c553cf0..ffa01c3aeda99 100644 --- a/src/renderers/dom/shared/ReactDOMInstrumentation.js +++ b/src/renderers/dom/shared/ReactDOMInstrumentation.js @@ -11,6 +11,6 @@ 'use strict'; -var ReactDOMDebugTool = require('ReactDOMDebugTool'); +var ReactDOMDebugToolDev = require('ReactDOMDebugToolDev'); -module.exports = {debugTool: ReactDOMDebugTool}; +module.exports = {debugTool: ReactDOMDebugToolDev}; diff --git a/src/renderers/dom/shared/ReactDOMTextComponent.js b/src/renderers/dom/shared/ReactDOMTextComponent.js index 95eacc9c2c06a..8ae952073352e 100644 --- a/src/renderers/dom/shared/ReactDOMTextComponent.js +++ b/src/renderers/dom/shared/ReactDOMTextComponent.js @@ -14,11 +14,11 @@ var DOMChildrenOperations = require('DOMChildrenOperations'); var DOMLazyTree = require('DOMLazyTree'); var ReactDOMComponentTree = require('ReactDOMComponentTree'); -var ReactInstrumentation = require('ReactInstrumentation'); +var ReactInstrumentationDev = require('ReactInstrumentationDev'); var escapeTextContentForBrowser = require('escapeTextContentForBrowser'); var invariant = require('invariant'); -var validateDOMNesting = require('validateDOMNesting'); +var validateDOMNestingDev = require('validateDOMNestingDev'); /** * Text nodes violate a couple assumptions that React makes about components: @@ -67,7 +67,7 @@ Object.assign(ReactDOMTextComponent.prototype, { context ) { if (__DEV__) { - ReactInstrumentation.debugTool.onSetText(this._debugID, this._stringText); + ReactInstrumentationDev.debugTool.onSetText(this._debugID, this._stringText); var parentInfo; if (hostParent != null) { @@ -78,7 +78,7 @@ Object.assign(ReactDOMTextComponent.prototype, { if (parentInfo) { // parentInfo should always be present except for the top-level // component when server rendering - validateDOMNesting('#text', this, parentInfo); + validateDOMNestingDev('#text', this, parentInfo); } } @@ -144,7 +144,7 @@ Object.assign(ReactDOMTextComponent.prototype, { ); if (__DEV__) { - ReactInstrumentation.debugTool.onSetText( + ReactInstrumentationDev.debugTool.onSetText( this._debugID, nextStringText ); diff --git a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js index be0b0269ab3d1..f03fdc5521677 100644 --- a/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js +++ b/src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js @@ -736,7 +736,7 @@ describe('ReactDOMComponent', function() { }); it('should work error event on element', function() { - spyOn(console, 'error'); + spyOn(console, 'error'); var container = document.createElement('div'); ReactDOM.render(