Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Reconciler Package #10758

Merged
merged 25 commits into from
Oct 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
265b3c0
Initial commit of react-reconciler bundle
iamdustan Sep 20, 2017
21853d5
I think it’s working 🙀
iamdustan Sep 20, 2017
703c512
React reconciler: slightly better description and README
iamdustan Sep 20, 2017
d4deee8
Drop react-reconciler version to an unstable release number
iamdustan Sep 21, 2017
a64e9e9
Convert to moduleType enum and fix packaging
iamdustan Sep 21, 2017
ac1e603
eslint
iamdustan Sep 21, 2017
1165ee8
s/Renderer/Reconciler in docs
iamdustan Sep 22, 2017
2018b79
yarn prettier
iamdustan Sep 22, 2017
3f7a6b6
change names of things in the react-reconciler readme
iamdustan Sep 22, 2017
b1ace5c
change predicate
iamdustan Sep 25, 2017
e7d4f44
rollup: flip object-assign shimming check
iamdustan Sep 25, 2017
34551f7
copy noop renderer into react-reconciler fixture
iamdustan Sep 25, 2017
8f50bf3
Change reconciler fixture test
iamdustan Sep 28, 2017
8dc59e6
prettier
iamdustan Sep 28, 2017
80f4a6b
Remove a bunch of Noop test renderer
iamdustan Sep 28, 2017
9d5345d
Delete a bunch of stuff we don’t care about for reconciler teesting. …
iamdustan Sep 28, 2017
6de269f
Remove PATENTS
gaearon Oct 10, 2017
f767f0e
Update Reconciler fixture docs
iamdustan Oct 11, 2017
d4842f0
ReactDOMUnstableNativeDependencies should be ISOMORPHIC
iamdustan Oct 11, 2017
d10506b
Inline fixture renderer
iamdustan Oct 11, 2017
ec18863
Make it "RENDERER"
gaearon Oct 11, 2017
5c6510d
There is no UMD build. It also doesn't need propTypes.
gaearon Oct 11, 2017
8a3ffdc
Tweak how the reconciler is built
gaearon Oct 11, 2017
a935605
Record sizes
gaearon Oct 11, 2017
04ec04e
Update README.md
gaearon Oct 11, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions fixtures/reconciler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# React Reconciler Test Fixture

This folder exists for **React contributors** only.
If you use React you don't need to worry about it.

These fixtures are a smoke-screen verification that the built React Reconciler distribution works.

To test, from the project root:
* `yarn build`
* `cd fixtures/reconciler`
* `yarn test`

They should run as part of the CI check.
366 changes: 366 additions & 0 deletions fixtures/reconciler/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
/**
* This is a renderer of React that doesn't have a render target output.
* It is used to test that the react-reconciler package doesn't blow up.
*
* @flow
*/
'use strict';

var React = require('react');
var assert = require('assert');
var ReactFiberReconciler = require('react-reconciler');
var emptyObject = require('fbjs/lib/emptyObject');
var assert = require('assert');

const UPDATE_SIGNAL = {};

var scheduledCallback = null;

type Container = {rootID: string, children: Array<Instance | TextInstance>};
type Props = {prop: any, hidden?: boolean};
type Instance = {|
type: string,
id: number,
children: Array<Instance | TextInstance>,
prop: any,
|};
type TextInstance = {|text: string, id: number|};

var instanceCounter = 0;

function appendChild(
parentInstance: Instance | Container,
child: Instance | TextInstance
): void {
const index = parentInstance.children.indexOf(child);
if (index !== -1) {
parentInstance.children.splice(index, 1);
}
parentInstance.children.push(child);
}

function insertBefore(
parentInstance: Instance | Container,
child: Instance | TextInstance,
beforeChild: Instance | TextInstance
): void {
const index = parentInstance.children.indexOf(child);
if (index !== -1) {
parentInstance.children.splice(index, 1);
}
const beforeIndex = parentInstance.children.indexOf(beforeChild);
if (beforeIndex === -1) {
throw new Error('This child does not exist.');
}
parentInstance.children.splice(beforeIndex, 0, child);
}

function removeChild(
parentInstance: Instance | Container,
child: Instance | TextInstance
): void {
const index = parentInstance.children.indexOf(child);
if (index === -1) {
throw new Error('This child does not exist.');
}
parentInstance.children.splice(index, 1);
}

var NoopRenderer = ReactFiberReconciler({
getRootHostContext() {
return emptyObject;
},

getChildHostContext() {
return emptyObject;
},

getPublicInstance(instance) {
return instance;
},

createInstance(type: string, props: Props): Instance {
const inst = {
id: instanceCounter++,
type: type,
children: [],
prop: props.prop,
};
// Hide from unit tests
Object.defineProperty(inst, 'id', {value: inst.id, enumerable: false});
return inst;
},

appendInitialChild(
parentInstance: Instance,
child: Instance | TextInstance
): void {
parentInstance.children.push(child);
},

finalizeInitialChildren(
domElement: Instance,
type: string,
props: Props
): boolean {
return false;
},

prepareUpdate(
instance: Instance,
type: string,
oldProps: Props,
newProps: Props
): null | {} {
return UPDATE_SIGNAL;
},

commitMount(instance: Instance, type: string, newProps: Props): void {
// Noop
},

commitUpdate(
instance: Instance,
updatePayload: Object,
type: string,
oldProps: Props,
newProps: Props
): void {
instance.prop = newProps.prop;
},

shouldSetTextContent(type: string, props: Props): boolean {
return (
typeof props.children === 'string' || typeof props.children === 'number'
);
},

resetTextContent(instance: Instance): void {},

shouldDeprioritizeSubtree(type: string, props: Props): boolean {
return !!props.hidden;
},

now: Date.now,

createTextInstance(
text: string,
rootContainerInstance: Container,
hostContext: Object,
internalInstanceHandle: Object
): TextInstance {
var inst = {text: text, id: instanceCounter++};
// Hide from unit tests
Object.defineProperty(inst, 'id', {value: inst.id, enumerable: false});
return inst;
},

commitTextUpdate(
textInstance: TextInstance,
oldText: string,
newText: string
): void {
textInstance.text = newText;
},

appendChild: appendChild,
appendChildToContainer: appendChild,
insertBefore: insertBefore,
insertInContainerBefore: insertBefore,
removeChild: removeChild,
removeChildFromContainer: removeChild,

scheduleDeferredCallback(callback) {
if (scheduledCallback) {
throw new Error(
'Scheduling a callback twice is excessive. Instead, keep track of ' +
'whether the callback has already been scheduled.'
);
}
scheduledCallback = callback;
},

prepareForCommit(): void {},

resetAfterCommit(): void {},
});

