From 7c6a95cf30aabbdc81973c0a0db305e2f22a9526 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Sat, 2 Jul 2016 01:59:12 -0700 Subject: [PATCH] Build renderers into their individual npm packages This copies modules into three separate packages instead of putting it all in React. The overlap in shared and between renderers gets duplicated. This allows the isomorphic package to stay minimal. It can also be used as a direct dependency without much risk. This also allow us to ship versions to each renderer independently and we can ship renderers without updating the main react package dependency. --- grunt/config/browserify.js | 33 ++-- grunt/tasks/npm-react-addons.js | 15 +- grunt/tasks/npm-react-dom.js | 3 + grunt/tasks/npm-react-native.js | 3 + grunt/tasks/npm-react.js | 2 +- gulpfile.js | 143 ++++++++++++++++-- package.json | 1 + packages/react-dom/package.json | 11 +- packages/react-native-renderer/package.json | 4 + .../stack/event}/SyntheticEvent.js | 0 10 files changed, 181 insertions(+), 34 deletions(-) rename src/renderers/{dom/client/syntheticEvents => shared/stack/event}/SyntheticEvent.js (100%) diff --git a/grunt/config/browserify.js b/grunt/config/browserify.js index d28f191f1383c..3a4aa2a272607 100644 --- a/grunt/config/browserify.js +++ b/grunt/config/browserify.js @@ -17,18 +17,21 @@ var SECRET_INTERNALS_NAME = 'React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_ var SECRET_DOM_INTERNALS_NAME = 'ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED'; var shimSharedModules = globalShim.configure({ - './ReactCurrentOwner': SECRET_INTERNALS_NAME + '.ReactCurrentOwner', - './ReactComponentTreeDevtool': SECRET_INTERNALS_NAME + '.ReactComponentTreeDevtool', + // Shared state + 'react/lib/ReactCurrentOwner': SECRET_INTERNALS_NAME + '.ReactCurrentOwner', + 'react/lib/ReactComponentTreeDevtool': SECRET_INTERNALS_NAME + '.ReactComponentTreeDevtool', // All these methods are shared are exposed. - './ReactElement': 'React', - './ReactPropTypes': 'React.PropTypes', - './ReactChildren': 'React.Children', + // TODO: Update the source to just use the React module. + 'react/lib/React': 'React', + 'react/lib/ReactElement': 'React', + 'react/lib/ReactPropTypes': 'React.PropTypes', + 'react/lib/ReactChildren': 'React.Children', }); // Shim references to ReactDOM internals from addons. var shimDOM = globalShim.configure({ - './ReactDOM': 'ReactDOM', - './ReactInstanceMap': SECRET_DOM_INTERNALS_NAME + '.ReactInstanceMap', + 'react-dom/lib/ReactDOM': 'ReactDOM', + 'react-dom/lib/ReactInstanceMap': SECRET_DOM_INTERNALS_NAME + '.ReactInstanceMap', // TestUtils pulls in a bunch of internals. './EventConstants': SECRET_DOM_INTERNALS_NAME + '.EventConstants', @@ -84,7 +87,7 @@ function simpleBannerify(src) { // Our basic config which we'll add to to make our other builds var basic = { entries: [ - './build/modules/ReactUMDEntry.js', + './build/node_modules/react/lib/ReactUMDEntry.js', ], outfile: './build/react.js', debug: false, @@ -97,7 +100,7 @@ var basic = { var min = { entries: [ - './build/modules/ReactUMDEntry.js', + './build/node_modules/react/lib/ReactUMDEntry.js', ], outfile: './build/react.min.js', debug: false, @@ -115,7 +118,7 @@ var min = { var addons = { entries: [ - './build/modules/ReactWithAddonsUMDEntry.js', + './build/node_modules/react/lib/ReactWithAddonsUMDEntry.js', ], outfile: './build/react-with-addons.js', debug: false, @@ -129,7 +132,7 @@ var addons = { var addonsMin = { entries: [ - './build/modules/ReactWithAddonsUMDEntry.js', + './build/node_modules/react/lib/ReactWithAddonsUMDEntry.js', ], outfile: './build/react-with-addons.min.js', debug: false, @@ -147,7 +150,7 @@ var addonsMin = { // The DOM Builds var dom = { entries: [ - './build/modules/ReactDOMUMDEntry.js', + './build/node_modules/react-dom/lib/ReactDOMUMDEntry.js', ], outfile: './build/react-dom.js', debug: false, @@ -161,7 +164,7 @@ var dom = { var domMin = { entries: [ - './build/modules/ReactDOMUMDEntry.js', + './build/node_modules/react-dom/lib/ReactDOMUMDEntry.js', ], outfile: './build/react-dom.min.js', debug: false, @@ -179,7 +182,7 @@ var domMin = { var domServer = { entries: [ - './build/modules/ReactDOMServerUMDEntry.js', + './build/node_modules/react-dom/lib/ReactDOMServerUMDEntry.js', ], outfile: './build/react-dom-server.js', debug: false, @@ -193,7 +196,7 @@ var domServer = { var domServerMin = { entries: [ - './build/modules/ReactDOMServerUMDEntry.js', + './build/node_modules/react-dom/lib/ReactDOMServerUMDEntry.js', ], outfile: './build/react-dom-server.min.js', debug: false, diff --git a/grunt/tasks/npm-react-addons.js b/grunt/tasks/npm-react-addons.js index 0f3d088d9ccaa..4aa0132a15791 100644 --- a/grunt/tasks/npm-react-addons.js +++ b/grunt/tasks/npm-react-addons.js @@ -6,46 +6,55 @@ var path = require('path'); var addons = { CSSTransitionGroup: { + package: 'react', module: 'ReactCSSTransitionGroup', name: 'css-transition-group', docs: 'animation', }, LinkedStateMixin: { + package: 'react', module: 'LinkedStateMixin', name: 'linked-state-mixin', docs: 'two-way-binding-helpers', }, Perf: { + package: 'react-dom', module: 'ReactPerf', name: 'perf', docs: 'perf', }, PureRenderMixin: { + package: 'react', module: 'ReactComponentWithPureRenderMixin', name: 'pure-render-mixin', docs: 'pure-render-mixin', }, TestUtils: { + package: 'react-dom', module: 'ReactTestUtils', name: 'test-utils', docs: 'test-utils', }, TransitionGroup: { + package: 'react', module: 'ReactTransitionGroup', name: 'transition-group', docs: 'animation', }, createFragment: { + package: 'react', module: 'ReactFragment', method: 'create', name: 'create-fragment', docs: 'create-fragment', }, shallowCompare: { + package: 'react', module: 'shallowCompare', name: 'shallow-compare', }, updates: { + package: 'react', module: 'update', name: 'update', docs: 'update', @@ -54,9 +63,11 @@ var addons = { function generateSource(info) { var pieces = [ - "module.exports = require('react/lib/", + 'module.exports = require(\'', + info.package, + '/lib/', info.module, - "')", + '\')', ]; if (info.method) { pieces.push('.', info.method); diff --git a/grunt/tasks/npm-react-dom.js b/grunt/tasks/npm-react-dom.js index 9856f1b6da9ee..859e95ac3d34d 100644 --- a/grunt/tasks/npm-react-dom.js +++ b/grunt/tasks/npm-react-dom.js @@ -5,6 +5,8 @@ var grunt = require('grunt'); var src = 'packages/react-dom/'; var dest = 'build/packages/react-dom/'; +var modSrc = 'build/node_modules/react-dom/lib'; +var lib = dest + 'lib/'; var dist = dest + 'dist/'; var distFiles = [ 'react-dom.js', @@ -21,6 +23,7 @@ function buildRelease() { // Copy to build/packages/react-dom var mappings = [].concat( grunt.file.expandMapping('**/*', dest, {cwd: src}), + grunt.file.expandMapping('**/*', lib, {cwd: modSrc}), grunt.file.expandMapping('{LICENSE,PATENTS}', dest) ); mappings.forEach(function(mapping) { diff --git a/grunt/tasks/npm-react-native.js b/grunt/tasks/npm-react-native.js index 7157e08f6bb3b..4aa8b9ec698a7 100644 --- a/grunt/tasks/npm-react-native.js +++ b/grunt/tasks/npm-react-native.js @@ -5,6 +5,8 @@ var grunt = require('grunt'); var src = 'packages/react-native-renderer/'; var dest = 'build/packages/react-native-renderer/'; +var modSrc = 'build/node_modules/react-native/lib'; +var lib = dest + 'lib/'; function buildRelease() { if (grunt.file.exists(dest)) { @@ -14,6 +16,7 @@ function buildRelease() { // Copy to build/packages/react-native-renderer var mappings = [].concat( grunt.file.expandMapping('**/*', dest, {cwd: src}), + grunt.file.expandMapping('**/*', lib, {cwd: modSrc}), grunt.file.expandMapping('{LICENSE,PATENTS}', dest) ); mappings.forEach(function(mapping) { diff --git a/grunt/tasks/npm-react.js b/grunt/tasks/npm-react.js index 2e459ec93b91a..038d2fec513ce 100644 --- a/grunt/tasks/npm-react.js +++ b/grunt/tasks/npm-react.js @@ -5,7 +5,7 @@ var grunt = require('grunt'); var src = 'packages/react/'; var dest = 'build/packages/react/'; -var modSrc = 'build/modules/'; +var modSrc = 'build/node_modules/react/lib'; var lib = dest + 'lib/'; var dist = dest + 'dist/'; var distFiles = [ diff --git a/gulpfile.js b/gulpfile.js index 103f608e208f9..1b818f8a0b534 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -13,6 +13,7 @@ var gulp = require('gulp'); var babel = require('gulp-babel'); var flatten = require('gulp-flatten'); var del = require('del'); +var merge = require('merge-stream'); var babelPluginModules = require('fbjs-scripts/babel-6/rewrite-modules'); var extractErrors = require('./scripts/error-codes/gulp-extract-errors'); @@ -21,21 +22,97 @@ var devExpressionWithCodes = require('./scripts/error-codes/dev-expression-with- var paths = { react: { src: [ - 'src/**/*.js', + 'src/umd/ReactUMDEntry.js', + 'src/umd/ReactWithAddonsUMDEntry.js', + + 'src/isomorphic/**/*.js', + 'src/addons/**/*.js', + + 'src/ReactVersion.js', + 'src/shared/**/*.js', + '!src/shared/vendor/**/*.js', + '!src/**/__benchmarks__/**/*.js', + '!src/**/__tests__/**/*.js', + '!src/**/__mocks__/**/*.js', + ], + lib: 'build/node_modules/react/lib', + }, + reactDOM: { + src: [ + 'src/umd/ReactDOMUMDEntry.js', + 'src/umd/ReactDOMServerUMDEntry.js', + + 'src/renderers/dom/**/*.js', + 'src/renderers/shared/**/*.js', + 'src/test/**/*.js', // ReactTestUtils is currently very coupled to DOM. + + 'src/ReactVersion.js', + 'src/shared/**/*.js', + '!src/shared/vendor/**/*.js', '!src/**/__benchmarks__/**/*.js', '!src/**/__tests__/**/*.js', '!src/**/__mocks__/**/*.js', - '!src/renderers/art/**/*.js', + ], + lib: 'build/node_modules/react-dom/lib', + }, + reactNative: { + src: [ + 'src/renderers/native/**/*.js', + 'src/renderers/shared/**/*.js', + + 'src/ReactVersion.js', + 'src/shared/**/*.js', '!src/shared/vendor/**/*.js', + '!src/**/__benchmarks__/**/*.js', + '!src/**/__tests__/**/*.js', + '!src/**/__mocks__/**/*.js', ], - lib: 'build/modules', + lib: 'build/node_modules/react-native/lib', }, }; -var moduleMap = Object.assign( +var moduleMapBase = Object.assign( {'object-assign': 'object-assign'}, - require('fbjs/module-map'), + require('fbjs/module-map') +); + +var moduleMapReact = Object.assign( { + // Addons needs to reach into DOM internals + ReactDOM: 'react-dom/lib/ReactDOM', + ReactInstanceMap: 'react-dom/lib/ReactInstanceMap', + ReactTestUtils: 'react-dom/lib/ReactTestUtils', + ReactPerf: 'react-dom/lib/ReactPerf', + getVendorPrefixedEventName: 'react-dom/lib/getVendorPrefixedEventName', + }, + moduleMapBase +); + +var rendererSharedState = { + // Shared state + ReactCurrentOwner: 'react/lib/ReactCurrentOwner', + ReactComponentTreeDevtool: 'react/lib/ReactComponentTreeDevtool', + + // TODO: Update the source to just use the React module. + React: 'react/lib/React', + ReactElement: 'react/lib/ReactElement', + ReactPropTypes: 'react/lib/ReactPropTypes', + ReactChildren: 'react/lib/ReactChildren', + + // Public exposed modules + ReactPropTypeLocations: 'react/lib/ReactPropTypeLocations', + checkReactTypeSpec: 'react/lib/checkReactTypeSpec', +}; + +var moduleMapReactDOM = Object.assign( + {}, + rendererSharedState, + moduleMapBase +); + +var moduleMapReactNative = Object.assign( + { + // React Native Hooks deepDiffer: 'react-native/lib/deepDiffer', deepFreezeAndThrowOnMutationInDev: 'react-native/lib/deepFreezeAndThrowOnMutationInDev', flattenStyle: 'react-native/lib/flattenStyle', @@ -45,36 +122,72 @@ var moduleMap = Object.assign( UIManager: 'react-native/lib/UIManager', UIManagerStatTracker: 'react-native/lib/UIManagerStatTracker', View: 'react-native/lib/View', - } + }, + rendererSharedState, + moduleMapBase ); var errorCodeOpts = { errorMapFilePath: 'scripts/error-codes/codes.json', }; -var babelOpts = { +var babelOptsReact = { plugins: [ devExpressionWithCodes, // this pass has to run before `rewrite-modules` - [babelPluginModules, {map: moduleMap}], + [babelPluginModules, {map: moduleMapReact}], + ], +}; + +var babelOptsReactDOM = { + plugins: [ + devExpressionWithCodes, // this pass has to run before `rewrite-modules` + [babelPluginModules, {map: moduleMapReactDOM}], + ], +}; + +var babelOptsReactNative = { + plugins: [ + devExpressionWithCodes, // this pass has to run before `rewrite-modules` + [babelPluginModules, {map: moduleMapReactNative}], ], }; gulp.task('react:clean', function() { - return del([paths.react.lib]); + return del([ + paths.react.lib, + paths.reactDOM.lib, + paths.reactNative.lib, + ]); }); gulp.task('react:modules', function() { - return gulp + return merge( + gulp .src(paths.react.src) - .pipe(babel(babelOpts)) + .pipe(babel(babelOptsReact)) .pipe(flatten()) - .pipe(gulp.dest(paths.react.lib)); + .pipe(gulp.dest(paths.react.lib)), + + gulp + .src(paths.reactDOM.src) + .pipe(babel(babelOptsReactDOM)) + .pipe(flatten()) + .pipe(gulp.dest(paths.reactDOM.lib)), + + gulp + .src(paths.reactNative.src) + .pipe(babel(babelOptsReactNative)) + .pipe(flatten()) + .pipe(gulp.dest(paths.reactNative.lib)) + ); }); gulp.task('react:extract-errors', function() { - return gulp - .src(paths.react.src) - .pipe(extractErrors(errorCodeOpts)); + return merge( + gulp.src(paths.react.src).pipe(extractErrors(errorCodeOpts)), + gulp.src(paths.reactDOM.src).pipe(extractErrors(errorCodeOpts)), + gulp.src(paths.reactNative.src).pipe(extractErrors(errorCodeOpts)) + ); }); gulp.task('default', ['react:modules']); diff --git a/package.json b/package.json index 691e2c052c27e..21d4796c154bd 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "gzip-js": "~0.3.2", "jest": "^12.1.1", "loose-envify": "^1.1.0", + "merge-stream": "^1.0.0", "object-assign": "^4.1.0", "platform": "^1.1.0", "run-sequence": "^1.1.4", diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json index 731630fde0748..8e0b72b50dabd 100644 --- a/packages/react-dom/package.json +++ b/packages/react-dom/package.json @@ -12,8 +12,17 @@ "url": "https://github.com/facebook/react/issues" }, "homepage": "https://facebook.github.io/react/", - "dependencies": {}, + "dependencies": { + "fbjs": "^0.8.1", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.0" + }, "peerDependencies": { "react": "^16.0.0-alpha" + }, + "browserify": { + "transform": [ + "loose-envify" + ] } } diff --git a/packages/react-native-renderer/package.json b/packages/react-native-renderer/package.json index 4f43245a698cd..cf8891889c8ed 100644 --- a/packages/react-native-renderer/package.json +++ b/packages/react-native-renderer/package.json @@ -14,6 +14,10 @@ }, "homepage": "https://facebook.github.io/react-native/", "dependencies": { + "fbjs": "^0.8.1", + "object-assign": "^4.1.0" + }, + "peerDependencies": { "react": "^16.0.0-alpha" } } diff --git a/src/renderers/dom/client/syntheticEvents/SyntheticEvent.js b/src/renderers/shared/stack/event/SyntheticEvent.js similarity index 100% rename from src/renderers/dom/client/syntheticEvents/SyntheticEvent.js rename to src/renderers/shared/stack/event/SyntheticEvent.js