@samitouri / QOS-React-2 / commits / 111731dedd

React reconciler package (#10758)

* Initial commit of react-reconciler bundle * I think it’s working 🙀 * React reconciler: slightly better description and README * Drop react-reconciler version to an unstable release number * Convert to moduleType enum and fix packaging * eslint * s/Renderer/Reconciler in docs * yarn prettier * change names of things in the react-reconciler readme * change predicate * rollup: flip object-assign shimming check * copy noop renderer into react-reconciler fixture * Change reconciler fixture test * prettier * Remove a bunch of Noop test renderer * Delete a bunch of stuff we don’t care about for reconciler teesting. Add flow pragmas for future flow pragma testing * Remove PATENTS * Update Reconciler fixture docs * ReactDOMUnstableNativeDependencies should be ISOMORPHIC * Inline fixture renderer * Make it "RENDERER" * There is no UMD build. It also doesn't need propTypes. * Tweak how the reconciler is built * Record sizes * Update README.md

Dustan Kasten committed Oct 11, 2017 at 14:29 UTC 111731dedd1c8ab2e3033f6ebdac45cb1941cbf7
11 files changed +620 -38
fixtures/reconciler/README.md new
+13
@@ -0,0 +1,13 @@
1 +# React Reconciler Test Fixture
2 +
3 +This folder exists for **React contributors** only.
4 +If you use React you don't need to worry about it.
5 +
6 +These fixtures are a smoke-screen verification that the built React Reconciler distribution works.
7 +
8 +To test, from the project root:
9 +* `yarn build`
10 +* `cd fixtures/reconciler`
11 +* `yarn test`
12 +
13 +They should run as part of the CI check.
fixtures/reconciler/index.js new
+366
@@ -0,0 +1,366 @@
1 +/**
2 + * This is a renderer of React that doesn't have a render target output.
3 + * It is used to test that the react-reconciler package doesn't blow up.
4 + *
5 + * @flow
6 + */
7 +'use strict';
8 +
9 +var React = require('react');
10 +var assert = require('assert');
11 +var ReactFiberReconciler = require('react-reconciler');
12 +var emptyObject = require('fbjs/lib/emptyObject');
13 +var assert = require('assert');
14 +
15 +const UPDATE_SIGNAL = {};
16 +
17 +var scheduledCallback = null;
18 +
19 +type Container = {rootID: string, children: Array<Instance | TextInstance>};
20 +type Props = {prop: any, hidden?: boolean};
21 +type Instance = {|
22 + type: string,
23 + id: number,
24 + children: Array<Instance | TextInstance>,
25 + prop: any,
26 +|};
27 +type TextInstance = {|text: string, id: number|};
28 +
29 +var instanceCounter = 0;
30 +
31 +function appendChild(
32 + parentInstance: Instance | Container,
33 + child: Instance | TextInstance
34 +): void {
35 + const index = parentInstance.children.indexOf(child);
36 + if (index !== -1) {
37 + parentInstance.children.splice(index, 1);
38 + }
39 + parentInstance.children.push(child);
40 +}
41 +
42 +function insertBefore(
43 + parentInstance: Instance | Container,
44 + child: Instance | TextInstance,
45 + beforeChild: Instance | TextInstance
46 +): void {
47 + const index = parentInstance.children.indexOf(child);
48 + if (index !== -1) {
49 + parentInstance.children.splice(index, 1);
50 + }
51 + const beforeIndex = parentInstance.children.indexOf(beforeChild);
52 + if (beforeIndex === -1) {
53 + throw new Error('This child does not exist.');
54 + }
55 + parentInstance.children.splice(beforeIndex, 0, child);
56 +}
57 +
58 +function removeChild(
59 + parentInstance: Instance | Container,
60 + child: Instance | TextInstance
61 +): void {
62 + const index = parentInstance.children.indexOf(child);
63 + if (index === -1) {
64 + throw new Error('This child does not exist.');
65 + }
66 + parentInstance.children.splice(index, 1);
67 +}
68 +
69 +var NoopRenderer = ReactFiberReconciler({
70 + getRootHostContext() {
71 + return emptyObject;
72 + },
73 +
74 + getChildHostContext() {
75 + return emptyObject;
76 + },
77 +
78 + getPublicInstance(instance) {
79 + return instance;
80 + },
81 +
82 + createInstance(type: string, props: Props): Instance {
83 + const inst = {
84 + id: instanceCounter++,
85 + type: type,
86 + children: [],
87 + prop: props.prop,
88 + };
89 + // Hide from unit tests
90 + Object.defineProperty(inst, 'id', {value: inst.id, enumerable: false});
91 + return inst;
92 + },
93 +
94 + appendInitialChild(
95 + parentInstance: Instance,
96 + child: Instance | TextInstance
97 + ): void {
98 + parentInstance.children.push(child);
99 + },
100 +
101 + finalizeInitialChildren(
102 + domElement: Instance,
103 + type: string,
104 + props: Props
105 + ): boolean {
106 + return false;
107 + },
108 +
109 + prepareUpdate(
110 + instance: Instance,
111 + type: string,
112 + oldProps: Props,
113 + newProps: Props
114 + ): null | {} {
115 + return UPDATE_SIGNAL;
116 + },
117 +
118 + commitMount(instance: Instance, type: string, newProps: Props): void {
119 + // Noop
120 + },
121 +
122 + commitUpdate(
123 + instance: Instance,
124 + updatePayload: Object,
125 + type: string,
126 + oldProps: Props,
127 + newProps: Props
128 + ): void {
129 + instance.prop = newProps.prop;
130 + },
131 +
132 + shouldSetTextContent(type: string, props: Props): boolean {
133 + return (
134 + typeof props.children === 'string' || typeof props.children === 'number'
135 + );
136 + },
137 +
138 + resetTextContent(instance: Instance): void {},
139 +
140 + shouldDeprioritizeSubtree(type: string, props: Props): boolean {
141 + return !!props.hidden;
142 + },
143 +
144 + now: Date.now,
145 +
146 + createTextInstance(
147 + text: string,
148 + rootContainerInstance: Container,
149 + hostContext: Object,
150 + internalInstanceHandle: Object
151 + ): TextInstance {
152 + var inst = {text: text, id: instanceCounter++};
153 + // Hide from unit tests
154 + Object.defineProperty(inst, 'id', {value: inst.id, enumerable: false});
155 + return inst;
156 + },
157 +
158 + commitTextUpdate(
159 + textInstance: TextInstance,
160 + oldText: string,
161 + newText: string
162 + ): void {
163 + textInstance.text = newText;
164 + },
165 +
166 + appendChild: appendChild,
167 + appendChildToContainer: appendChild,
168 + insertBefore: insertBefore,
169 + insertInContainerBefore: insertBefore,
170 + removeChild: removeChild,
171 + removeChildFromContainer: removeChild,
172 +
173 + scheduleDeferredCallback(callback) {
174 + if (scheduledCallback) {
175 + throw new Error(
176 + 'Scheduling a callback twice is excessive. Instead, keep track of ' +
177 + 'whether the callback has already been scheduled.'
178 + );
179 + }
180 + scheduledCallback = callback;
181 + },
182 +
183 + prepareForCommit(): void {},
184 +
185 + resetAfterCommit(): void {},
186 +});
187 +
188 +var rootContainers = new Map();
189 +var roots = new Map();
190 +var DEFAULT_ROOT_ID = '<default>';
191 +
192 +let yieldedValues = null;
193 +
194 +function* flushUnitsOfWork(n: number): Generator<Array<mixed>, void, void> {
195 + var didStop = false;
196 + while (!didStop && scheduledCallback !== null) {
197 + var cb = scheduledCallback;
198 + scheduledCallback = null;
199 + yieldedValues = null;
200 + var unitsRemaining = n;
201 + cb({
202 + timeRemaining() {
203 + if (yieldedValues !== null) {
204 + return 0;
205 + }
206 + if (unitsRemaining-- > 0) {
207 + return 999;
208 + }
209 + didStop = true;
210 + return 0;
211 + },
212 + });
213 +
214 + if (yieldedValues !== null) {
215 + const values = yieldedValues;
216 + yieldedValues = null;
217 + yield values;
218 + }
219 + }
220 +}
221 +
222 +var Noop = {
223 + getChildren(rootID: string = DEFAULT_ROOT_ID) {
224 + const container = rootContainers.get(rootID);
225 + if (container) {
226 + return container.children;
227 + } else {
228 + return null;
229 + }
230 + },
231 +
232 + // Shortcut for testing a single root
233 + render(element: React$Element<any>, callback: ?Function) {
234 + Noop.renderToRootWithID(element, DEFAULT_ROOT_ID, callback);
235 + },
236 +
237 + renderToRootWithID(
238 + element: React$Element<any>,
239 + rootID: string,
240 + callback: ?Function
241 + ) {
242 + let root = roots.get(rootID);
243 + if (!root) {
244 + const container = {rootID: rootID, children: []};
245 + rootContainers.set(rootID, container);
246 + root = NoopRenderer.createContainer(container);
247 + roots.set(rootID, root);
248 + }
249 + NoopRenderer.updateContainer(element, root, null, callback);
250 + },
251 +
252 + flush(): Array<mixed> {
253 + return Noop.flushUnitsOfWork(Infinity);
254 + },
255 +
256 + flushUnitsOfWork(n: number): Array<mixed> {
257 + let values = [];
258 + for (const value of flushUnitsOfWork(n)) {
259 + values.push(...value);
260 + }
261 + return values;
262 + },
263 +
264 + batchedUpdates: NoopRenderer.batchedUpdates,
265 +
266 + deferredUpdates: NoopRenderer.deferredUpdates,
267 +
268 + unbatchedUpdates: NoopRenderer.unbatchedUpdates,
269 +
270 + flushSync: NoopRenderer.flushSync,
271 +};
272 +
273 +type TestProps = {|
274 + active: boolean,
275 +|};
276 +type TestState = {|
277 + counter: number,
278 +|};
279 +
280 +let instance = null;
281 +class Test extends React.Component<TestProps, TestState> {
282 + state = {counter: 0};
283 + increment() {
284 + this.setState(({counter}) => ({
285 + counter: counter + 1,
286 + }));
287 + }
288 + render() {
289 + return [this.props.active ? 'Active' : 'Inactive', this.state.counter];
290 + }
291 +}
292 +const Children = props => props.children;
293 +Noop.render(
294 + <main>
295 + <div>Hello</div>
296 + <Children>
297 + Hello world
298 + <span>{'Number '}{42}</span>
299 + <Test active={true} ref={t => (instance = t)} />
300 + </Children>
301 + </main>
302 +);
303 +Noop.flush();
304 +const actual1 = Noop.getChildren();
305 +const expected1 = [
306 + {
307 + type: 'main',
308 + children: [
309 + {type: 'div', children: [], prop: undefined},
310 + {text: 'Hello world'},
311 + {
312 + type: 'span',
313 + children: [{text: 'Number '}, {text: '42'}],
314 + prop: undefined,
315 + },
316 + {text: 'Active'},
317 + {text: '0'},
318 + ],
319 + prop: undefined,
320 + },
321 +];
322 +assert.deepEqual(
323 + actual1,
324 + expected1,
325 + 'Error. Noop.getChildren() returned unexpected value.\nExpected:\ ' +
326 + JSON.stringify(expected1, null, 2) +
327 + '\n\nActual:\n ' +
328 + JSON.stringify(actual1, null, 2)
329 +);
330 +
331 +if (instance === null) {
332 + throw new Error('Expected instance to exist.');
333 +}
334 +
335 +instance.increment();
336 +Noop.flush();
337 +const actual2 = Noop.getChildren();
338 +const expected2 = [
339 + {
340 + type: 'main',
341 + children: [
342 + {type: 'div', children: [], prop: undefined},
343 + {text: 'Hello world'},
344 + {
345 + type: 'span',
346 + children: [{text: 'Number '}, {text: '42'}],
347 + prop: undefined,
348 + },
349 + {text: 'Active'},
350 + {text: '1'},
351 + ],
352 + prop: undefined,
353 + },
354 +];
355 +assert.deepEqual(
356 + actual2,
357 + expected2,
358 + 'Error. Noop.getChildren() returned unexpected value.\nExpected:\ ' +
359 + JSON.stringify(expected2, null, 2) +
360 + '\n\nActual:\n ' +
361 + JSON.stringify(actual2, null, 2)
362 +);
363 +
364 +const beginGreen = '\u001b[32m';
365 +const endGreen = '\u001b[39m';
366 +console.log(beginGreen + 'Reconciler package is OK!' + endGreen);
fixtures/reconciler/package.json new
+10
@@ -0,0 +1,10 @@
1 +{
2 + "name": "react-fixtures",
3 + "version": "0.1.0",
4 + "private": true,
5 + "scripts": {
6 + "test:dev": "NODE_PATH=../../build/packages ../../node_modules/.bin/babel-node ./index",
7 + "test:prod": "NODE_PATH=../../build/packages NODE_ENV=production ../../node_modules/.bin/babel-node ./index",
8 + "test": "npm run test:dev && npm run test:prod"
9 + }
10 +}
packages/react-reconciler/README.md new
+39
@@ -0,0 +1,39 @@
1 +# react-reconciler
2 +
3 +This is an experimental package for creating custom React renderers.
4 +
5 +**Its API is not as stable as that of React, React Native, or React DOM, and does not follow the common versioning scheme.**
6 +
7 +**Use it at your own risk.**
8 +
9 +## API
10 +
11 +```js
12 +var Reconciler = require('react-reconciler');
13 +
14 +var ReconcilerConfig = {
15 + // You'll need to implement some methods here.
16 + // See below for more information and examples.
17 +};
18 +
19 +var MyRenderer = Reconciler(ReconcilerConfig);
20 +
21 +var RendererPublicAPI = {
22 + render(element, container, callback) {
23 + // Call MyRenderer.updateContainer() to schedule changes on the roots.
24 + // See ReactDOM, React Native, or React ART for practical examples.
25 + }
26 +};
27 +
28 +module.exports = RendererPublicAPI;
29 +```
30 +
31 +## Practical Examples
32 +
33 +* [React ART](https://github.com/facebook/react/blob/master/src/renderers/art/ReactARTFiberEntry.js)
34 +* [React DOM](https://github.com/facebook/react/blob/master/src/fb/ReactDOMFiberFBEntry.js)
35 +* [React Native](https://github.com/facebook/react/blob/master/src/renderers/native/ReactNativeFiberRenderer.js)
36 +
37 +If these links break please file an issue and we’ll fix them. They intentionally link to the latest versions since the API is still evolving.
38 +
39 +This [third-party tutorial](https://github.com/nitin42/Making-a-custom-React-renderer) is relatively up-to-date and may be helpful.
packages/react-reconciler/index.js new
+7
@@ -0,0 +1,7 @@
1 +'use strict';
2 +
3 +if (process.env.NODE_ENV === 'production') {
4 + module.exports = require('./cjs/react-reconciler.production.min.js');
5 +} else {
6 + module.exports = require('./cjs/react-reconciler.development.js');
7 +}
packages/react-reconciler/package.json new
+35
@@ -0,0 +1,35 @@
1 +{
2 + "name": "react-reconciler",
3 + "description": "React package for creating custom renderers.",
4 + "version": "0.1.0",
5 + "keywords": [
6 + "react"
7 + ],
8 + "homepage": "https://facebook.github.io/react/",
9 + "bugs": "https://github.com/facebook/react/issues",
10 + "license": "MIT",
11 + "files": [
12 + "LICENSE",
13 + "README.md",
14 + "index.js",
15 + "cjs/"
16 + ],
17 + "main": "index.js",
18 + "repository": "facebook/react",
19 + "engines": {
20 + "node": ">=0.10.0"
21 + },
22 + "peerDependencies": {
23 + "react": "^16.0.0"
24 + },
25 + "dependencies": {
26 + "fbjs": "^0.8.16",
27 + "loose-envify": "^1.1.0",
28 + "object-assign": "^4.1.1"
29 + },
30 + "browserify": {
31 + "transform": [
32 + "loose-envify"
33 + ]
34 + }
35 +}
scripts/circleci/build.sh
+5 -1
@@ -3,4 +3,8 @@
3 set -e
4
5 npm run build -- --extract-errors
6 -git checkout -- scripts/error-codes/codes.json
\ No newline at end of file
6 +git checkout -- scripts/error-codes/codes.json
7 +
8 +# Check that the standalone reconciler isn't borked
9 +cd fixtures/reconciler
10 +yarn test
scripts/rollup/build.js
+72 -11
@@ -34,6 +34,8 @@ const FB_PROD = Bundles.bundleTypes.FB_PROD;
34 const RN_DEV = Bundles.bundleTypes.RN_DEV;
35 const RN_PROD = Bundles.bundleTypes.RN_PROD;
36
37 +const RECONCILER = Bundles.moduleTypes.RECONCILER;
38 +
39 const reactVersion = require('../../package.json').version;
40 const requestedBundleTypes = (argv.type || '')
41 .split(',')
@@ -78,7 +80,13 @@ function getHeaderSanityCheck(bundleType, hasteName) {
80 }
81 }
82
81 -function getBanner(bundleType, hasteName, filename) {
83 +function getBanner(bundleType, hasteName, filename, moduleType) {
84 + if (moduleType === RECONCILER) {
85 + // Standalone reconciler is only used by third-party renderers.
86 + // It is handled separately.
87 + return getReconcilerBanner(bundleType, filename);
88 + }
89 +
90 switch (bundleType) {
91 // UMDs are not wrapped in conditions.
92 case UMD_DEV:
@@ -112,7 +120,13 @@ function getBanner(bundleType, hasteName, filename) {
120 }
121 }
122
115 -function getFooter(bundleType) {
123 +function getFooter(bundleType, filename, moduleType) {
124 + if (moduleType === RECONCILER) {
125 + // Standalone reconciler is only used by third-party renderers.
126 + // It is handled separately.
127 + return getReconcilerFooter(bundleType);
128 + }
129 +
130 // Only need a footer if getBanner() has an opening brace.
131 switch (bundleType) {
132 // Non-UMD DEV bundles need conditions to help weak dead code elimination.
@@ -125,7 +139,46 @@ function getFooter(bundleType) {
139 }
140 }
141
128 -function updateBabelConfig(babelOpts, bundleType) {
142 +// TODO: this is extremely gross.
143 +// But it only affects the "experimental" standalone reconciler build.
144 +// The goal is to avoid having any shared state between renderers sharing it on npm.
145 +// Ideally we should just remove shared state in all Fiber modules and then lint against it.
146 +// But for now, we store the exported function in a variable, and then put the rest of the code
147 +// into a closure that makes all module-level state private to each call.
148 +const RECONCILER_WRAPPER_INTRO = `var $$$reconciler;\nmodule.exports = function(config) {\n`;
149 +const RECONCILER_WRAPPER_OUTRO = `return ($$$reconciler || ($$$reconciler = module.exports))(config);\n};\n`;
150 +
151 +function getReconcilerBanner(bundleType, filename) {
152 + let banner = `${Header.getHeader(filename, reactVersion)}\n\n'use strict';\n\n\n`;
153 + switch (bundleType) {
154 + case NODE_DEV:
155 + banner += `if (process.env.NODE_ENV !== "production") {\n${RECONCILER_WRAPPER_INTRO}`;
156 + break;
157 + case NODE_PROD:
158 + banner += RECONCILER_WRAPPER_INTRO;
159 + break;
160 + default:
161 + throw new Error(
162 + 'Standalone reconciler does not support ' + bundleType + ' builds.'
163 + );
164 + }
165 + return banner;
166 +}
167 +
168 +function getReconcilerFooter(bundleType) {
169 + switch (bundleType) {
170 + case NODE_DEV:
171 + return `\n${RECONCILER_WRAPPER_OUTRO}\n}`;
172 + case NODE_PROD:
173 + return `\n${RECONCILER_WRAPPER_OUTRO}`;
174 + default:
175 + throw new Error(
176 + 'Standalone reconciler does not support ' + bundleType + ' builds.'
177 + );
178 + }
179 +}
180 +
181 +function updateBabelConfig(babelOpts, bundleType, filename) {
182 switch (bundleType) {
183 case FB_DEV:
184 case FB_PROD:
@@ -166,16 +219,23 @@ function handleRollupWarnings(warning) {
219 console.warn(warning.message || warning);
220 }
221
169 -function updateBundleConfig(config, filename, format, bundleType, hasteName) {
222 +function updateBundleConfig(
223 + config,
224 + filename,
225 + format,
226 + bundleType,
227 + hasteName,
228 + moduleType
229 +) {
230 return Object.assign({}, config, {
171 - banner: getBanner(bundleType, hasteName, filename),
231 + banner: getBanner(bundleType, hasteName, filename, moduleType),
232 dest: Packaging.getPackageDestination(
233 config,
234 bundleType,
235 filename,
236 hasteName
237 ),
178 - footer: getFooter(bundleType),
238 + footer: getFooter(bundleType, filename, moduleType),
239 format,
240 interop: false,
241 });
@@ -309,7 +369,7 @@ function getPlugins(
369 filename,
370 bundleType,
371 hasteName,
312 - isRenderer,
372 + moduleType,
373 manglePropertiesOnProd,
374 useFiber,
375 modulesToStub
@@ -317,7 +377,7 @@ function getPlugins(
377 const plugins = [
378 babel(updateBabelConfig(babelOpts, bundleType)),
379 alias(
320 - Modules.getAliases(paths, bundleType, isRenderer, argv['extract-errors'])
380 + Modules.getAliases(paths, bundleType, moduleType, argv['extract-errors'])
381 ),
382 ];
383
@@ -453,7 +513,7 @@ function createBundle(bundle, bundleType) {
513 external: Modules.getExternalModules(
514 bundle.externals,
515 bundleType,
456 - bundle.isRenderer
516 + bundle.moduleType
517 ),
518 onwarn: handleRollupWarnings,
519 plugins: getPlugins(
@@ -463,7 +523,7 @@ function createBundle(bundle, bundleType) {
523 filename,
524 bundleType,
525 bundle.hasteName,
466 - bundle.isRenderer,
526 + bundle.moduleType,
527 bundle.manglePropertiesOnProd,
528 bundle.useFiber,
529 bundle.modulesToStub
@@ -476,7 +536,8 @@ function createBundle(bundle, bundleType) {
536 filename,
537 format,
538 bundleType,
479 - bundle.hasteName
539 + bundle.hasteName,
540 + bundle.moduleType
541 )
542 )
543 )
scripts/rollup/bundles.js
+48 -11
@@ -20,6 +20,16 @@ const FB_PROD = bundleTypes.FB_PROD;
20 const RN_DEV = bundleTypes.RN_DEV;
21 const RN_PROD = bundleTypes.RN_PROD;
22
23 +const moduleTypes = {
24 + ISOMORPHIC: 'ISOMORPHIC',
25 + RENDERER: 'RENDERER',
26 + RECONCILER: 'RECONCILER',
27 +};
28 +
29 +const ISOMORPHIC = moduleTypes.ISOMORPHIC;
30 +const RENDERER = moduleTypes.RENDERER;
31 +const RECONCILER = moduleTypes.RECONCILER;
32 +
33 const babelOptsReact = {
34 exclude: 'node_modules/**',
35 presets: [],
@@ -51,7 +61,7 @@ const bundles = [
61 ],
62 fbEntry: 'src/isomorphic/ReactEntry',
63 hasteName: 'React',
54 - isRenderer: false,
64 + moduleType: ISOMORPHIC,
65 label: 'core',
66 manglePropertiesOnProd: false,
67 name: 'react',
@@ -79,7 +89,7 @@ const bundles = [
89 externals: ['prop-types', 'prop-types/checkPropTypes'],
90 fbEntry: 'src/fb/ReactDOMFiberFBEntry',
91 hasteName: 'ReactDOMFiber',
82 - isRenderer: true,
92 + moduleType: RENDERER,
93 label: 'dom-fiber',
94 manglePropertiesOnProd: false,
95 name: 'react-dom',
@@ -112,7 +122,7 @@ const bundles = [
122 ],
123 fbEntry: 'src/renderers/dom/test/ReactTestUtilsEntry',
124 hasteName: 'ReactTestUtils',
115 - isRenderer: true,
125 + moduleType: RENDERER,
126 label: 'test-utils',
127 manglePropertiesOnProd: false,
128 name: 'react-dom/test-utils',
@@ -147,7 +157,7 @@ const bundles = [
157 ],
158 fbEntry: 'src/renderers/dom/shared/ReactDOMUnstableNativeDependenciesEntry',
159 hasteName: 'ReactDOMUnstableNativeDependencies',
150 - isRenderer: false,
160 + moduleType: RENDERER,
161 label: 'dom-unstable-native-dependencies',
162 manglePropertiesOnProd: false,
163 name: 'react-dom/unstable-native-dependencies',
@@ -176,7 +186,7 @@ const bundles = [
186 externals: ['prop-types', 'prop-types/checkPropTypes'],
187 fbEntry: 'src/renderers/dom/ReactDOMServerBrowserEntry',
188 hasteName: 'ReactDOMServer',
179 - isRenderer: true,
189 + moduleType: RENDERER,
190 label: 'dom-server-browser',
191 manglePropertiesOnProd: false,
192 name: 'react-dom/server.browser',
@@ -201,7 +211,7 @@ const bundles = [
211 },
212 entry: 'src/renderers/dom/ReactDOMServerNodeEntry',
213 externals: ['prop-types', 'prop-types/checkPropTypes', 'stream'],
204 - isRenderer: true,
214 + moduleType: RENDERER,
215 label: 'dom-server-server-node',
216 manglePropertiesOnProd: false,
217 name: 'react-dom/server.node',
@@ -237,7 +247,7 @@ const bundles = [
247 ],
248 fbEntry: 'src/renderers/art/ReactARTFiberEntry',
249 hasteName: 'ReactARTFiber',
240 - isRenderer: true,
250 + moduleType: RENDERER,
251 label: 'art-fiber',
252 manglePropertiesOnProd: false,
253 name: 'react-art',
@@ -274,7 +284,7 @@ const bundles = [
284 'prop-types/checkPropTypes',
285 ],
286 hasteName: 'ReactNativeFiber',
277 - isRenderer: true,
287 + moduleType: RENDERER,
288 label: 'native-fiber',
289 manglePropertiesOnProd: false,
290 name: 'react-native-renderer',
@@ -335,7 +345,7 @@ const bundles = [
345 externals: ['prop-types/checkPropTypes'],
346 fbEntry: 'src/renderers/testing/ReactTestRendererFiberEntry',
347 hasteName: 'ReactTestRendererFiber',
338 - isRenderer: true,
348 + moduleType: RENDERER,
349 label: 'test-fiber',
350 manglePropertiesOnProd: false,
351 name: 'react-test-renderer',
@@ -364,7 +374,7 @@ const bundles = [
374 ],
375 fbEntry: 'src/renderers/testing/ReactShallowRendererEntry',
376 hasteName: 'ReactShallowRenderer',
367 - isRenderer: true,
377 + moduleType: RENDERER,
378 label: 'shallow-renderer',
379 manglePropertiesOnProd: false,
380 name: 'react-test-renderer/shallow',
@@ -389,7 +399,7 @@ const bundles = [
399 },
400 entry: 'src/renderers/noop/ReactNoopEntry',
401 externals: ['prop-types/checkPropTypes', 'jest-matchers'],
392 - isRenderer: true,
402 + moduleType: RENDERER,
403 label: 'noop-fiber',
404 manglePropertiesOnProd: false,
405 name: 'react-noop-renderer',
@@ -401,6 +411,32 @@ const bundles = [
411 'src/shared/**/*.js',
412 ],
413 },
414 +
415 + /******* React Reconciler *******/
416 + {
417 + babelOpts: babelOptsReact,
418 + bundleTypes: [NODE_DEV, NODE_PROD],
419 + config: {
420 + destDir: 'build/',
421 + globals: {
422 + react: 'React',
423 + },
424 + moduleName: 'ReactReconciler',
425 + sourceMap: false,
426 + },
427 + entry: 'src/renderers/shared/fiber/ReactFiberReconciler',
428 + externals: ['react', 'prop-types/checkPropTypes'],
429 + moduleType: RECONCILER,
430 + label: 'react-reconciler',
431 + manglePropertiesOnProd: false,
432 + name: 'react-reconciler',
433 + paths: [
434 + 'src/renderers/shared/**/*.js',
435 +
436 + 'src/ReactVersion.js',
437 + 'src/shared/**/*.js',
438 + ],
439 + },
440 ];
441
442 // Based on deep-freeze by substack (public domain)
@@ -423,5 +459,6 @@ deepFreeze(bundles);
459
460 module.exports = {
461 bundleTypes,
462 + moduleTypes,
463 bundles,
464 };
scripts/rollup/modules.js
+13 -11
@@ -4,6 +4,7 @@ const resolve = require('path').resolve;
4 const basename = require('path').basename;
5 const sync = require('glob').sync;
6 const bundleTypes = require('./bundles').bundleTypes;
7 +const moduleTypes = require('./bundles').moduleTypes;
8 const extractErrorCodes = require('../error-codes/extract-errors');
9
10 const exclude = [
@@ -21,6 +22,8 @@ const FB_PROD = bundleTypes.FB_PROD;
22 const RN_DEV = bundleTypes.RN_DEV;
23 const RN_PROD = bundleTypes.RN_PROD;
24
25 +const ISOMORPHIC = moduleTypes.ISOMORPHIC;
26 +
27 const errorCodeOpts = {
28 errorMapFilePath: 'scripts/error-codes/codes.json',
29 };
@@ -87,7 +90,7 @@ function createModuleMap(paths, extractErrors, bundleType) {
90 return moduleMap;
91 }
92
90 -function getNodeModules(bundleType, isRenderer) {
93 +function getNodeModules(bundleType, moduleType) {
94 // rather than adding the rollup node resolve plugin,
95 // we can instead deal with the only node module that is used
96 // for UMD bundles - object-assign
@@ -97,9 +100,9 @@ function getNodeModules(bundleType, isRenderer) {
100 return {
101 // Bundle object-assign once in the isomorphic React, and then use
102 // that from the renderer UMD. Avoids bundling it in both UMDs.
100 - 'object-assign': isRenderer
101 - ? resolve('./scripts/rollup/shims/rollup/assign.js')
102 - : resolve('./node_modules/object-assign/index.js'),
103 + 'object-assign': moduleType === ISOMORPHIC
104 + ? resolve('./node_modules/object-assign/index.js')
105 + : resolve('./scripts/rollup/shims/rollup/assign.js'),
106 // include the ART package modules directly by aliasing them from node_modules
107 'art/modes/current': resolve('./node_modules/art/modes/current.js'),
108 'art/modes/fast-noSideEffects': resolve(
@@ -136,7 +139,7 @@ function ignoreReactNativeModules() {
139 ];
140 }
141
139 -function getExternalModules(externals, bundleType, isRenderer) {
142 +function getExternalModules(externals, bundleType, moduleType) {
143 // external modules tell Rollup that we should not attempt
144 // to bundle these modules and instead treat them as
145 // external dependencies to the bundle. so for CJS bundles
@@ -144,11 +147,10 @@ function getExternalModules(externals, bundleType, isRenderer) {
147 // the top of the bundle. for UMD bundles this means having
148 // both a require and a global check for them
149 let externalModules = externals.slice();
147 -
150 switch (bundleType) {
151 case UMD_DEV:
152 case UMD_PROD:
151 - if (isRenderer) {
153 + if (moduleType !== ISOMORPHIC) {
154 externalModules.push('react');
155 }
156 break;
@@ -158,7 +160,7 @@ function getExternalModules(externals, bundleType, isRenderer) {
160 case RN_PROD:
161 fbjsModules.forEach(module => externalModules.push(module));
162 externalModules.push('object-assign');
161 - if (isRenderer) {
163 + if (moduleType !== ISOMORPHIC) {
164 externalModules.push('react');
165 }
166 break;
@@ -168,7 +170,7 @@ function getExternalModules(externals, bundleType, isRenderer) {
170 externalModules.push('object-assign');
171 externalModules.push('ReactCurrentOwner');
172 externalModules.push('lowPriorityWarning');
171 - if (isRenderer) {
173 + if (moduleType !== ISOMORPHIC) {
174 externalModules.push('React');
175 if (externalModules.indexOf('react-dom') > -1) {
176 externalModules.push('ReactDOM');
@@ -282,7 +284,7 @@ function replaceBundleStubModules(bundleModulesToStub) {
284 return stubbedModules;
285 }
286
285 -function getAliases(paths, bundleType, isRenderer, extractErrors) {
287 +function getAliases(paths, bundleType, moduleType, extractErrors) {
288 return Object.assign(
289 createModuleMap(
290 paths,
@@ -290,7 +292,7 @@ function getAliases(paths, bundleType, isRenderer, extractErrors) {
292 bundleType
293 ),
294 getInternalModules(),
293 - getNodeModules(bundleType, isRenderer),
295 + getNodeModules(bundleType, moduleType),
296 getFbjsModuleAliases(bundleType)
297 );
298 }
scripts/rollup/results.json
+12 -4
@@ -57,12 +57,12 @@
57 "gzip": 11028
58 },
59 "react-dom-unstable-native-dependencies.development.js (UMD_DEV)": {
60 - "size": 86854,
61 - "gzip": 21985
60 + "size": 84930,
61 + "gzip": 21288
62 },
63 "react-dom-unstable-native-dependencies.production.min.js (UMD_PROD)": {
64 - "size": 15251,
65 - "gzip": 5010
64 + "size": 14441,
65 + "gzip": 4650
66 },
67 "react-dom-unstable-native-dependencies.development.js (NODE_DEV)": {
68 "size": 80723,
@@ -207,6 +207,14 @@
207 "react-dom-test-utils.production.min.js (NODE_PROD)": {
208 "size": 11608,
209 "gzip": 4241
210 + },
211 + "react-reconciler.development.js (NODE_DEV)": {
212 + "size": 279927,
213 + "gzip": 58576
214 + },
215 + "react-reconciler.production.min.js (NODE_PROD)": {
216 + "size": 38630,
217 + "gzip": 12165
218 }
219 }
220 }
\ No newline at end of file