Build renderers into their individual npm packages (#7168)
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.
Sebastian Markbåge committed
Aug 10, 2016 at 18:17 UTC
0f004efce2dcd0189a663f5724853eab261782e6
17 files changed
+237
-42
grunt/config/browserify.js
+17
-10
@@ -16,7 +16,7 @@ var envifyProd = envify({NODE_ENV: process.env.NODE_ENV || 'production'});
16
17
var SECRET_INTERNALS_NAME = 'React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED';
18
19
-var shimSharedModules = globalShim.configure({
19
+var shimSharedModulesFiles = {
20
'./ReactCurrentOwner': SECRET_INTERNALS_NAME + '.ReactCurrentOwner',
21
'./ReactComponentTreeHook': SECRET_INTERNALS_NAME + '.ReactComponentTreeHook',
22
// The methods we used here are exposed on the main React export.
@@ -26,7 +26,14 @@ var shimSharedModules = globalShim.configure({
26
'./ReactElement': 'React',
27
'./ReactPropTypes': 'React.PropTypes',
28
'./ReactChildren': 'React.Children',
29
-});
29
+};
30
+
31
+// We can access these as absolute or relative. We need to shim both.
32
+for (var key in shimSharedModulesFiles) {
33
+ shimSharedModulesFiles[key.replace(/^\.\//, 'react/lib/')] = shimSharedModulesFiles[key];
34
+}
35
+
36
+var shimSharedModules = globalShim.configure(shimSharedModulesFiles);
37
38
var shimDOMModules = aliasify.configure({
39
'aliases': {
@@ -72,7 +79,7 @@ function simpleBannerify(src) {
79
// Our basic config which we'll add to to make our other builds
80
var basic = {
81
entries: [
75
- './build/modules/ReactUMDEntry.js',
82
+ './build/node_modules/react/lib/ReactUMDEntry.js',
83
],
84
outfile: './build/react.js',
85
debug: false,
@@ -85,7 +92,7 @@ var basic = {
92
93
var min = {
94
entries: [
88
- './build/modules/ReactUMDEntry.js',
95
+ './build/node_modules/react/lib/ReactUMDEntry.js',
96
],
97
outfile: './build/react.min.js',
98
debug: false,
@@ -103,7 +110,7 @@ var min = {
110
111
var addons = {
112
entries: [
106
- './build/modules/ReactWithAddonsUMDEntry.js',
113
+ './build/node_modules/react/lib/ReactWithAddonsUMDEntry.js',
114
],
115
outfile: './build/react-with-addons.js',
116
debug: false,
@@ -117,7 +124,7 @@ var addons = {
124
125
var addonsMin = {
126
entries: [
120
- './build/modules/ReactWithAddonsUMDEntry.js',
127
+ './build/node_modules/react/lib/ReactWithAddonsUMDEntry.js',
128
],
129
outfile: './build/react-with-addons.min.js',
130
debug: false,
@@ -135,7 +142,7 @@ var addonsMin = {
142
// The DOM Builds
143
var dom = {
144
entries: [
138
- './build/modules/ReactDOMUMDEntry.js',
145
+ './build/node_modules/react-dom/lib/ReactDOMUMDEntry.js',
146
],
147
outfile: './build/react-dom.js',
148
debug: false,
@@ -149,7 +156,7 @@ var dom = {
156
157
var domMin = {
158
entries: [
152
- './build/modules/ReactDOMUMDEntry.js',
159
+ './build/node_modules/react-dom/lib/ReactDOMUMDEntry.js',
160
],
161
outfile: './build/react-dom.min.js',
162
debug: false,
@@ -167,7 +174,7 @@ var domMin = {
174
175
var domServer = {
176
entries: [
170
- './build/modules/ReactDOMServerUMDEntry.js',
177
+ './build/node_modules/react-dom/lib/ReactDOMServerUMDEntry.js',
178
],
179
outfile: './build/react-dom-server.js',
180
debug: false,
@@ -181,7 +188,7 @@ var domServer = {
188
189
var domServerMin = {
190
entries: [
184
- './build/modules/ReactDOMServerUMDEntry.js',
191
+ './build/node_modules/react-dom/lib/ReactDOMServerUMDEntry.js',
192
],
193
outfile: './build/react-dom-server.min.js',
194
debug: false,
grunt/tasks/npm-react-addons.js
+19
-2
@@ -6,46 +6,55 @@ var path = require('path');
6
7
var addons = {
8
CSSTransitionGroup: {
9
+ peerDependency: 'react',
10
module: 'ReactCSSTransitionGroup',
11
name: 'css-transition-group',
12
docs: 'animation',
13
},
14
LinkedStateMixin: {
15
+ peerDependency: 'react',
16
module: 'LinkedStateMixin',
17
name: 'linked-state-mixin',
18
docs: 'two-way-binding-helpers',
19
},
20
Perf: {
21
+ peerDependency: 'react-dom',
22
module: 'ReactPerf',
23
name: 'perf',
24
docs: 'perf',
25
},
26
PureRenderMixin: {
27
+ peerDependency: 'react',
28
module: 'ReactComponentWithPureRenderMixin',
29
name: 'pure-render-mixin',
30
docs: 'pure-render-mixin',
31
},
32
TestUtils: {
33
+ peerDependency: 'react-dom',
34
module: 'ReactTestUtils',
35
name: 'test-utils',
36
docs: 'test-utils',
37
},
38
TransitionGroup: {
39
+ peerDependency: 'react',
40
module: 'ReactTransitionGroup',
41
name: 'transition-group',
42
docs: 'animation',
43
},
44
createFragment: {
45
+ peerDependency: 'react',
46
module: 'ReactFragment',
47
method: 'create',
48
name: 'create-fragment',
49
docs: 'create-fragment',
50
},
51
shallowCompare: {
52
+ peerDependency: 'react',
53
module: 'shallowCompare',
54
name: 'shallow-compare',
55
},
56
updates: {
57
+ peerDependency: 'react',
58
module: 'update',
59
name: 'update',
60
docs: 'update',
@@ -54,9 +63,11 @@ var addons = {
63
64
function generateSource(info) {
65
var pieces = [
57
- "module.exports = require('react/lib/",
66
+ 'module.exports = require(\'',
67
+ info.peerDependency,
68
+ '/lib/',
69
info.module,
59
- "')",
70
+ '\')',
71
];
72
if (info.method) {
73
pieces.push('.', info.method);
@@ -78,6 +89,12 @@ function buildReleases() {
89
var pkgData = Object.assign({}, pkgTemplate);
90
pkgData.name = pkgName;
91
92
+ var version = pkgTemplate.peerDependencies.react;
93
+ if (info.peerDependency !== 'react') {
94
+ pkgData.peerDependencies = {};
95
+ pkgData.peerDependencies[info.peerDependency] = version;
96
+ }
97
+
98
grunt.file.mkdir(destDir);
99
var link = info.docs ? info.docs : 'addons';
100
link = `https://facebook.github.io/react/docs/${link}.html`;
grunt/tasks/npm-react-dom.js
+3
@@ -5,6 +5,8 @@ var grunt = require('grunt');
5
6
var src = 'packages/react-dom/';
7
var dest = 'build/packages/react-dom/';
8
+var modSrc = 'build/node_modules/react-dom/lib';
9
+var lib = dest + 'lib/';
10
var dist = dest + 'dist/';
11
var distFiles = [
12
'react-dom.js',
@@ -21,6 +23,7 @@ function buildRelease() {
23
// Copy to build/packages/react-dom
24
var mappings = [].concat(
25
grunt.file.expandMapping('**/*', dest, {cwd: src}),
26
+ grunt.file.expandMapping('**/*', lib, {cwd: modSrc}),
27
grunt.file.expandMapping('{LICENSE,PATENTS}', dest)
28
);
29
mappings.forEach(function(mapping) {
grunt/tasks/npm-react-native.js
+3
@@ -5,6 +5,8 @@ var grunt = require('grunt');
5
6
var src = 'packages/react-native-renderer/';
7
var dest = 'build/packages/react-native-renderer/';
8
+var modSrc = 'build/node_modules/react-native/lib';
9
+var lib = dest + 'lib/';
10
11
function buildRelease() {
12
if (grunt.file.exists(dest)) {
@@ -14,6 +16,7 @@ function buildRelease() {
16
// Copy to build/packages/react-native-renderer
17
var mappings = [].concat(
18
grunt.file.expandMapping('**/*', dest, {cwd: src}),
19
+ grunt.file.expandMapping('**/*', lib, {cwd: modSrc}),
20
grunt.file.expandMapping('{LICENSE,PATENTS}', dest)
21
);
22
mappings.forEach(function(mapping) {
grunt/tasks/npm-react-test.js
+3
@@ -5,6 +5,8 @@ var grunt = require('grunt');
5
6
var src = 'packages/react-test-renderer/';
7
var dest = 'build/packages/react-test-renderer/';
8
+var modSrc = 'build/node_modules/react-test-renderer/lib';
9
+var lib = dest + 'lib/';
10
11
function buildRelease() {
12
if (grunt.file.exists(dest)) {
@@ -14,6 +16,7 @@ function buildRelease() {
16
// Copy to build/packages/react-native-renderer
17
var mappings = [].concat(
18
grunt.file.expandMapping('**/*', dest, {cwd: src}),
19
+ grunt.file.expandMapping('**/*', lib, {cwd: modSrc}),
20
grunt.file.expandMapping('{LICENSE,PATENTS}', dest)
21
);
22
mappings.forEach(function(mapping) {
grunt/tasks/npm-react.js
+1
-1
@@ -5,7 +5,7 @@ var grunt = require('grunt');
5
6
var src = 'packages/react/';
7
var dest = 'build/packages/react/';
8
-var modSrc = 'build/modules/';
8
+var modSrc = 'build/node_modules/react/lib';
9
var lib = dest + 'lib/';
10
var dist = dest + 'dist/';
11
var distFiles = [
gulpfile.js
+167
-17
@@ -13,6 +13,7 @@ var gulp = require('gulp');
13
var babel = require('gulp-babel');
14
var flatten = require('gulp-flatten');
15
var del = require('del');
16
+var merge = require('merge-stream');
17
18
var babelPluginModules = require('fbjs-scripts/babel-6/rewrite-modules');
19
var extractErrors = require('./scripts/error-codes/gulp-extract-errors');
@@ -28,21 +29,113 @@ function getTask(name) {
29
var paths = {
30
react: {
31
src: [
31
- 'src/**/*.js',
32
+ 'src/umd/ReactUMDEntry.js',
33
+ 'src/umd/ReactWithAddonsUMDEntry.js',
34
+ 'src/umd/shims/ReactAddonsDOMDependenciesUMDShim.js',
35
+
36
+ 'src/isomorphic/**/*.js',
37
+ 'src/addons/**/*.js',
38
+
39
+ 'src/ReactVersion.js',
40
+ 'src/shared/**/*.js',
41
+ '!src/shared/vendor/**/*.js',
42
+ '!src/**/__benchmarks__/**/*.js',
43
+ '!src/**/__tests__/**/*.js',
44
+ '!src/**/__mocks__/**/*.js',
45
+ ],
46
+ lib: 'build/node_modules/react/lib',
47
+ },
48
+ reactDOM: {
49
+ src: [
50
+ 'src/umd/ReactDOMUMDEntry.js',
51
+ 'src/umd/ReactDOMServerUMDEntry.js',
52
+
53
+ 'src/renderers/dom/**/*.js',
54
+ 'src/renderers/shared/**/*.js',
55
+ 'src/test/**/*.js', // ReactTestUtils is currently very coupled to DOM.
56
+
57
+ 'src/ReactVersion.js',
58
+ 'src/shared/**/*.js',
59
+ '!src/shared/vendor/**/*.js',
60
+ '!src/**/__benchmarks__/**/*.js',
61
+ '!src/**/__tests__/**/*.js',
62
+ '!src/**/__mocks__/**/*.js',
63
+ ],
64
+ lib: 'build/node_modules/react-dom/lib',
65
+ },
66
+ reactNative: {
67
+ src: [
68
+ 'src/renderers/native/**/*.js',
69
+ 'src/renderers/shared/**/*.js',
70
+
71
+ 'src/ReactVersion.js',
72
+ 'src/shared/**/*.js',
73
+ '!src/shared/vendor/**/*.js',
74
'!src/**/__benchmarks__/**/*.js',
75
'!src/**/__tests__/**/*.js',
76
'!src/**/__mocks__/**/*.js',
35
- '!src/renderers/art/**/*.js',
77
+ ],
78
+ lib: 'build/node_modules/react-native/lib',
79
+ },
80
+ reactTestRenderer: {
81
+ src: [
82
+ 'src/renderers/testing/**/*.js',
83
+ 'src/renderers/shared/**/*.js',
84
+
85
+ 'src/ReactVersion.js',
86
+ 'src/shared/**/*.js',
87
'!src/shared/vendor/**/*.js',
88
+ '!src/**/__benchmarks__/**/*.js',
89
+ '!src/**/__tests__/**/*.js',
90
+ '!src/**/__mocks__/**/*.js',
91
],
38
- lib: 'build/modules',
92
+ lib: 'build/node_modules/react-test-renderer/lib',
93
},
94
};
95
42
-var moduleMap = Object.assign(
96
+var moduleMapBase = Object.assign(
97
{'object-assign': 'object-assign'},
44
- require('fbjs/module-map'),
98
+ require('fbjs/module-map')
99
+);
100
+
101
+var moduleMapReact = Object.assign(
102
+ {
103
+ // Addons needs to reach into DOM internals
104
+ ReactDOM: 'react-dom/lib/ReactDOM',
105
+ ReactInstanceMap: 'react-dom/lib/ReactInstanceMap',
106
+ ReactTestUtils: 'react-dom/lib/ReactTestUtils',
107
+ ReactPerf: 'react-dom/lib/ReactPerf',
108
+ getVendorPrefixedEventName: 'react-dom/lib/getVendorPrefixedEventName',
109
+ },
110
+ moduleMapBase
111
+);
112
+
113
+var rendererSharedState = {
114
+ // Shared state
115
+ ReactCurrentOwner: 'react/lib/ReactCurrentOwner',
116
+ ReactComponentTreeHook: 'react/lib/ReactComponentTreeHook',
117
+
118
+ // TODO: Move to shared since these are actually shared and can be copied.
119
+ ReactPropTypeLocations: 'react/lib/ReactPropTypeLocations',
120
+ ReactPropTypesSecret: 'react/lib/ReactPropTypesSecret',
121
+ checkReactTypeSpec: 'react/lib/checkReactTypeSpec',
122
+
123
+ // TODO: Update the source to just use the React module.
124
+ React: 'react/lib/React',
125
+ ReactElement: 'react/lib/ReactElement',
126
+ ReactPropTypes: 'react/lib/ReactPropTypes',
127
+ ReactChildren: 'react/lib/ReactChildren',
128
+};
129
+
130
+var moduleMapReactDOM = Object.assign(
131
+ {},
132
+ rendererSharedState,
133
+ moduleMapBase
134
+);
135
+
136
+var moduleMapReactNative = Object.assign(
137
{
138
+ // React Native Hooks
139
deepDiffer: 'react-native/lib/deepDiffer',
140
deepFreezeAndThrowOnMutationInDev: 'react-native/lib/deepFreezeAndThrowOnMutationInDev',
141
flattenStyle: 'react-native/lib/flattenStyle',
@@ -52,17 +145,46 @@ var moduleMap = Object.assign(
145
UIManager: 'react-native/lib/UIManager',
146
UIManagerStatTracker: 'react-native/lib/UIManagerStatTracker',
147
View: 'react-native/lib/View',
55
- }
148
+ },
149
+ rendererSharedState,
150
+ moduleMapBase
151
+);
152
+
153
+var moduleMapReactTestRenderer = Object.assign(
154
+ {},
155
+ rendererSharedState,
156
+ moduleMapBase
157
);
158
159
var errorCodeOpts = {
160
errorMapFilePath: 'scripts/error-codes/codes.json',
161
};
162
62
-var babelOpts = {
163
+var babelOptsReact = {
164
+ plugins: [
165
+ devExpressionWithCodes, // this pass has to run before `rewrite-modules`
166
+ [babelPluginModules, {map: moduleMapReact}],
167
+ ],
168
+};
169
+
170
+var babelOptsReactDOM = {
171
+ plugins: [
172
+ devExpressionWithCodes, // this pass has to run before `rewrite-modules`
173
+ [babelPluginModules, {map: moduleMapReactDOM}],
174
+ ],
175
+};
176
+
177
+var babelOptsReactNative = {
178
+ plugins: [
179
+ devExpressionWithCodes, // this pass has to run before `rewrite-modules`
180
+ [babelPluginModules, {map: moduleMapReactNative}],
181
+ ],
182
+};
183
+
184
+var babelOptsReactTestRenderer = {
185
plugins: [
186
devExpressionWithCodes, // this pass has to run before `rewrite-modules`
65
- [babelPluginModules, {map: moduleMap}],
187
+ [babelPluginModules, {map: moduleMapReactTestRenderer}],
188
],
189
};
190
@@ -75,21 +197,49 @@ gulp.task('flow', getTask('flow'));
197
gulp.task('version-check', getTask('version-check'));
198
199
gulp.task('react:clean', function() {
78
- return del([paths.react.lib]);
200
+ return del([
201
+ paths.react.lib,
202
+ paths.reactDOM.lib,
203
+ paths.reactNative.lib,
204
+ paths.reactTestRenderer.lib,
205
+ ]);
206
});
207
208
gulp.task('react:modules', function() {
82
- return gulp
83
- .src(paths.react.src)
84
- .pipe(babel(babelOpts))
85
- .pipe(flatten())
86
- .pipe(gulp.dest(paths.react.lib));
209
+ return merge(
210
+ gulp
211
+ .src(paths.react.src)
212
+ .pipe(babel(babelOptsReact))
213
+ .pipe(flatten())
214
+ .pipe(gulp.dest(paths.react.lib)),
215
+
216
+ gulp
217
+ .src(paths.reactDOM.src)
218
+ .pipe(babel(babelOptsReactDOM))
219
+ .pipe(flatten())
220
+ .pipe(gulp.dest(paths.reactDOM.lib)),
221
+
222
+ gulp
223
+ .src(paths.reactNative.src)
224
+ .pipe(babel(babelOptsReactNative))
225
+ .pipe(flatten())
226
+ .pipe(gulp.dest(paths.reactNative.lib)),
227
+
228
+ gulp
229
+ .src(paths.reactTestRenderer.src)
230
+ .pipe(babel(babelOptsReactTestRenderer))
231
+ .pipe(flatten())
232
+ .pipe(gulp.dest(paths.reactTestRenderer.lib))
233
+ );
234
});
235
236
gulp.task('react:extract-errors', function() {
90
- return gulp
91
- .src(paths.react.src)
92
- .pipe(extractErrors(errorCodeOpts));
237
+ return merge(
238
+ gulp.src(paths.react.src).pipe(extractErrors(errorCodeOpts)),
239
+ gulp.src(paths.reactDOM.src).pipe(extractErrors(errorCodeOpts)),
240
+ gulp.src(paths.reactNative.src).pipe(extractErrors(errorCodeOpts)),
241
+ gulp.src(paths.reactTestRenderer.src).pipe(extractErrors(errorCodeOpts))
242
+ );
243
});
244
245
gulp.task('default', ['react:modules']);
package.json
+1
@@ -61,6 +61,7 @@
61
"gzip-js": "~0.3.2",
62
"jest": "^12.1.1",
63
"loose-envify": "^1.1.0",
64
+ "merge-stream": "^1.0.0",
65
"object-assign": "^4.1.0",
66
"platform": "^1.1.0",
67
"run-sequence": "^1.1.4",
packages/react-dom/index.js
+1
-1
@@ -1,3 +1,3 @@
1
'use strict';
2
3
-module.exports = require('react/lib/ReactDOM');
3
+module.exports = require('./lib/ReactDOM');
packages/react-dom/package.json
+12
-2
@@ -12,7 +12,11 @@
12
"url": "https://github.com/facebook/react/issues"
13
},
14
"homepage": "https://facebook.github.io/react/",
15
- "dependencies": {},
15
+ "dependencies": {
16
+ "fbjs": "^0.8.1",
17
+ "loose-envify": "^1.1.0",
18
+ "object-assign": "^4.1.0"
19
+ },
20
"peerDependencies": {
21
"react": "^16.0.0-alpha"
22
},
@@ -21,7 +25,13 @@
25
"PATENTS",
26
"README.md",
27
"dist/",
28
+ "lib/",
29
"index.js",
30
"server.js"
26
- ]
31
+ ],
32
+ "browserify": {
33
+ "transform": [
34
+ "loose-envify"
35
+ ]
36
+ }
37
}
packages/react-dom/server.js
+1
-1
@@ -1,3 +1,3 @@
1
'use strict';
2
3
-module.exports = require('react/lib/ReactDOMServer');
3
+module.exports = require('./lib/ReactDOMServer');
packages/react-linked-input/LinkedInput.js
+1
-1
@@ -10,7 +10,7 @@
10
'use strict';
11
12
var React = require('react');
13
-var LinkedValueUtils = require('react/lib/LinkedValueUtils');
13
+var LinkedValueUtils = require('react-dom/lib/LinkedValueUtils');
14
15
class LinkedInput extends React.Component {
16
render() {
packages/react-native-renderer/index.js
+1
-1
@@ -1,3 +1,3 @@
1
'use strict';
2
3
-module.exports = require('react/lib/ReactNative');
3
+module.exports = require('./lib/ReactNative');
packages/react-native-renderer/package.json
+6
-1
@@ -14,12 +14,17 @@
14
},
15
"homepage": "https://facebook.github.io/react-native/",
16
"dependencies": {
17
+ "fbjs": "^0.8.1",
18
+ "object-assign": "^4.1.0"
19
+ },
20
+ "peerDependencies": {
21
"react": "^16.0.0-alpha"
22
},
23
"files": [
24
"LICENSE",
25
"PATENTS",
26
"README.md",
23
- "index.js"
27
+ "index.js",
28
+ "lib/"
29
]
30
}
packages/react-test-renderer/index.js
+1
-2
@@ -1,4 +1,3 @@
1
-
1
'use strict';
2
4
-module.exports = require('react/lib/ReactTestRenderer');
3
+module.exports = require('./lib/ReactTestRenderer');
src/renderers/shared/stack/event/SyntheticEvent.js
renamed
src/renderers/testing/ReactTestRenderer.js
-3
@@ -20,8 +20,6 @@ var ReactTestMount = require('ReactTestMount');
20
var ReactTestReconcileTransaction = require('ReactTestReconcileTransaction');
21
var ReactUpdates = require('ReactUpdates');
22
23
-var renderSubtreeIntoContainer = require('renderSubtreeIntoContainer');
24
-
23
/**
24
* Drill down (through composites and empty components) until we get a native or
25
* native text component.
@@ -141,7 +139,6 @@ var ReactTestRenderer = {
139
140
/* eslint-disable camelcase */
141
unstable_batchedUpdates: ReactUpdates.batchedUpdates,
144
- unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer,
142
/* eslint-enable camelcase */
143
};
144