mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
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
This commit is contained in:
committed by
Dan Abramov
parent
fb0199b73c
commit
111731dedd
13
fixtures/reconciler/README.md
Normal file
13
fixtures/reconciler/README.md
Normal file
@@ -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
fixtures/reconciler/index.js
Normal file
366
fixtures/reconciler/index.js
Normal file
@@ -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
fixtures/reconciler/package.json
Normal file
10
fixtures/reconciler/package.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
39
packages/react-reconciler/README.md
Normal file
39
packages/react-reconciler/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# react-reconciler
|
||||
|
||||
This is an experimental package for creating custom React renderers.
|
||||
|
||||
**Its API is not as stable as that of React, React Native, or React DOM, and does not follow the common versioning scheme.**
|
||||
|
||||
**Use it at your own risk.**
|
||||
|
||||
## API
|
||||
|
||||
```js
|
||||
var Reconciler = require('react-reconciler');
|
||||
|
||||
var ReconcilerConfig = {
|
||||
// You'll need to implement some methods here.
|
||||
// See below for more information and examples.
|
||||
};
|
||||
|
||||
var MyRenderer = Reconciler(ReconcilerConfig);
|
||||
|
||||
var RendererPublicAPI = {
|
||||
render(element, container, callback) {
|
||||
// Call MyRenderer.updateContainer() to schedule changes on the roots.
|
||||
// See ReactDOM, React Native, or React ART for practical examples.
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = RendererPublicAPI;
|
||||
```
|
||||
|
||||
## Practical Examples
|
||||
|
||||
* [React ART](https://github.com/facebook/react/blob/master/src/renderers/art/ReactARTFiberEntry.js)
|
||||
* [React DOM](https://github.com/facebook/react/blob/master/src/fb/ReactDOMFiberFBEntry.js)
|
||||
* [React Native](https://github.com/facebook/react/blob/master/src/renderers/native/ReactNativeFiberRenderer.js)
|
||||
|
||||
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.
|
||||
|
||||
This [third-party tutorial](https://github.com/nitin42/Making-a-custom-React-renderer) is relatively up-to-date and may be helpful.
|
||||
7
packages/react-reconciler/index.js
vendored
Normal file
7
packages/react-reconciler/index.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./cjs/react-reconciler.production.min.js');
|
||||
} else {
|
||||
module.exports = require('./cjs/react-reconciler.development.js');
|
||||
}
|
||||
35
packages/react-reconciler/package.json
Normal file
35
packages/react-reconciler/package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "react-reconciler",
|
||||
"description": "React package for creating custom renderers.",
|
||||
"version": "0.1.0",
|
||||
"keywords": [
|
||||
"react"
|
||||
],
|
||||
"homepage": "https://facebook.github.io/react/",
|
||||
"bugs": "https://github.com/facebook/react/issues",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"index.js",
|
||||
"cjs/"
|
||||
],
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"fbjs": "^0.8.16",
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
"loose-envify"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,8 @@
|
||||
set -e
|
||||
|
||||
npm run build -- --extract-errors
|
||||
git checkout -- scripts/error-codes/codes.json
|
||||
git checkout -- scripts/error-codes/codes.json
|
||||
|
||||
# Check that the standalone reconciler isn't borked
|
||||
cd fixtures/reconciler
|
||||
yarn test
|
||||
|
||||
@@ -34,6 +34,8 @@ const FB_PROD = Bundles.bundleTypes.FB_PROD;
|
||||
const RN_DEV = Bundles.bundleTypes.RN_DEV;
|
||||
const RN_PROD = Bundles.bundleTypes.RN_PROD;
|
||||
|
||||
const RECONCILER = Bundles.moduleTypes.RECONCILER;
|
||||
|
||||
const reactVersion = require('../../package.json').version;
|
||||
const requestedBundleTypes = (argv.type || '')
|
||||
.split(',')
|
||||
@@ -78,7 +80,13 @@ function getHeaderSanityCheck(bundleType, hasteName) {
|
||||
}
|
||||
}
|
||||
|
||||
function getBanner(bundleType, hasteName, filename) {
|
||||
function getBanner(bundleType, hasteName, filename, moduleType) {
|
||||
if (moduleType === RECONCILER) {
|
||||
// Standalone reconciler is only used by third-party renderers.
|
||||
// It is handled separately.
|
||||
return getReconcilerBanner(bundleType, filename);
|
||||
}
|
||||
|
||||
switch (bundleType) {
|
||||
// UMDs are not wrapped in conditions.
|
||||
case UMD_DEV:
|
||||
@@ -112,7 +120,13 @@ function getBanner(bundleType, hasteName, filename) {
|
||||
}
|
||||
}
|
||||
|
||||
function getFooter(bundleType) {
|
||||
function getFooter(bundleType, filename, moduleType) {
|
||||
if (moduleType === RECONCILER) {
|
||||
// Standalone reconciler is only used by third-party renderers.
|
||||
// It is handled separately.
|
||||
return getReconcilerFooter(bundleType);
|
||||
}
|
||||
|
||||
// Only need a footer if getBanner() has an opening brace.
|
||||
switch (bundleType) {
|
||||
// Non-UMD DEV bundles need conditions to help weak dead code elimination.
|
||||
@@ -125,7 +139,46 @@ function getFooter(bundleType) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateBabelConfig(babelOpts, bundleType) {
|
||||
// TODO: this is extremely gross.
|
||||
// But it only affects the "experimental" standalone reconciler build.
|
||||
// The goal is to avoid having any shared state between renderers sharing it on npm.
|
||||
// Ideally we should just remove shared state in all Fiber modules and then lint against it.
|
||||
// But for now, we store the exported function in a variable, and then put the rest of the code
|
||||
// into a closure that makes all module-level state private to each call.
|
||||
const RECONCILER_WRAPPER_INTRO = `var $$$reconciler;\nmodule.exports = function(config) {\n`;
|
||||
const RECONCILER_WRAPPER_OUTRO = `return ($$$reconciler || ($$$reconciler = module.exports))(config);\n};\n`;
|
||||
|
||||
function getReconcilerBanner(bundleType, filename) {
|
||||
let banner = `${Header.getHeader(filename, reactVersion)}\n\n'use strict';\n\n\n`;
|
||||
switch (bundleType) {
|
||||
case NODE_DEV:
|
||||
banner += `if (process.env.NODE_ENV !== "production") {\n${RECONCILER_WRAPPER_INTRO}`;
|
||||
break;
|
||||
case NODE_PROD:
|
||||
banner += RECONCILER_WRAPPER_INTRO;
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
'Standalone reconciler does not support ' + bundleType + ' builds.'
|
||||
);
|
||||
}
|
||||
return banner;
|
||||
}
|
||||
|
||||
function getReconcilerFooter(bundleType) {
|
||||
switch (bundleType) {
|
||||
case NODE_DEV:
|
||||
return `\n${RECONCILER_WRAPPER_OUTRO}\n}`;
|
||||
case NODE_PROD:
|
||||
return `\n${RECONCILER_WRAPPER_OUTRO}`;
|
||||
default:
|
||||
throw new Error(
|
||||
'Standalone reconciler does not support ' + bundleType + ' builds.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function updateBabelConfig(babelOpts, bundleType, filename) {
|
||||
switch (bundleType) {
|
||||
case FB_DEV:
|
||||
case FB_PROD:
|
||||
@@ -166,16 +219,23 @@ function handleRollupWarnings(warning) {
|
||||
console.warn(warning.message || warning);
|
||||
}
|
||||
|
||||
function updateBundleConfig(config, filename, format, bundleType, hasteName) {
|
||||
function updateBundleConfig(
|
||||
config,
|
||||
filename,
|
||||
format,
|
||||
bundleType,
|
||||
hasteName,
|
||||
moduleType
|
||||
) {
|
||||
return Object.assign({}, config, {
|
||||
banner: getBanner(bundleType, hasteName, filename),
|
||||
banner: getBanner(bundleType, hasteName, filename, moduleType),
|
||||
dest: Packaging.getPackageDestination(
|
||||
config,
|
||||
bundleType,
|
||||
filename,
|
||||
hasteName
|
||||
),
|
||||
footer: getFooter(bundleType),
|
||||
footer: getFooter(bundleType, filename, moduleType),
|
||||
format,
|
||||
interop: false,
|
||||
});
|
||||
@@ -309,7 +369,7 @@ function getPlugins(
|
||||
filename,
|
||||
bundleType,
|
||||
hasteName,
|
||||
isRenderer,
|
||||
moduleType,
|
||||
manglePropertiesOnProd,
|
||||
useFiber,
|
||||
modulesToStub
|
||||
@@ -317,7 +377,7 @@ function getPlugins(
|
||||
const plugins = [
|
||||
babel(updateBabelConfig(babelOpts, bundleType)),
|
||||
alias(
|
||||
Modules.getAliases(paths, bundleType, isRenderer, argv['extract-errors'])
|
||||
Modules.getAliases(paths, bundleType, moduleType, argv['extract-errors'])
|
||||
),
|
||||
];
|
||||
|
||||
@@ -453,7 +513,7 @@ function createBundle(bundle, bundleType) {
|
||||
external: Modules.getExternalModules(
|
||||
bundle.externals,
|
||||
bundleType,
|
||||
bundle.isRenderer
|
||||
bundle.moduleType
|
||||
),
|
||||
onwarn: handleRollupWarnings,
|
||||
plugins: getPlugins(
|
||||
@@ -463,7 +523,7 @@ function createBundle(bundle, bundleType) {
|
||||
filename,
|
||||
bundleType,
|
||||
bundle.hasteName,
|
||||
bundle.isRenderer,
|
||||
bundle.moduleType,
|
||||
bundle.manglePropertiesOnProd,
|
||||
bundle.useFiber,
|
||||
bundle.modulesToStub
|
||||
@@ -476,7 +536,8 @@ function createBundle(bundle, bundleType) {
|
||||
filename,
|
||||
format,
|
||||
bundleType,
|
||||
bundle.hasteName
|
||||
bundle.hasteName,
|
||||
bundle.moduleType
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -20,6 +20,16 @@ const FB_PROD = bundleTypes.FB_PROD;
|
||||
const RN_DEV = bundleTypes.RN_DEV;
|
||||
const RN_PROD = bundleTypes.RN_PROD;
|
||||
|
||||
const moduleTypes = {
|
||||
ISOMORPHIC: 'ISOMORPHIC',
|
||||
RENDERER: 'RENDERER',
|
||||
RECONCILER: 'RECONCILER',
|
||||
};
|
||||
|
||||
const ISOMORPHIC = moduleTypes.ISOMORPHIC;
|
||||
const RENDERER = moduleTypes.RENDERER;
|
||||
const RECONCILER = moduleTypes.RECONCILER;
|
||||
|
||||
const babelOptsReact = {
|
||||
exclude: 'node_modules/**',
|
||||
presets: [],
|
||||
@@ -51,7 +61,7 @@ const bundles = [
|
||||
],
|
||||
fbEntry: 'src/isomorphic/ReactEntry',
|
||||
hasteName: 'React',
|
||||
isRenderer: false,
|
||||
moduleType: ISOMORPHIC,
|
||||
label: 'core',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react',
|
||||
@@ -79,7 +89,7 @@ const bundles = [
|
||||
externals: ['prop-types', 'prop-types/checkPropTypes'],
|
||||
fbEntry: 'src/fb/ReactDOMFiberFBEntry',
|
||||
hasteName: 'ReactDOMFiber',
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'dom-fiber',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-dom',
|
||||
@@ -112,7 +122,7 @@ const bundles = [
|
||||
],
|
||||
fbEntry: 'src/renderers/dom/test/ReactTestUtilsEntry',
|
||||
hasteName: 'ReactTestUtils',
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'test-utils',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-dom/test-utils',
|
||||
@@ -147,7 +157,7 @@ const bundles = [
|
||||
],
|
||||
fbEntry: 'src/renderers/dom/shared/ReactDOMUnstableNativeDependenciesEntry',
|
||||
hasteName: 'ReactDOMUnstableNativeDependencies',
|
||||
isRenderer: false,
|
||||
moduleType: RENDERER,
|
||||
label: 'dom-unstable-native-dependencies',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-dom/unstable-native-dependencies',
|
||||
@@ -176,7 +186,7 @@ const bundles = [
|
||||
externals: ['prop-types', 'prop-types/checkPropTypes'],
|
||||
fbEntry: 'src/renderers/dom/ReactDOMServerBrowserEntry',
|
||||
hasteName: 'ReactDOMServer',
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'dom-server-browser',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-dom/server.browser',
|
||||
@@ -201,7 +211,7 @@ const bundles = [
|
||||
},
|
||||
entry: 'src/renderers/dom/ReactDOMServerNodeEntry',
|
||||
externals: ['prop-types', 'prop-types/checkPropTypes', 'stream'],
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'dom-server-server-node',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-dom/server.node',
|
||||
@@ -237,7 +247,7 @@ const bundles = [
|
||||
],
|
||||
fbEntry: 'src/renderers/art/ReactARTFiberEntry',
|
||||
hasteName: 'ReactARTFiber',
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'art-fiber',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-art',
|
||||
@@ -274,7 +284,7 @@ const bundles = [
|
||||
'prop-types/checkPropTypes',
|
||||
],
|
||||
hasteName: 'ReactNativeFiber',
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'native-fiber',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-native-renderer',
|
||||
@@ -335,7 +345,7 @@ const bundles = [
|
||||
externals: ['prop-types/checkPropTypes'],
|
||||
fbEntry: 'src/renderers/testing/ReactTestRendererFiberEntry',
|
||||
hasteName: 'ReactTestRendererFiber',
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'test-fiber',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-test-renderer',
|
||||
@@ -364,7 +374,7 @@ const bundles = [
|
||||
],
|
||||
fbEntry: 'src/renderers/testing/ReactShallowRendererEntry',
|
||||
hasteName: 'ReactShallowRenderer',
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'shallow-renderer',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-test-renderer/shallow',
|
||||
@@ -389,7 +399,7 @@ const bundles = [
|
||||
},
|
||||
entry: 'src/renderers/noop/ReactNoopEntry',
|
||||
externals: ['prop-types/checkPropTypes', 'jest-matchers'],
|
||||
isRenderer: true,
|
||||
moduleType: RENDERER,
|
||||
label: 'noop-fiber',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-noop-renderer',
|
||||
@@ -401,6 +411,32 @@ const bundles = [
|
||||
'src/shared/**/*.js',
|
||||
],
|
||||
},
|
||||
|
||||
/******* React Reconciler *******/
|
||||
{
|
||||
babelOpts: babelOptsReact,
|
||||
bundleTypes: [NODE_DEV, NODE_PROD],
|
||||
config: {
|
||||
destDir: 'build/',
|
||||
globals: {
|
||||
react: 'React',
|
||||
},
|
||||
moduleName: 'ReactReconciler',
|
||||
sourceMap: false,
|
||||
},
|
||||
entry: 'src/renderers/shared/fiber/ReactFiberReconciler',
|
||||
externals: ['react', 'prop-types/checkPropTypes'],
|
||||
moduleType: RECONCILER,
|
||||
label: 'react-reconciler',
|
||||
manglePropertiesOnProd: false,
|
||||
name: 'react-reconciler',
|
||||
paths: [
|
||||
'src/renderers/shared/**/*.js',
|
||||
|
||||
'src/ReactVersion.js',
|
||||
'src/shared/**/*.js',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// Based on deep-freeze by substack (public domain)
|
||||
@@ -423,5 +459,6 @@ deepFreeze(bundles);
|
||||
|
||||
module.exports = {
|
||||
bundleTypes,
|
||||
moduleTypes,
|
||||
bundles,
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ const resolve = require('path').resolve;
|
||||
const basename = require('path').basename;
|
||||
const sync = require('glob').sync;
|
||||
const bundleTypes = require('./bundles').bundleTypes;
|
||||
const moduleTypes = require('./bundles').moduleTypes;
|
||||
const extractErrorCodes = require('../error-codes/extract-errors');
|
||||
|
||||
const exclude = [
|
||||
@@ -21,6 +22,8 @@ const FB_PROD = bundleTypes.FB_PROD;
|
||||
const RN_DEV = bundleTypes.RN_DEV;
|
||||
const RN_PROD = bundleTypes.RN_PROD;
|
||||
|
||||
const ISOMORPHIC = moduleTypes.ISOMORPHIC;
|
||||
|
||||
const errorCodeOpts = {
|
||||
errorMapFilePath: 'scripts/error-codes/codes.json',
|
||||
};
|
||||
@@ -87,7 +90,7 @@ function createModuleMap(paths, extractErrors, bundleType) {
|
||||
return moduleMap;
|
||||
}
|
||||
|
||||
function getNodeModules(bundleType, isRenderer) {
|
||||
function getNodeModules(bundleType, moduleType) {
|
||||
// rather than adding the rollup node resolve plugin,
|
||||
// we can instead deal with the only node module that is used
|
||||
// for UMD bundles - object-assign
|
||||
@@ -97,9 +100,9 @@ function getNodeModules(bundleType, isRenderer) {
|
||||
return {
|
||||
// Bundle object-assign once in the isomorphic React, and then use
|
||||
// that from the renderer UMD. Avoids bundling it in both UMDs.
|
||||
'object-assign': isRenderer
|
||||
? resolve('./scripts/rollup/shims/rollup/assign.js')
|
||||
: resolve('./node_modules/object-assign/index.js'),
|
||||
'object-assign': moduleType === ISOMORPHIC
|
||||
? resolve('./node_modules/object-assign/index.js')
|
||||
: resolve('./scripts/rollup/shims/rollup/assign.js'),
|
||||
// include the ART package modules directly by aliasing them from node_modules
|
||||
'art/modes/current': resolve('./node_modules/art/modes/current.js'),
|
||||
'art/modes/fast-noSideEffects': resolve(
|
||||
@@ -136,7 +139,7 @@ function ignoreReactNativeModules() {
|
||||
];
|
||||
}
|
||||
|
||||
function getExternalModules(externals, bundleType, isRenderer) {
|
||||
function getExternalModules(externals, bundleType, moduleType) {
|
||||
// external modules tell Rollup that we should not attempt
|
||||
// to bundle these modules and instead treat them as
|
||||
// external dependencies to the bundle. so for CJS bundles
|
||||
@@ -144,11 +147,10 @@ function getExternalModules(externals, bundleType, isRenderer) {
|
||||
// the top of the bundle. for UMD bundles this means having
|
||||
// both a require and a global check for them
|
||||
let externalModules = externals.slice();
|
||||
|
||||
switch (bundleType) {
|
||||
case UMD_DEV:
|
||||
case UMD_PROD:
|
||||
if (isRenderer) {
|
||||
if (moduleType !== ISOMORPHIC) {
|
||||
externalModules.push('react');
|
||||
}
|
||||
break;
|
||||
@@ -158,7 +160,7 @@ function getExternalModules(externals, bundleType, isRenderer) {
|
||||
case RN_PROD:
|
||||
fbjsModules.forEach(module => externalModules.push(module));
|
||||
externalModules.push('object-assign');
|
||||
if (isRenderer) {
|
||||
if (moduleType !== ISOMORPHIC) {
|
||||
externalModules.push('react');
|
||||
}
|
||||
break;
|
||||
@@ -168,7 +170,7 @@ function getExternalModules(externals, bundleType, isRenderer) {
|
||||
externalModules.push('object-assign');
|
||||
externalModules.push('ReactCurrentOwner');
|
||||
externalModules.push('lowPriorityWarning');
|
||||
if (isRenderer) {
|
||||
if (moduleType !== ISOMORPHIC) {
|
||||
externalModules.push('React');
|
||||
if (externalModules.indexOf('react-dom') > -1) {
|
||||
externalModules.push('ReactDOM');
|
||||
@@ -282,7 +284,7 @@ function replaceBundleStubModules(bundleModulesToStub) {
|
||||
return stubbedModules;
|
||||
}
|
||||
|
||||
function getAliases(paths, bundleType, isRenderer, extractErrors) {
|
||||
function getAliases(paths, bundleType, moduleType, extractErrors) {
|
||||
return Object.assign(
|
||||
createModuleMap(
|
||||
paths,
|
||||
@@ -290,7 +292,7 @@ function getAliases(paths, bundleType, isRenderer, extractErrors) {
|
||||
bundleType
|
||||
),
|
||||
getInternalModules(),
|
||||
getNodeModules(bundleType, isRenderer),
|
||||
getNodeModules(bundleType, moduleType),
|
||||
getFbjsModuleAliases(bundleType)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,12 +57,12 @@
|
||||
"gzip": 11028
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.development.js (UMD_DEV)": {
|
||||
"size": 86854,
|
||||
"gzip": 21985
|
||||
"size": 84930,
|
||||
"gzip": 21288
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.production.min.js (UMD_PROD)": {
|
||||
"size": 15251,
|
||||
"gzip": 5010
|
||||
"size": 14441,
|
||||
"gzip": 4650
|
||||
},
|
||||
"react-dom-unstable-native-dependencies.development.js (NODE_DEV)": {
|
||||
"size": 80723,
|
||||
@@ -207,6 +207,14 @@
|
||||
"react-dom-test-utils.production.min.js (NODE_PROD)": {
|
||||
"size": 11608,
|
||||
"gzip": 4241
|
||||
},
|
||||
"react-reconciler.development.js (NODE_DEV)": {
|
||||
"size": 279927,
|
||||
"gzip": 58576
|
||||
},
|
||||
"react-reconciler.production.min.js (NODE_PROD)": {
|
||||
"size": 38630,
|
||||
"gzip": 12165
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user