var rootContainers = new Map();
var roots = new Map();
var DEFAULT_ROOT_ID = '<default>';

let yieldedValues = null;

function* flushUnitsOfWork(n: number): Generator<Array<mixed>, void, void> {
var didStop = false;
while (!didStop && scheduledCallback !== null) {
var cb = scheduledCallback;
scheduledCallback = null;
yieldedValues = null;
var unitsRemaining = n;
cb({
timeRemaining() {
if (yieldedValues !== null) {
return 0;
}
if (unitsRemaining-- > 0) {
return 999;
}
didStop = true;
return 0;
},
});

if (yieldedValues !== null) {
const values = yieldedValues;
yieldedValues = null;
yield values;
}
}
}

var Noop = {
getChildren(rootID: string = DEFAULT_ROOT_ID) {
const container = rootContainers.get(rootID);
if (container) {
return container.children;
} else {
return null;
}
},

// Shortcut for testing a single root
render(element: React$Element<any>, callback: ?Function) {
Noop.renderToRootWithID(element, DEFAULT_ROOT_ID, callback);
},

renderToRootWithID(
element: React$Element<any>,
rootID: string,
callback: ?Function
) {
let root = roots.get(rootID);
if (!root) {
const container = {rootID: rootID, children: []};
rootContainers.set(rootID, container);
root = NoopRenderer.createContainer(container);
roots.set(rootID, root);
}
NoopRenderer.updateContainer(element, root, null, callback);
},

flush(): Array<mixed> {
return Noop.flushUnitsOfWork(Infinity);
},

flushUnitsOfWork(n: number): Array<mixed> {
let values = [];
for (const value of flushUnitsOfWork(n)) {
values.push(...value);
}
return values;
},

batchedUpdates: NoopRenderer.batchedUpdates,

deferredUpdates: NoopRenderer.deferredUpdates,

unbatchedUpdates: NoopRenderer.unbatchedUpdates,

flushSync: NoopRenderer.flushSync,
};

type TestProps = {|
active: boolean,
|};
type TestState = {|
counter: number,
|};

let instance = null;
class Test extends React.Component<TestProps, TestState> {
state = {counter: 0};
increment() {
this.setState(({counter}) => ({
counter: counter + 1,
}));
}
render() {
return [this.props.active ? 'Active' : 'Inactive', this.state.counter];
}
}
const Children = props => props.children;
Noop.render(
<main>
<div>Hello</div>
<Children>
Hello world
<span>{'Number '}{42}</span>
<Test active={true} ref={t => (instance = t)} />
</Children>
</main>
);
Noop.flush();
const actual1 = Noop.getChildren();
const expected1 = [
{
type: 'main',
children: [
{type: 'div', children: [], prop: undefined},
{text: 'Hello world'},
{
type: 'span',
children: [{text: 'Number '}, {text: '42'}],
prop: undefined,
},
{text: 'Active'},
{text: '0'},
],
prop: undefined,
},
];
assert.deepEqual(
actual1,
expected1,
'Error. Noop.getChildren() returned unexpected value.\nExpected:\ ' +
JSON.stringify(expected1, null, 2) +
'\n\nActual:\n ' +
JSON.stringify(actual1, null, 2)
);

if (instance === null) {
throw new Error('Expected instance to exist.');
}

instance.increment();
Noop.flush();
const actual2 = Noop.getChildren();
const expected2 = [
{
type: 'main',
children: [
{type: 'div', children: [], prop: undefined},
{text: 'Hello world'},
{
type: 'span',
children: [{text: 'Number '}, {text: '42'}],
prop: undefined,
},
{text: 'Active'},
{text: '1'},
],
prop: undefined,
},
];
assert.deepEqual(
actual2,
expected2,
'Error. Noop.getChildren() returned unexpected value.\nExpected:\ ' +
JSON.stringify(expected2, null, 2) +
'\n\nActual:\n ' +
JSON.stringify(actual2, null, 2)
);

const beginGreen = '\u001b[32m';
const endGreen = '\u001b[39m';
console.log(beginGreen + 'Reconciler package is OK!' + endGreen);
10 changes: 10 additions & 0 deletions fixtures/reconciler/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "react-fixtures",
"version": "0.1.0",
"private": true,
"scripts": {
"test:dev": "NODE_PATH=../../build/packages ../../node_modules/.bin/babel-node ./index",
"test:prod": "NODE_PATH=../../build/packages NODE_ENV=production ../../node_modules/.bin/babel-node ./index",
"test": "npm run test:dev && npm run test:prod"
}
}
Loading