@samitouri / QOS-React-2 / commits / c22b94f14a

ReactNative flat renderer bundles (#9626)

* Split ReactNativeFiber into separate ReactNativeFiberRenderer module Hopefully this is sufficient to work around Rollup circular dependency problems. (To be seen in subsequent commits...) * Split findNodeHandle into findNodeHandleFiber + findNodeHandleStack This allowed me to remove the ReactNative -> findNodeHandle injections, which should in turn allow me to require a fully-functional findNodeHandle without going through ReactNative. This will hopefully allow ReactNativeBaseomponent to avoid a circular dependency. * Un-forked findNodeHandle in favor of just inlining the findNode function impl * takeSnapshot no longer requires/depends-on ReactNative for findNodeHandle Instead it uses the new, renderer-specific wrappers (eg findNodeHandleFiberWrapper and findNodeHandleStackWrapper) to ensure the returned value is numeric (or null). This avoids a circular dependency that would trip up Rollup. * NativeMethodsMixin requires findNodeHandler wrapper(s) directly rather than ReactNative This works around a potential circular dependency that would break the Rollup build * Add RN_* build targets to hash-finle-name check * Strip @providesModule annotations from headers for RN_* builds * Added process.env.REACT_NATIVE_USE_FIBER to ReactNativeFeatureFlags This is kind of a hacky solution, but it is temporary. It works around the fact that ReactNativeFeatureFlag values need to be set at build time in order to avoid a mismatch between runtime flag values. DOM avoids the need to do this by using injection but Native is not able to use this same approach due to circular dependency issues. * Moved a couple of SECRET exports to dev-only. Removed SyntheticEvent and PooledClass from SECRET exports. Converted Rollup helper function to use named params. * Split NativeMethodsMixins interface and object-type * Add @noflow header to flat-bundle template to avoid triggering Flow problems When Flow tries to infer such a large file, it consumes massive amounts of CPU/RAM and can often lead to programs crashing. It is better for such large files to use .flow.js types instead. * NativeMethodsMixin and ReactNativeFiberHostComponent now share the same Flow type * Collocated (externally exposed) ReactTypes and ReactNativeTypes into single files to be synced to fbsource. ReactNativeFiber and ReactNativeStack use ReactNativeType Flow type * Build script syncs RN types and PooledClass automatically * Added optional sync-RN step to Rollup build script * Added results.json for new RN bundles

Brian Vaughn committed May 24, 2017 at 17:06 UTC c22b94f14a809abb376f07a53f36860a7c6a342e
33 files changed +924 -589
scripts/rollup/build.js
+85 -12
@@ -18,6 +18,7 @@ const Bundles = require('./bundles');
18 const propertyMangleWhitelist = require('./mangle').propertyMangleWhitelist;
19 const sizes = require('./plugins/sizes-plugin');
20 const Stats = require('./stats');
21 +const syncReactNative = require('./sync').syncReactNative;
22 const Packaging = require('./packaging');
23 const Header = require('./header');
24
@@ -37,6 +38,7 @@ const requestedBundleTypes = (argv.type || '')
38 const requestedBundleNames = (argv._[0] || '')
39 .split(',')
40 .map(type => type.toLowerCase());
41 +const syncFbsource = argv['sync-fbsource'];
42
43 // used for when we property mangle with uglify/gcc
44 const mangleRegex = new RegExp(
@@ -46,6 +48,32 @@ const mangleRegex = new RegExp(
48 'g'
49 );
50
51 +function getHeaderSanityCheck(bundleType, hasteName) {
52 + switch (bundleType) {
53 + case FB_DEV:
54 + case FB_PROD:
55 + case RN_DEV:
56 + case RN_PROD:
57 + let hasteFinalName = hasteName;
58 + switch (bundleType) {
59 + case FB_DEV:
60 + case RN_DEV:
61 + hasteFinalName += '-dev';
62 + break;
63 + case FB_PROD:
64 + case RN_PROD:
65 + hasteFinalName += '-prod';
66 + break;
67 + }
68 + return hasteFinalName;
69 + case UMD_DEV:
70 + case UMD_PROD:
71 + return reactVersion;
72 + default:
73 + return null;
74 + }
75 +}
76 +
77 function getBanner(bundleType, hasteName, filename) {
78 switch (bundleType) {
79 case FB_DEV:
@@ -55,9 +83,11 @@ function getBanner(bundleType, hasteName, filename) {
83 let hasteFinalName = hasteName;
84 switch (bundleType) {
85 case FB_DEV:
86 + case RN_DEV:
87 hasteFinalName += '-dev';
88 break;
89 case FB_PROD:
90 + case RN_PROD:
91 hasteFinalName += '-prod';
92 break;
93 }
@@ -122,6 +152,12 @@ function updateBundleConfig(config, filename, format, bundleType, hasteName) {
152 });
153 }
154
155 +function setReactNativeUseFiberEnvVariable(useFiber) {
156 + return {
157 + 'process.env.REACT_NATIVE_USE_FIBER': useFiber,
158 + };
159 +}
160 +
161 function stripEnvVariables(production) {
162 return {
163 __DEV__: production ? 'false' : 'true',
@@ -165,7 +201,13 @@ function getFilename(name, hasteName, bundleType) {
201 }
202 }
203
168 -function uglifyConfig(mangle, manglePropertiesOnProd, preserveVersionHeader) {
204 +function uglifyConfig({
205 + mangle,
206 + manglePropertiesOnProd,
207 + preserveVersionHeader,
208 + removeComments,
209 + headerSanityCheck,
210 +}) {
211 return {
212 warnings: false,
213 compress: {
@@ -186,7 +228,10 @@ function uglifyConfig(mangle, manglePropertiesOnProd, preserveVersionHeader) {
228 comments(node, comment) {
229 if (preserveVersionHeader && comment.pos === 0 && comment.col === 0) {
230 // Keep the very first comment (the bundle header) in prod bundles.
189 - if (comment.value.indexOf(reactVersion) === -1) {
231 + if (
232 + headerSanityCheck &&
233 + comment.value.indexOf(headerSanityCheck) === -1
234 + ) {
235 // Sanity check: this doesn't look like the bundle header!
236 throw new Error(
237 'Expected the first comment to be the file header but got: ' +
@@ -195,8 +240,7 @@ function uglifyConfig(mangle, manglePropertiesOnProd, preserveVersionHeader) {
240 }
241 return true;
242 }
198 - // Keep all comments in FB bundles.
199 - return !mangle;
243 + return !removeComments;
244 },
245 },
246 mangleProperties: mangle && manglePropertiesOnProd
@@ -242,8 +286,10 @@ function getPlugins(
286 paths,
287 filename,
288 bundleType,
289 + hasteName,
290 isRenderer,
246 - manglePropertiesOnProd
291 + manglePropertiesOnProd,
292 + useFiber
293 ) {
294 const plugins = [
295 babel(updateBabelConfig(babelOpts, bundleType)),
@@ -259,11 +305,12 @@ function getPlugins(
305 plugins.unshift(replace(replaceModules));
306 }
307
308 + const headerSanityCheck = getHeaderSanityCheck(bundleType, hasteName);
309 +
310 switch (bundleType) {
311 case UMD_DEV:
312 case NODE_DEV:
313 case FB_DEV:
266 - case RN_DEV:
314 plugins.push(
315 replace(stripEnvVariables(false)),
316 // needs to happen after strip env
@@ -273,17 +320,36 @@ function getPlugins(
320 case UMD_PROD:
321 case NODE_PROD:
322 case FB_PROD:
276 - case RN_PROD:
323 plugins.push(
324 replace(stripEnvVariables(true)),
325 // needs to happen after strip env
326 commonjs(getCommonJsConfig(bundleType)),
327 uglify(
282 - uglifyConfig(
283 - bundleType !== FB_PROD,
328 + uglifyConfig({
329 + mangle: bundleType !== FB_PROD,
330 manglePropertiesOnProd,
285 - bundleType === UMD_PROD
286 - )
331 + preserveVersionHeader: bundleType === UMD_PROD,
332 + removeComments: bundleType === FB_PROD,
333 + headerSanityCheck,
334 + })
335 + )
336 + );
337 + break;
338 + case RN_DEV:
339 + case RN_PROD:
340 + plugins.push(
341 + replace(stripEnvVariables(bundleType === RN_PROD)),
342 + replace(setReactNativeUseFiberEnvVariable(useFiber)),
343 + // needs to happen after strip env
344 + commonjs(getCommonJsConfig(bundleType)),
345 + uglify(
346 + uglifyConfig({
347 + mangle: false,
348 + manglePropertiesOnProd,
349 + preserveVersionHeader: true,
350 + removeComments: true,
351 + headerSanityCheck,
352 + })
353 )
354 );
355 break;
@@ -349,8 +415,10 @@ function createBundle(bundle, bundleType) {
415 bundle.paths,
416 filename,
417 bundleType,
418 + bundle.hasteName,
419 bundle.isRenderer,
353 - bundle.manglePropertiesOnProd
420 + bundle.manglePropertiesOnProd,
421 + bundle.useFiber
422 ),
423 })
424 .then(result =>
@@ -406,6 +474,11 @@ rimraf('build', () => {
474 () => createBundle(bundle, RN_PROD)
475 );
476 }
477 + if (syncFbsource) {
478 + tasks.push(() =>
479 + syncReactNative(join('build', 'react-native'), syncFbsource)
480 + );
481 + }
482 // rather than run concurently, opt to run them serially
483 // this helps improve console/warning/error output
484 // and fixes a bunch of IO failures that sometimes occured
scripts/rollup/bundles.js
+8 -8
@@ -19,8 +19,8 @@ const NODE_DEV = bundleTypes.NODE_DEV;
19 const NODE_PROD = bundleTypes.NODE_PROD;
20 const FB_DEV = bundleTypes.FB_DEV;
21 const FB_PROD = bundleTypes.FB_PROD;
22 -// const RN_DEV = bundleTypes.RN_DEV;
23 -// const RN_PROD = bundleTypes.RN_PROD;
22 +const RN_DEV = bundleTypes.RN_DEV;
23 +const RN_PROD = bundleTypes.RN_PROD;
24
25 const babelOptsReact = {
26 exclude: 'node_modules/**',
@@ -284,9 +284,7 @@ const bundles = [
284 /******* React Native *******/
285 {
286 babelOpts: babelOptsReact,
287 - bundleTypes: [
288 - /* RN_DEV, RN_PROD */
289 - ],
287 + bundleTypes: [RN_DEV, RN_PROD],
288 config: {
289 destDir: 'build/',
290 moduleName: 'ReactNativeStack',
@@ -304,6 +302,7 @@ const bundles = [
302 'deepDiffer',
303 'deepFreezeAndThrowOnMutationInDev',
304 'flattenStyle',
305 + 'prop-types/checkPropTypes',
306 ],
307 hasteName: 'ReactNativeStack',
308 isRenderer: true,
@@ -317,12 +316,11 @@ const bundles = [
316 'src/ReactVersion.js',
317 'src/shared/**/*.js',
318 ],
319 + useFiber: false,
320 },
321 {
322 babelOpts: babelOptsReact,
323 - bundleTypes: [
324 - /* RN_DEV, RN_PROD */
325 - ],
323 + bundleTypes: [RN_DEV, RN_PROD],
324 config: {
325 destDir: 'build/',
326 moduleName: 'ReactNativeFiber',
@@ -340,6 +338,7 @@ const bundles = [
338 'deepDiffer',
339 'deepFreezeAndThrowOnMutationInDev',
340 'flattenStyle',
341 + 'prop-types/checkPropTypes',
342 ],
343 hasteName: 'ReactNativeFiber',
344 isRenderer: true,
@@ -353,6 +352,7 @@ const bundles = [
352 'src/ReactVersion.js',
353 'src/shared/**/*.js',
354 ],
355 + useFiber: true,
356 },
357
358 /******* React Test Renderer *******/
scripts/rollup/header.js
+1
@@ -11,6 +11,7 @@ function getProvidesHeader(hasteFinalName, bundleType, fbDevCode) {
11 * LICENSE file in the root directory of this source tree. An additional grant
12 * of patent rights can be found in the PATENTS file in the same directory.
13 *
14 + * @noflow
15 * @providesModule ${hasteFinalName}
16 */${bundleType === FB_DEV ? fbDevCode : ''}
17 `;
scripts/rollup/packaging.js
+18 -13
@@ -1,11 +1,11 @@
1 'use strict';
2
3 const basename = require('path').basename;
4 -const ncp = require('ncp').ncp;
4 const fs = require('fs');
5 const join = require('path').join;
6 const resolve = require('path').resolve;
7 const Bundles = require('./bundles');
8 +const asyncCopyTo = require('./utils').asyncCopyTo;
9
10 const UMD_DEV = Bundles.bundleTypes.UMD_DEV;
11 const UMD_PROD = Bundles.bundleTypes.UMD_PROD;
@@ -23,17 +23,12 @@ const facebookWWWSrcDependencies = [
23 'src/renderers/dom/shared/eventPlugins/TapEventPlugin.js',
24 ];
25
26 -function asyncCopyTo(from, to) {
27 - return new Promise(_resolve => {
28 - ncp(from, to, error => {
29 - if (error) {
30 - console.error(error);
31 - process.exit(1);
32 - }
33 - _resolve();
34 - });
35 - });
36 -}
26 +// these files need to be copied to the react-native build
27 +const reactNativeSrcDependencies = [
28 + 'src/shared/utils/PooledClass.js',
29 + 'src/renderers/shared/fiber/isomorphic/ReactTypes.js',
30 + 'src/renderers/native/ReactNativeTypes.js',
31 +];
32
33 function getPackageName(name) {
34 if (name.indexOf('/') !== -1) {
@@ -51,7 +46,17 @@ function createReactNativeBuild() {
46 const from = join('scripts', 'rollup', 'shims', 'react-native');
47 const to = join('build', 'react-native', 'shims');
48
54 - return asyncCopyTo(from, to);
49 + return asyncCopyTo(from, to).then(() => {
50 + let promises = [];
51 + // we also need to copy over some specific files from src
52 + // defined in reactNativeSrcDependencies
53 + for (const srcDependency of reactNativeSrcDependencies) {
54 + promises.push(
55 + asyncCopyTo(resolve(srcDependency), join(to, basename(srcDependency)))
56 + );
57 + }
58 + return Promise.all(promises);
59 + });
60 }
61
62 function createFacebookWWWBuild() {
scripts/rollup/results.json
+16
@@ -163,6 +163,22 @@
163 "ReactDOMServerStream-prod.js (FB_PROD)": {
164 "size": 345920,
165 "gzip": 83497
166 + },
167 + "ReactNativeStack-dev.js (RN_DEV)": {
168 + "size": 350743,
169 + "gzip": 63769
170 + },
171 + "ReactNativeStack-prod.js (RN_PROD)": {
172 + "size": 269602,
173 + "gzip": 46634
174 + },
175 + "ReactNativeFiber-dev.js (RN_DEV)": {
176 + "size": 327677,
177 + "gzip": 59441
178 + },
179 + "ReactNativeFiber-prod.js (RN_PROD)": {
180 + "size": 248866,
181 + "gzip": 43107
182 }
183 }
184 }
\ No newline at end of file
scripts/rollup/shims/react-native/NativeMethodsMixin.js
+5 -2
@@ -16,5 +16,8 @@ const {
16 __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
17 } = require('ReactNative');
18
19 -module.exports =
20 - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.NativeMethodsMixin;
19 +import type {NativeMethodsMixinType} from 'ReactNativeTypes';
20 +
21 +const {NativeMethodsMixin} = __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
22 +
23 +module.exports = ((NativeMethodsMixin: any): $Exact<NativeMethodsMixinType>);
scripts/rollup/shims/react-native/ReactGlobalSharedState.js renamed
+3 -2
@@ -6,7 +6,7 @@
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 - * @providesModule PooledClass
9 + * @providesModule ReactGlobalSharedState
10 */
11
12 'use strict';
@@ -15,4 +15,5 @@ const {
15 __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
16 } = require('ReactNative');
17
18 -module.exports = __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.PooledClass;
18 +module.exports =
19 + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactGlobalSharedState;
scripts/rollup/shims/react-native/ReactNative.js new
+30
@@ -0,0 +1,30 @@
1 +/**
2 + * Copyright (c) 2015-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactNative
10 + * @flow
11 + */
12 +'use strict';
13 +
14 +const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
15 +
16 +import type {ReactNativeType} from 'ReactNativeTypes';
17 +
18 +let ReactNative;
19 +
20 +if (__DEV__) {
21 + ReactNative = ReactNativeFeatureFlags.useFiber
22 + ? require('ReactNativeFiber-dev')
23 + : require('ReactNativeStack-dev');
24 +} else {
25 + ReactNative = ReactNativeFeatureFlags.useFiber
26 + ? require('ReactNativeFiber-prod')
27 + : require('ReactNativeStack-prod');
28 +}
29 +
30 +module.exports = (ReactNative: ReactNativeType);
scripts/rollup/shims/react-native/ReactNativeFeatureFlags.js new
+19
@@ -0,0 +1,19 @@
1 +/**
2 + * Copyright 2013-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactNativeFeatureFlags
10 + * @flow
11 + */
12 +
13 +'use strict';
14 +
15 +var ReactNativeFeatureFlags = {
16 + useFiber: false,
17 +};
18 +
19 +module.exports = ReactNativeFeatureFlags;
scripts/rollup/shims/react-native/findNodeHandle.js deleted
-30
@@ -1,30 +0,0 @@
1 -/**
2 - * Copyright 2013-present, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - * @providesModule findNodeHandle
10 - * @flow
11 - */
12 -
13 -'use strict';
14 -
15 -// While ReactNative renderer bundle is initializing, some
16 -// code (e.g. UIManager) imports from ReactNative.
17 -
18 -// We use an indirection to avoid a circular dependency.
19 -
20 -let realFindNodeHandle = null;
21 -
22 -function findNodeHandle(componentOrHandle: any): ?number {
23 - if (realFindNodeHandle === null) {
24 - realFindNodeHandle = require('ReactNative')
25 - .__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.findNodeHandle;
26 - }
27 - return realFindNodeHandle(componentOrHandle);
28 -}
29 -
30 -module.exports = findNodeHandle;
scripts/rollup/shims/react-native/takeSnapshot.js renamed
+2 -2
@@ -6,7 +6,7 @@
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 *
9 - * @providesModule ReactErrorUtils
9 + * @providesModule takeSnapshot
10 */
11
12 'use strict';
@@ -16,4 +16,4 @@ const {
16 } = require('ReactNative');
17
18 module.exports =
19 - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactErrorUtils;
19 + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.takeSnapshot;
scripts/rollup/sync.js new
+37
@@ -0,0 +1,37 @@
1 +'use strict';
2 +
3 +const asyncCopyTo = require('./utils').asyncCopyTo;
4 +const chalk = require('chalk');
5 +const resolvePath = require('./utils').resolvePath;
6 +
7 +const DEFAULT_FB_SOURCE_PATH = '~/fbsource/';
8 +const RELATIVE_RN_PATH = 'xplat/js/react-native-github/Libraries/Renderer/';
9 +
10 +function syncReactNative(buildPath, fbSourcePath) {
11 + fbSourcePath = typeof fbSourcePath === 'string'
12 + ? fbSourcePath
13 + : DEFAULT_FB_SOURCE_PATH;
14 +
15 + if (fbSourcePath.charAt(fbSourcePath.length - 1) !== '/') {
16 + fbSourcePath += '/';
17 + }
18 +
19 + const destPath = resolvePath(fbSourcePath + RELATIVE_RN_PATH);
20 +
21 + console.log(
22 + `${chalk.bgYellow.black(' SYNCING ')} ReactNative to ${destPath}`
23 + );
24 +
25 + const promise = asyncCopyTo(buildPath, destPath);
26 + promise.then(() => {
27 + console.log(
28 + `${chalk.bgGreen.black(' SYNCED ')} ReactNative to ${destPath}`
29 + );
30 + });
31 +
32 + return promise;
33 +}
34 +
35 +module.exports = {
36 + syncReactNative: syncReactNative,
37 +};
scripts/rollup/utils.js new
+30
@@ -0,0 +1,30 @@
1 +'use strict';
2 +
3 +const ncp = require('ncp').ncp;
4 +const join = require('path').join;
5 +const resolve = require('path').resolve;
6 +
7 +function asyncCopyTo(from, to) {
8 + return new Promise(_resolve => {
9 + ncp(from, to, error => {
10 + if (error) {
11 + console.error(error);
12 + process.exit(1);
13 + }
14 + _resolve();
15 + });
16 + });
17 +}
18 +
19 +function resolvePath(path) {
20 + if (path[0] === '~') {
21 + return join(process.env.HOME, path.slice(1));
22 + } else {
23 + return resolve(path);
24 + }
25 +}
26 +
27 +module.exports = {
28 + asyncCopyTo: asyncCopyTo,
29 + resolvePath: resolvePath,
30 +};
src/renderers/native/NativeMethodsMixin.js
+18 -23
@@ -11,7 +11,6 @@
11 */
12 'use strict';
13
14 -var ReactNative = require('ReactNative');
14 var ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
15 var ReactNativeAttributePayload = require('ReactNativeAttributePayload');
16 var TextInputState = require('TextInputState');
@@ -30,11 +29,16 @@ import type {
29 MeasureInWindowOnSuccessCallback,
30 MeasureLayoutOnSuccessCallback,
31 MeasureOnSuccessCallback,
33 -} from 'NativeMethodsMixinUtils';
32 + NativeMethodsMixinType,
33 +} from 'ReactNativeTypes';
34 import type {
35 ReactNativeBaseComponentViewConfig,
36 } from 'ReactNativeViewConfigRegistry';
37
38 +const findNumericNodeHandle = ReactNativeFeatureFlags.useFiber
39 + ? require('findNumericNodeHandleFiber')
40 + : require('findNumericNodeHandleStack');
41 +
42 /**
43 * `NativeMethodsMixin` provides methods to access the underlying native
44 * component directly. This can be useful in cases when you want to focus
@@ -46,12 +50,11 @@ import type {
50 * generally include most components that you define in your own app. For more
51 * information, see [Direct
52 * Manipulation](docs/direct-manipulation.html).
53 + *
54 + * Note the Flow $Exact<> syntax is required to support mixins.
55 + * React createClass mixins can only be used with exact types.
56 */
50 -// TODO (bvaughn) Figure out how to use the NativeMethodsInterface type to-
51 -// ensure that these mixins and ReactNativeFiberHostComponent stay in sync.
52 -// Unfortunately, using it causes Flow to complain WRT createClass mixins:
53 -// "call of method `createClass`. Expected an exact object instead of ..."
54 -var NativeMethodsMixin = {
57 +var NativeMethodsMixin: $Exact<NativeMethodsMixinType> = {
58 /**
59 * Determines the location on screen, width, and height of the given view and
60 * returns the values via an async callback. If successful, the callback will
@@ -71,7 +74,7 @@ var NativeMethodsMixin = {
74 */
75 measure: function(callback: MeasureOnSuccessCallback) {
76 UIManager.measure(
74 - ReactNative.findNodeHandle(this),
77 + findNumericNodeHandle(this),
78 mountSafeCallback(this, callback),
79 );
80 },
@@ -93,7 +96,7 @@ var NativeMethodsMixin = {
96 */
97 measureInWindow: function(callback: MeasureInWindowOnSuccessCallback) {
98 UIManager.measureInWindow(
96 - ReactNative.findNodeHandle(this),
99 + findNumericNodeHandle(this),
100 mountSafeCallback(this, callback),
101 );
102 },
@@ -104,7 +107,7 @@ var NativeMethodsMixin = {
107 * are relative to the origin x, y of the ancestor view.
108 *
109 * As always, to obtain a native node handle for a component, you can use
107 - * `ReactNative.findNodeHandle(component)`.
110 + * `findNumericNodeHandle(component)`.
111 */
112 measureLayout: function(
113 relativeToNativeNode: number,
@@ -112,7 +115,7 @@ var NativeMethodsMixin = {
115 onFail: () => void /* currently unused */,
116 ) {
117 UIManager.measureLayout(
115 - ReactNative.findNodeHandle(this),
118 + findNumericNodeHandle(this),
119 relativeToNativeNode,
120 mountSafeCallback(this, onFail),
121 mountSafeCallback(this, onSuccess),
@@ -126,14 +129,6 @@ var NativeMethodsMixin = {
129 * Manipulation](docs/direct-manipulation.html)).
130 */
131 setNativeProps: function(nativeProps: Object) {
129 - // Ensure ReactNative factory function has configured findNodeHandle.
130 - // Requiring it won't execute the factory function until first referenced.
131 - // It's possible for tests that use ReactTestRenderer to reach this point,
132 - // Without having executed ReactNative.
133 - // Defer the factory function until now to avoid a cycle with UIManager.
134 - // TODO (bvaughn) Remove this once ReactNativeStack is dropped.
135 - require('ReactNative');
136 -
132 injectedSetNativeProps(this, nativeProps);
133 },
134
@@ -142,14 +137,14 @@ var NativeMethodsMixin = {
137 * will depend on the platform and type of view.
138 */
139 focus: function() {
145 - TextInputState.focusTextInput(ReactNative.findNodeHandle(this));
140 + TextInputState.focusTextInput(findNumericNodeHandle(this));
141 },
142
143 /**
144 * Removes focus from an input or view. This is the opposite of `focus()`.
145 */
146 blur: function() {
152 - TextInputState.blurTextInput(ReactNative.findNodeHandle(this));
147 + TextInputState.blurTextInput(findNumericNodeHandle(this));
148 },
149 };
150
@@ -158,7 +153,7 @@ function setNativePropsFiber(componentOrHandle: any, nativeProps: Object) {
153 // Class components don't have viewConfig -> validateAttributes.
154 // Nor does it make sense to set native props on a non-native component.
155 // Instead, find the nearest host component and set props on it.
161 - // Use findNodeHandle() rather than ReactNative.findNodeHandle() because
156 + // Use findNodeHandle() rather than findNumericNodeHandle() because
157 // We want the instance/wrapper (not the native tag).
158 let maybeInstance;
159
@@ -200,7 +195,7 @@ function setNativePropsStack(componentOrHandle: any, nativeProps: Object) {
195 // Class components don't have viewConfig -> validateAttributes.
196 // Nor does it make sense to set native props on a non-native component.
197 // Instead, find the nearest host component and set props on it.
203 - // Use findNodeHandle() rather than ReactNative.findNodeHandle() because
198 + // Use findNodeHandle() rather than findNumericNodeHandle() because
199 // We want the instance/wrapper (not the native tag).
200 let maybeInstance = findNodeHandle(componentOrHandle);
201
src/renderers/native/NativeMethodsMixinUtils.js
-40
@@ -11,46 +11,6 @@
11 */
12 'use strict';
13
14 -export type MeasureOnSuccessCallback = (
15 - x: number,
16 - y: number,
17 - width: number,
18 - height: number,
19 - pageX: number,
20 - pageY: number,
21 -) => void;
22 -
23 -export type MeasureInWindowOnSuccessCallback = (
24 - x: number,
25 - y: number,
26 - width: number,
27 - height: number,
28 -) => void;
29 -
30 -export type MeasureLayoutOnSuccessCallback = (
31 - left: number,
32 - top: number,
33 - width: number,
34 - height: number,
35 -) => void;
36 -
37 -/**
38 - * Shared between ReactNativeFiberHostComponent and NativeMethodsMixin to keep
39 - * API in sync.
40 - */
41 -export interface NativeMethodsInterface {
42 - blur(): void,
43 - focus(): void,
44 - measure(callback: MeasureOnSuccessCallback): void,
45 - measureInWindow(callback: MeasureInWindowOnSuccessCallback): void,
46 - measureLayout(
47 - relativeToNativeNode: number,
48 - onSuccess: MeasureLayoutOnSuccessCallback,
49 - onFail: () => void,
50 - ): void,
51 - setNativeProps(nativeProps: Object): void,
52 -}
53 -
14 /**
15 * In the future, we should cleanup callbacks by cancelling them instead of
16 * using this.
src/renderers/native/ReactNativeFeatureFlags.js
+3 -1
@@ -12,8 +12,10 @@
12
13 'use strict';
14
15 +// Read from process.env in order to support Rollup flat bundles.
16 +// Jest test script will also write this value for Fiber tests.
17 var ReactNativeFeatureFlags = {
16 - useFiber: false,
18 + useFiber: process.env.REACT_NATIVE_USE_FIBER,
19 };
20
21 module.exports = ReactNativeFeatureFlags;
src/renderers/native/ReactNativeFiber.js
+36 -384
@@ -13,412 +13,40 @@
13 'use strict';
14
15 const ReactFiberErrorLogger = require('ReactFiberErrorLogger');
16 -const ReactFiberReconciler = require('ReactFiberReconciler');
16 const ReactGenericBatching = require('ReactGenericBatching');
18 -const ReactNativeAttributePayload = require('ReactNativeAttributePayload');
19 -const ReactNativeComponentTree = require('ReactNativeComponentTree');
17 const ReactNativeFiberErrorDialog = require('ReactNativeFiberErrorDialog');
21 -const ReactNativeFiberHostComponent = require('ReactNativeFiberHostComponent');
18 const ReactNativeInjection = require('ReactNativeInjection');
23 -const ReactNativeTagHandles = require('ReactNativeTagHandles');
24 -const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
19 const ReactPortal = require('ReactPortal');
20 +const ReactNativeComponentTree = require('ReactNativeComponentTree');
21 +const ReactNativeFiberRenderer = require('ReactNativeFiberRenderer');
22 const ReactNativeFiberInspector = require('ReactNativeFiberInspector');
23 const ReactVersion = require('ReactVersion');
24 const UIManager = require('UIManager');
25
30 -const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
31 -const emptyObject = require('fbjs/lib/emptyObject');
32 -const findNodeHandle = require('findNodeHandle');
33 -const invariant = require('fbjs/lib/invariant');
26 +const findNumericNodeHandle = require('findNumericNodeHandleFiber');
27
28 const {injectInternals} = require('ReactFiberDevToolsHook');
29
30 import type {Element} from 'React';
38 -import type {Fiber} from 'ReactFiber';
39 -import type {
40 - ReactNativeBaseComponentViewConfig,
41 -} from 'ReactNativeViewConfigRegistry';
31 +import type {ReactNativeType} from 'ReactNativeTypes';
32 import type {ReactNodeList} from 'ReactTypes';
43 -const {
44 - precacheFiberNode,
45 - uncacheFiberNode,
46 - updateFiberProps,
47 -} = ReactNativeComponentTree;
33
34 ReactNativeInjection.inject();
35
51 -type Container = number;
52 -export type Instance = {
53 - _children: Array<Instance | number>,
54 - _nativeTag: number,
55 - viewConfig: ReactNativeBaseComponentViewConfig,
56 -};
57 -type Props = Object;
58 -type TextInstance = number;
59 -
60 -function recursivelyUncacheFiberNode(node: Instance | TextInstance) {
61 - if (typeof node === 'number') {
62 - // Leaf node (eg text)
63 - uncacheFiberNode(node);
64 - } else {
65 - uncacheFiberNode((node: any)._nativeTag);
66 -
67 - (node: any)._children.forEach(recursivelyUncacheFiberNode);
68 - }
69 -}
70 -
71 -const NativeRenderer = ReactFiberReconciler({
72 - appendChild(
73 - parentInstance: Instance | Container,
74 - child: Instance | TextInstance,
75 - ): void {
76 - const childTag = typeof child === 'number' ? child : child._nativeTag;
77 -
78 - if (typeof parentInstance === 'number') {
79 - // Root container
80 - UIManager.setChildren(
81 - parentInstance, // containerTag
82 - [childTag], // reactTags
83 - );
84 - } else {
85 - const children = parentInstance._children;
86 -
87 - const index = children.indexOf(child);
88 -
89 - if (index >= 0) {
90 - children.splice(index, 1);
91 - children.push(child);
92 -
93 - UIManager.manageChildren(
94 - parentInstance._nativeTag, // containerTag
95 - [index], // moveFromIndices
96 - [children.length - 1], // moveToIndices
97 - [], // addChildReactTags
98 - [], // addAtIndices
99 - [], // removeAtIndices
100 - );
101 - } else {
102 - children.push(child);
103 -
104 - UIManager.manageChildren(
105 - parentInstance._nativeTag, // containerTag
106 - [], // moveFromIndices
107 - [], // moveToIndices
108 - [childTag], // addChildReactTags
109 - [children.length - 1], // addAtIndices
110 - [], // removeAtIndices
111 - );
112 - }
113 - }
114 - },
115 -
116 - appendInitialChild(
117 - parentInstance: Instance,
118 - child: Instance | TextInstance,
119 - ): void {
120 - parentInstance._children.push(child);
121 - },
122 -
123 - commitTextUpdate(
124 - textInstance: TextInstance,
125 - oldText: string,
126 - newText: string,
127 - ): void {
128 - UIManager.updateView(
129 - textInstance, // reactTag
130 - 'RCTRawText', // viewName
131 - {text: newText}, // props
132 - );
133 - },
134 -
135 - commitMount(
136 - instance: Instance,
137 - type: string,
138 - newProps: Props,
139 - internalInstanceHandle: Object,
140 - ): void {
141 - // Noop
142 - },
143 -
144 - commitUpdate(
145 - instance: Instance,
146 - updatePayloadTODO: Object,
147 - type: string,
148 - oldProps: Props,
149 - newProps: Props,
150 - internalInstanceHandle: Object,
151 - ): void {
152 - const viewConfig = instance.viewConfig;
153 -
154 - updateFiberProps(instance._nativeTag, newProps);
155 -
156 - const updatePayload = ReactNativeAttributePayload.diff(
157 - oldProps,
158 - newProps,
159 - viewConfig.validAttributes,
160 - );
161 -
162 - UIManager.updateView(
163 - instance._nativeTag, // reactTag
164 - viewConfig.uiViewClassName, // viewName
165 - updatePayload, // props
166 - );
167 - },
168 -
169 - createInstance(
170 - type: string,
171 - props: Props,
172 - rootContainerInstance: Container,
173 - hostContext: {},
174 - internalInstanceHandle: Object,
175 - ): Instance {
176 - const tag = ReactNativeTagHandles.allocateTag();
177 - const viewConfig = ReactNativeViewConfigRegistry.get(type);
178 -
179 - if (__DEV__) {
180 - for (const key in viewConfig.validAttributes) {
181 - if (props.hasOwnProperty(key)) {
182 - deepFreezeAndThrowOnMutationInDev(props[key]);
183 - }
184 - }
185 - }
186 -
187 - const updatePayload = ReactNativeAttributePayload.create(
188 - props,
189 - viewConfig.validAttributes,
190 - );
191 -
192 - UIManager.createView(
193 - tag, // reactTag
194 - viewConfig.uiViewClassName, // viewName
195 - rootContainerInstance, // rootTag
196 - updatePayload, // props
197 - );
198 -
199 - const component = new ReactNativeFiberHostComponent(tag, viewConfig);
200 -
201 - precacheFiberNode(internalInstanceHandle, tag);
202 - updateFiberProps(tag, props);
203 -
204 - // Not sure how to avoid this cast. Flow is okay if the component is defined
205 - // in the same file but if it's external it can't see the types.
206 - return ((component: any): Instance);
207 - },
208 -
209 - createTextInstance(
210 - text: string,
211 - rootContainerInstance: Container,
212 - hostContext: {},
213 - internalInstanceHandle: Object,
214 - ): TextInstance {
215 - const tag = ReactNativeTagHandles.allocateTag();
216 -
217 - UIManager.createView(
218 - tag, // reactTag
219 - 'RCTRawText', // viewName
220 - rootContainerInstance, // rootTag
221 - {text: text}, // props
222 - );
223 -
224 - precacheFiberNode(internalInstanceHandle, tag);
225 -
226 - return tag;
227 - },
228 -
229 - finalizeInitialChildren(
230 - parentInstance: Instance,
231 - type: string,
232 - props: Props,
233 - rootContainerInstance: Container,
234 - ): boolean {
235 - // Don't send a no-op message over the bridge.
236 - if (parentInstance._children.length === 0) {
237 - return false;
238 - }
239 -
240 - // Map from child objects to native tags.
241 - // Either way we need to pass a copy of the Array to prevent it from being frozen.
242 - const nativeTags = parentInstance._children.map(
243 - child =>
244 - (typeof child === 'number'
245 - ? child // Leaf node (eg text)
246 - : child._nativeTag),
247 - );
248 -
249 - UIManager.setChildren(
250 - parentInstance._nativeTag, // containerTag
251 - nativeTags, // reactTags
252 - );
253 -
254 - return false;
255 - },
256 -
257 - getRootHostContext(): {} {
258 - return emptyObject;
259 - },
260 -
261 - getChildHostContext(): {} {
262 - return emptyObject;
263 - },
264 -
265 - getPublicInstance(instance) {
266 - return instance;
267 - },
268 -
269 - insertBefore(
270 - parentInstance: Instance | Container,
271 - child: Instance | TextInstance,
272 - beforeChild: Instance | TextInstance,
273 - ): void {
274 - // TODO (bvaughn): Remove this check when...
275 - // We create a wrapper object for the container in ReactNative render()
276 - // Or we refactor to remove wrapper objects entirely.
277 - // For more info on pros/cons see PR #8560 description.
278 - invariant(
279 - typeof parentInstance !== 'number',
280 - 'Container does not support insertBefore operation',
281 - );
282 -
283 - const children = (parentInstance: any)._children;
284 -
285 - const index = children.indexOf(child);
286 -
287 - // Move existing child or add new child?
288 - if (index >= 0) {
289 - children.splice(index, 1);
290 - const beforeChildIndex = children.indexOf(beforeChild);
291 - children.splice(beforeChildIndex, 0, child);
292 -
293 - UIManager.manageChildren(
294 - (parentInstance: any)._nativeTag, // containerID
295 - [index], // moveFromIndices
296 - [beforeChildIndex], // moveToIndices
297 - [], // addChildReactTags
298 - [], // addAtIndices
299 - [], // removeAtIndices
300 - );
301 - } else {
302 - const beforeChildIndex = children.indexOf(beforeChild);
303 - children.splice(beforeChildIndex, 0, child);
304 -
305 - const childTag = typeof child === 'number' ? child : child._nativeTag;
306 -
307 - UIManager.manageChildren(
308 - (parentInstance: any)._nativeTag, // containerID
309 - [], // moveFromIndices
310 - [], // moveToIndices
311 - [childTag], // addChildReactTags
312 - [beforeChildIndex], // addAtIndices
313 - [], // removeAtIndices
314 - );
315 - }
316 - },
317 -
318 - prepareForCommit(): void {
319 - // Noop
320 - },
321 -
322 - prepareUpdate(
323 - instance: Instance,
324 - type: string,
325 - oldProps: Props,
326 - newProps: Props,
327 - rootContainerInstance: Container,
328 - hostContext: {},
329 - ): null | Object {
330 - return emptyObject;
331 - },
332 -
333 - removeChild(
334 - parentInstance: Instance | Container,
335 - child: Instance | TextInstance,
336 - ): void {
337 - recursivelyUncacheFiberNode(child);
338 -
339 - if (typeof parentInstance === 'number') {
340 - UIManager.manageChildren(
341 - parentInstance, // containerID
342 - [], // moveFromIndices
343 - [], // moveToIndices
344 - [], // addChildReactTags
345 - [], // addAtIndices
346 - [0], // removeAtIndices
347 - );
348 - } else {
349 - const children = parentInstance._children;
350 - const index = children.indexOf(child);
351 -
352 - children.splice(index, 1);
353 -
354 - UIManager.manageChildren(
355 - parentInstance._nativeTag, // containerID
356 - [], // moveFromIndices
357 - [], // moveToIndices
358 - [], // addChildReactTags
359 - [], // addAtIndices
360 - [index], // removeAtIndices
361 - );
362 - }
363 - },
364 -
365 - resetAfterCommit(): void {
366 - // Noop
367 - },
368 -
369 - resetTextContent(instance: Instance): void {
370 - // Noop
371 - },
372 -
373 - shouldDeprioritizeSubtree(type: string, props: Props): boolean {
374 - return false;
375 - },
376 -
377 - scheduleAnimationCallback: global.requestAnimationFrame,
378 -
379 - scheduleDeferredCallback: global.requestIdleCallback,
380 -
381 - shouldSetTextContent(props: Props): boolean {
382 - // TODO (bvaughn) Revisit this decision.
383 - // Always returning false simplifies the createInstance() implementation,
384 - // But creates an additional child Fiber for raw text children.
385 - // No additional native views are created though.
386 - // It's not clear to me which is better so I'm deferring for now.
387 - // More context @ github.com/facebook/react/pull/8560#discussion_r92111303
388 - return false;
389 - },
390 -
391 - useSyncScheduling: true,
392 -});
393 -
36 ReactGenericBatching.injection.injectFiberBatchedUpdates(
395 - NativeRenderer.batchedUpdates,
37 + ReactNativeFiberRenderer.batchedUpdates,
38 );
39
40 const roots = new Map();
41
400 -findNodeHandle.injection.injectFindNode((fiber: Fiber) =>
401 - NativeRenderer.findHostInstance(fiber),
402 -);
403 -findNodeHandle.injection.injectFindRootNodeID(instance => instance);
404 -
42 // Intercept lifecycle errors and ensure they are shown with the correct stack
43 // trace within the native redbox component.
44 ReactFiberErrorLogger.injection.injectDialog(
45 ReactNativeFiberErrorDialog.showDialog,
46 );
47
411 -const ReactNative = {
412 - // External users of findNodeHandle() expect the host tag number return type.
413 - // The injected findNodeHandle() strategy returns the instance wrapper though.
414 - // See NativeMethodsMixin#setNativeProps for more info on why this is done.
415 - findNodeHandle(componentOrHandle: any): ?number {
416 - const instance: any = findNodeHandle(componentOrHandle);
417 - if (instance == null || typeof instance === 'number') {
418 - return instance;
419 - }
420 - return instance._nativeTag;
421 - },
48 +var ReactNative: ReactNativeType = {
49 + findNodeHandle: findNumericNodeHandle,
50
51 render(element: Element<any>, containerTag: any, callback: ?Function) {
52 let root = roots.get(containerTag);
@@ -426,19 +54,19 @@ const ReactNative = {
54 if (!root) {
55 // TODO (bvaughn): If we decide to keep the wrapper component,
56 // We could create a wrapper for containerTag as well to reduce special casing.
429 - root = NativeRenderer.createContainer(containerTag);
57 + root = ReactNativeFiberRenderer.createContainer(containerTag);
58 roots.set(containerTag, root);
59 }
432 - NativeRenderer.updateContainer(element, root, null, callback);
60 + ReactNativeFiberRenderer.updateContainer(element, root, null, callback);
61
434 - return NativeRenderer.getPublicRootInstance(root);
62 + return ReactNativeFiberRenderer.getPublicRootInstance(root);
63 },
64
65 unmountComponentAtNode(containerTag: number) {
66 const root = roots.get(containerTag);
67 if (root) {
68 // TODO: Is it safe to reset this now or should I wait since this unmount could be deferred?
441 - NativeRenderer.updateContainer(null, root, null, () => {
69 + ReactNativeFiberRenderer.updateContainer(null, root, null, () => {
70 roots.delete(containerTag);
71 });
72 }
@@ -460,12 +88,36 @@ const ReactNative = {
88 },
89
90 unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
91 +
92 + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
93 + // Used as a mixin in many createClass-based components
94 + NativeMethodsMixin: require('NativeMethodsMixin'),
95 +
96 + // Used by react-native-github/Libraries/ components
97 + ReactGlobalSharedState: require('ReactGlobalSharedState'), // Systrace
98 + ReactNativeComponentTree: require('ReactNativeComponentTree'), // InspectorUtils, ScrollResponder
99 + ReactNativePropRegistry: require('ReactNativePropRegistry'), // flattenStyle, Stylesheet
100 + TouchHistoryMath: require('TouchHistoryMath'), // PanResponder
101 + createReactNativeComponentClass: require('createReactNativeComponentClass'), // eg Text
102 + takeSnapshot: require('takeSnapshot'), // react-native-implementation
103 + },
104 };
105
106 +if (__DEV__) {
107 + // $FlowFixMe
108 + Object.assign(
109 + ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
110 + {
111 + ReactDebugTool: require('ReactDebugTool'), // RCTRenderingPerf, Systrace
112 + ReactPerf: require('ReactPerf'), // ReactPerfStallHandler, RCTRenderingPerf
113 + },
114 + );
115 +}
116 +
117 if (typeof injectInternals === 'function') {
118 injectInternals({
119 findFiberByHostInstance: ReactNativeComponentTree.getClosestInstanceFromNode,
468 - findHostInstanceByFiber: NativeRenderer.findHostInstance,
120 + findHostInstanceByFiber: ReactNativeFiberRenderer.findHostInstance,
121 getInspectorDataForViewTag: ReactNativeFiberInspector.getInspectorDataForViewTag,
122 // This is an enum because we may add more (e.g. profiler build)
123 bundleType: __DEV__ ? 1 : 0,
src/renderers/native/ReactNativeFiberHostComponent.js
+7 -4
@@ -23,9 +23,9 @@ import type {
23 MeasureInWindowOnSuccessCallback,
24 MeasureLayoutOnSuccessCallback,
25 MeasureOnSuccessCallback,
26 - NativeMethodsInterface,
27 -} from 'NativeMethodsMixinUtils';
28 -import type {Instance} from 'ReactNativeFiber';
26 + NativeMethodsMixinType,
27 +} from 'ReactNativeTypes';
28 +import type {Instance} from 'ReactNativeFiberRenderer';
29 import type {
30 ReactNativeBaseComponentViewConfig,
31 } from 'ReactNativeViewConfigRegistry';
@@ -37,7 +37,7 @@ import type {
37 * ReactNativeFiber depends on this component and NativeMethodsMixin depends on
38 * ReactNativeFiber).
39 */
40 -class ReactNativeFiberHostComponent implements NativeMethodsInterface {
40 +class ReactNativeFiberHostComponent {
41 _children: Array<Instance | number>;
42 _nativeTag: number;
43 viewConfig: ReactNativeBaseComponentViewConfig;
@@ -98,4 +98,7 @@ class ReactNativeFiberHostComponent implements NativeMethodsInterface {
98 }
99 }
100
101 +// eslint-disable-next-line no-unused-expressions
102 +(ReactNativeFiberHostComponent.prototype: NativeMethodsMixinType);
103 +
104 module.exports = ReactNativeFiberHostComponent;
src/renderers/native/ReactNativeFiberRenderer.js new
+380
@@ -0,0 +1,380 @@
1 +/**
2 + * Copyright 2013-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactNativeFiberRenderer
10 + * @flow
11 + */
12 +
13 +'use strict';
14 +
15 +const ReactFiberReconciler = require('ReactFiberReconciler');
16 +const ReactNativeAttributePayload = require('ReactNativeAttributePayload');
17 +const ReactNativeComponentTree = require('ReactNativeComponentTree');
18 +const ReactNativeFiberHostComponent = require('ReactNativeFiberHostComponent');
19 +const ReactNativeTagHandles = require('ReactNativeTagHandles');
20 +const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
21 +const UIManager = require('UIManager');
22 +
23 +const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
24 +const emptyObject = require('fbjs/lib/emptyObject');
25 +const invariant = require('fbjs/lib/invariant');
26 +
27 +import type {
28 + ReactNativeBaseComponentViewConfig,
29 +} from 'ReactNativeViewConfigRegistry';
30 +
31 +export type Container = number;
32 +export type Instance = {
33 + _children: Array<Instance | number>,
34 + _nativeTag: number,
35 + viewConfig: ReactNativeBaseComponentViewConfig,
36 +};
37 +export type Props = Object;
38 +export type TextInstance = number;
39 +
40 +const {
41 + precacheFiberNode,
42 + uncacheFiberNode,
43 + updateFiberProps,
44 +} = ReactNativeComponentTree;
45 +
46 +function recursivelyUncacheFiberNode(node: Instance | TextInstance) {
47 + if (typeof node === 'number') {
48 + // Leaf node (eg text)
49 + uncacheFiberNode(node);
50 + } else {
51 + uncacheFiberNode((node: any)._nativeTag);
52 +
53 + (node: any)._children.forEach(recursivelyUncacheFiberNode);
54 + }
55 +}
56 +
57 +const NativeRenderer = ReactFiberReconciler({
58 + appendChild(
59 + parentInstance: Instance | Container,
60 + child: Instance | TextInstance,
61 + ): void {
62 + const childTag = typeof child === 'number' ? child : child._nativeTag;
63 +
64 + if (typeof parentInstance === 'number') {
65 + // Root container
66 + UIManager.setChildren(
67 + parentInstance, // containerTag
68 + [childTag], // reactTags
69 + );
70 + } else {
71 + const children = parentInstance._children;
72 +
73 + const index = children.indexOf(child);
74 +
75 + if (index >= 0) {
76 + children.splice(index, 1);
77 + children.push(child);
78 +
79 + UIManager.manageChildren(
80 + parentInstance._nativeTag, // containerTag
81 + [index], // moveFromIndices
82 + [children.length - 1], // moveToIndices
83 + [], // addChildReactTags
84 + [], // addAtIndices
85 + [], // removeAtIndices
86 + );
87 + } else {
88 + children.push(child);
89 +
90 + UIManager.manageChildren(
91 + parentInstance._nativeTag, // containerTag
92 + [], // moveFromIndices
93 + [], // moveToIndices
94 + [childTag], // addChildReactTags
95 + [children.length - 1], // addAtIndices
96 + [], // removeAtIndices
97 + );
98 + }
99 + }
100 + },
101 +
102 + appendInitialChild(
103 + parentInstance: Instance,
104 + child: Instance | TextInstance,
105 + ): void {
106 + parentInstance._children.push(child);
107 + },
108 +
109 + commitTextUpdate(
110 + textInstance: TextInstance,
111 + oldText: string,
112 + newText: string,
113 + ): void {
114 + UIManager.updateView(
115 + textInstance, // reactTag
116 + 'RCTRawText', // viewName
117 + {text: newText}, // props
118 + );
119 + },
120 +
121 + commitMount(
122 + instance: Instance,
123 + type: string,
124 + newProps: Props,
125 + internalInstanceHandle: Object,
126 + ): void {
127 + // Noop
128 + },
129 +
130 + commitUpdate(
131 + instance: Instance,
132 + updatePayloadTODO: Object,
133 + type: string,
134 + oldProps: Props,
135 + newProps: Props,
136 + internalInstanceHandle: Object,
137 + ): void {
138 + const viewConfig = instance.viewConfig;
139 +
140 + updateFiberProps(instance._nativeTag, newProps);
141 +
142 + const updatePayload = ReactNativeAttributePayload.diff(
143 + oldProps,
144 + newProps,
145 + viewConfig.validAttributes,
146 + );
147 +
148 + UIManager.updateView(
149 + instance._nativeTag, // reactTag
150 + viewConfig.uiViewClassName, // viewName
151 + updatePayload, // props
152 + );
153 + },
154 +
155 + createInstance(
156 + type: string,
157 + props: Props,
158 + rootContainerInstance: Container,
159 + hostContext: {},
160 + internalInstanceHandle: Object,
161 + ): Instance {
162 + const tag = ReactNativeTagHandles.allocateTag();
163 + const viewConfig = ReactNativeViewConfigRegistry.get(type);
164 +
165 + if (__DEV__) {
166 + for (const key in viewConfig.validAttributes) {
167 + if (props.hasOwnProperty(key)) {
168 + deepFreezeAndThrowOnMutationInDev(props[key]);
169 + }
170 + }
171 + }
172 +
173 + const updatePayload = ReactNativeAttributePayload.create(
174 + props,
175 + viewConfig.validAttributes,
176 + );
177 +
178 + UIManager.createView(
179 + tag, // reactTag
180 + viewConfig.uiViewClassName, // viewName
181 + rootContainerInstance, // rootTag
182 + updatePayload, // props
183 + );
184 +
185 + const component = new ReactNativeFiberHostComponent(tag, viewConfig);
186 +
187 + precacheFiberNode(internalInstanceHandle, tag);
188 + updateFiberProps(tag, props);
189 +
190 + // Not sure how to avoid this cast. Flow is okay if the component is defined
191 + // in the same file but if it's external it can't see the types.
192 + return ((component: any): Instance);
193 + },
194 +
195 + createTextInstance(
196 + text: string,
197 + rootContainerInstance: Container,
198 + hostContext: {},
199 + internalInstanceHandle: Object,
200 + ): TextInstance {
201 + const tag = ReactNativeTagHandles.allocateTag();
202 +
203 + UIManager.createView(
204 + tag, // reactTag
205 + 'RCTRawText', // viewName
206 + rootContainerInstance, // rootTag
207 + {text: text}, // props
208 + );
209 +
210 + precacheFiberNode(internalInstanceHandle, tag);
211 +
212 + return tag;
213 + },
214 +
215 + finalizeInitialChildren(
216 + parentInstance: Instance,
217 + type: string,
218 + props: Props,
219 + rootContainerInstance: Container,
220 + ): boolean {
221 + // Don't send a no-op message over the bridge.
222 + if (parentInstance._children.length === 0) {
223 + return false;
224 + }
225 +
226 + // Map from child objects to native tags.
227 + // Either way we need to pass a copy of the Array to prevent it from being frozen.
228 + const nativeTags = parentInstance._children.map(
229 + child =>
230 + (typeof child === 'number'
231 + ? child // Leaf node (eg text)
232 + : child._nativeTag),
233 + );
234 +
235 + UIManager.setChildren(
236 + parentInstance._nativeTag, // containerTag
237 + nativeTags, // reactTags
238 + );
239 +
240 + return false;
241 + },
242 +
243 + getRootHostContext(): {} {
244 + return emptyObject;
245 + },
246 +
247 + getChildHostContext(): {} {
248 + return emptyObject;
249 + },
250 +
251 + getPublicInstance(instance) {
252 + return instance;
253 + },
254 +
255 + insertBefore(
256 + parentInstance: Instance | Container,
257 + child: Instance | TextInstance,
258 + beforeChild: Instance | TextInstance,
259 + ): void {
260 + // TODO (bvaughn): Remove this check when...
261 + // We create a wrapper object for the container in ReactNative render()
262 + // Or we refactor to remove wrapper objects entirely.
263 + // For more info on pros/cons see PR #8560 description.
264 + invariant(
265 + typeof parentInstance !== 'number',
266 + 'Container does not support insertBefore operation',
267 + );
268 +
269 + const children = (parentInstance: any)._children;
270 +
271 + const index = children.indexOf(child);
272 +
273 + // Move existing child or add new child?
274 + if (index >= 0) {
275 + children.splice(index, 1);
276 + const beforeChildIndex = children.indexOf(beforeChild);
277 + children.splice(beforeChildIndex, 0, child);
278 +
279 + UIManager.manageChildren(
280 + (parentInstance: any)._nativeTag, // containerID
281 + [index], // moveFromIndices
282 + [beforeChildIndex], // moveToIndices
283 + [], // addChildReactTags
284 + [], // addAtIndices
285 + [], // removeAtIndices
286 + );
287 + } else {
288 + const beforeChildIndex = children.indexOf(beforeChild);
289 + children.splice(beforeChildIndex, 0, child);
290 +
291 + const childTag = typeof child === 'number' ? child : child._nativeTag;
292 +
293 + UIManager.manageChildren(
294 + (parentInstance: any)._nativeTag, // containerID
295 + [], // moveFromIndices
296 + [], // moveToIndices
297 + [childTag], // addChildReactTags
298 + [beforeChildIndex], // addAtIndices
299 + [], // removeAtIndices
300 + );
301 + }
302 + },
303 +
304 + prepareForCommit(): void {
305 + // Noop
306 + },
307 +
308 + prepareUpdate(
309 + instance: Instance,
310 + type: string,
311 + oldProps: Props,
312 + newProps: Props,
313 + rootContainerInstance: Container,
314 + hostContext: {},
315 + ): null | Object {
316 + return emptyObject;
317 + },
318 +
319 + removeChild(
320 + parentInstance: Instance | Container,
321 + child: Instance | TextInstance,
322 + ): void {
323 + recursivelyUncacheFiberNode(child);
324 +
325 + if (typeof parentInstance === 'number') {
326 + UIManager.manageChildren(
327 + parentInstance, // containerID
328 + [], // moveFromIndices
329 + [], // moveToIndices
330 + [], // addChildReactTags
331 + [], // addAtIndices
332 + [0], // removeAtIndices
333 + );
334 + } else {
335 + const children = parentInstance._children;
336 + const index = children.indexOf(child);
337 +
338 + children.splice(index, 1);
339 +
340 + UIManager.manageChildren(
341 + parentInstance._nativeTag, // containerID
342 + [], // moveFromIndices
343 + [], // moveToIndices
344 + [], // addChildReactTags
345 + [], // addAtIndices
346 + [index], // removeAtIndices
347 + );
348 + }
349 + },
350 +
351 + resetAfterCommit(): void {
352 + // Noop
353 + },
354 +
355 + resetTextContent(instance: Instance): void {
356 + // Noop
357 + },
358 +
359 + shouldDeprioritizeSubtree(type: string, props: Props): boolean {
360 + return false;
361 + },
362 +
363 + scheduleAnimationCallback: global.requestAnimationFrame,
364 +
365 + scheduleDeferredCallback: global.requestIdleCallback,
366 +
367 + shouldSetTextContent(props: Props): boolean {
368 + // TODO (bvaughn) Revisit this decision.
369 + // Always returning false simplifies the createInstance() implementation,
370 + // But creates an additional child Fiber for raw text children.
371 + // No additional native views are created though.
372 + // It's not clear to me which is better so I'm deferring for now.
373 + // More context @ github.com/facebook/react/pull/8560#discussion_r92111303
374 + return false;
375 + },
376 +
377 + useSyncScheduling: true,
378 +});
379 +
380 +module.exports = NativeRenderer;
src/renderers/native/ReactNativeStack.js
+29 -12
@@ -18,7 +18,9 @@ var ReactNativeStackInjection = require('ReactNativeStackInjection');
18 var ReactUpdates = require('ReactUpdates');
19 var ReactNativeStackInspector = require('ReactNativeStackInspector');
20
21 -var findNodeHandle = require('findNodeHandle');
21 +var findNumericNodeHandle = require('findNumericNodeHandleStack');
22 +
23 +import type {ReactNativeType} from 'ReactNativeTypes';
24
25 ReactNativeInjection.inject();
26 ReactNativeStackInjection.inject();
@@ -31,19 +33,10 @@ var render = function(
33 return ReactNativeMount.renderComponent(element, mountInto, callback);
34 };
35
34 -var ReactNative = {
36 +var ReactNative: ReactNativeType = {
37 hasReactNativeInitialized: false,
38
37 - // External users of findNodeHandle() expect the host tag number return type.
38 - // The injected findNodeHandle() strategy returns the instance wrapper though.
39 - // See NativeMethodsMixin#setNativeProps for more info on why this is done.
40 - findNodeHandle(componentOrHandle: any): ?number {
41 - const nodeHandle = findNodeHandle(componentOrHandle);
42 - if (nodeHandle == null || typeof nodeHandle === 'number') {
43 - return nodeHandle;
44 - }
45 - return nodeHandle.getHostNode();
46 - },
39 + findNodeHandle: findNumericNodeHandle,
40
41 render: render,
42
@@ -54,8 +47,32 @@ var ReactNative = {
47 /* eslint-enable camelcase */
48
49 unmountComponentAtNodeAndRemoveContainer: ReactNativeMount.unmountComponentAtNodeAndRemoveContainer,
50 +
51 + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: {
52 + // Used as a mixin in many createClass-based components
53 + NativeMethodsMixin: require('NativeMethodsMixin'),
54 +
55 + // Used by react-native-github/Libraries/ components
56 + ReactGlobalSharedState: require('ReactGlobalSharedState'), // Systrace
57 + ReactNativeComponentTree: require('ReactNativeComponentTree'), // InspectorUtils, ScrollResponder
58 + ReactNativePropRegistry: require('ReactNativePropRegistry'), // flattenStyle, Stylesheet
59 + TouchHistoryMath: require('TouchHistoryMath'), // PanResponder
60 + createReactNativeComponentClass: require('createReactNativeComponentClass'), // eg Text
61 + takeSnapshot: require('takeSnapshot'), // react-native-implementation
62 + },
63 };
64
65 +if (__DEV__) {
66 + // $FlowFixMe
67 + Object.assign(
68 + ReactNative.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
69 + {
70 + ReactDebugTool: require('ReactDebugTool'), // RCTRenderingPerf, Systrace
71 + ReactPerf: require('ReactPerf'), // ReactPerfStallHandler, RCTRenderingPerf
72 + },
73 + );
74 +}
75 +
76 // Inject the runtime into a devtools global hook regardless of browser.
77 // Allows for debugging when the hook is injected on the page.
78 /* globals __REACT_DEVTOOLS_GLOBAL_HOOK__ */
src/renderers/native/ReactNativeStackInjection.js
-4
@@ -30,7 +30,6 @@ var ReactNativeTextComponent = require('ReactNativeTextComponent');
30 var ReactSimpleEmptyComponent = require('ReactSimpleEmptyComponent');
31 var ReactUpdates = require('ReactUpdates');
32
33 -var findNodeHandle = require('findNodeHandle');
33 var invariant = require('fbjs/lib/invariant');
34
35 function inject() {
@@ -60,9 +59,6 @@ function inject() {
59 );
60 };
61
63 - findNodeHandle.injection.injectFindNode(instance => instance);
64 - findNodeHandle.injection.injectFindRootNodeID(instance => instance);
65 -
62 ReactEmptyComponent.injection.injectEmptyComponentFactory(EmptyComponent);
63
64 ReactHostComponent.injection.injectTextComponentClass(
src/renderers/native/ReactNativeTypes.js new
+89
@@ -0,0 +1,89 @@
1 +/**
2 + * Copyright (c) 2015-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactNativeTypes
10 + * @flow
11 + */
12 +'use strict';
13 +
14 +import type React from 'react';
15 +
16 +export type MeasureOnSuccessCallback = (
17 + x: number,
18 + y: number,
19 + width: number,
20 + height: number,
21 + pageX: number,
22 + pageY: number,
23 +) => void;
24 +
25 +export type MeasureInWindowOnSuccessCallback = (
26 + x: number,
27 + y: number,
28 + width: number,
29 + height: number,
30 +) => void;
31 +
32 +export type MeasureLayoutOnSuccessCallback = (
33 + left: number,
34 + top: number,
35 + width: number,
36 + height: number,
37 +) => void;
38 +
39 +/**
40 + * This type keeps ReactNativeFiberHostComponent and NativeMethodsMixin in sync.
41 + * It can also provide types for ReactNative applications that use NMM or refs.
42 + */
43 +export type NativeMethodsMixinType = {
44 + blur(): void,
45 + focus(): void,
46 + measure(callback: MeasureOnSuccessCallback): void,
47 + measureInWindow(callback: MeasureInWindowOnSuccessCallback): void,
48 + measureLayout(
49 + relativeToNativeNode: number,
50 + onSuccess: MeasureLayoutOnSuccessCallback,
51 + onFail: () => void,
52 + ): void,
53 + setNativeProps(nativeProps: Object): void,
54 +};
55 +
56 +type ReactNativeBaseComponentViewConfig = {
57 + validAttributes: Object,
58 + uiViewClassName: string,
59 + propTypes?: Object,
60 +};
61 +
62 +type SecretInternalsType = {
63 + NativeMethodsMixin: NativeMethodsMixinType,
64 + createReactNativeComponentClass(
65 + viewConfig: ReactNativeBaseComponentViewConfig,
66 + ): any,
67 + ReactNativeComponentTree: any,
68 + ReactNativePropRegistry: any,
69 + // TODO (bvaughn) Decide which additional types to expose here?
70 + // And how much information to fill in for the above types.
71 +};
72 +
73 +/**
74 + * Flat ReactNative renderer bundles are too big for Flow to parse effeciently.
75 + * Provide minimal Flow typing for the high-level RN API and call it a day.
76 + */
77 +export type ReactNativeType = {
78 + findNodeHandle(componentOrHandle: any): ?number,
79 + render(
80 + element: React.Element<any>,
81 + containerTag: any,
82 + callback: ?Function,
83 + ): any,
84 + unmountComponentAtNode(containerTag: number): any,
85 + unmountComponentAtNodeAndRemoveContainer(containerTag: number): any,
86 + unstable_batchedUpdates: any, // TODO (bvaughn) Add types
87 +
88 + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType,
89 +};
src/renderers/native/findNodeHandle.js
+9 -15
@@ -13,11 +13,14 @@
13 'use strict';
14
15 var ReactInstanceMap = require('ReactInstanceMap');
16 +var ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
17 +var ReactNativeFiberRenderer = require('ReactNativeFiberRenderer');
18 var {ReactCurrentOwner} = require('ReactGlobalSharedState');
19
20 var invariant = require('fbjs/lib/invariant');
21 var warning = require('fbjs/lib/warning');
22
23 +import type {Fiber} from 'ReactFiber';
24 import type {ReactInstance} from 'ReactInstanceType';
25
26 /**
@@ -50,8 +53,10 @@ import type {ReactInstance} from 'ReactInstanceType';
53 * nodeHandle N/A rootNodeID tag
54 */
55
53 -let injectedFindNode;
54 -let injectedFindRootNodeID;
56 +// Rollup will strip the ReactNativeFiberRenderer from the Stack build.
57 +const injectedFindNode = ReactNativeFeatureFlags.useFiber
58 + ? (fiber: Fiber) => ReactNativeFiberRenderer.findHostInstance(fiber)
59 + : instance => instance;
60
61 // TODO (bvaughn) Rename the findNodeHandle module to something more descriptive
62 // eg findInternalHostInstance. This will reduce the likelihood of someone
@@ -90,9 +95,8 @@ function findNodeHandle(componentOrHandle: any): any {
95 if (internalInstance) {
96 return injectedFindNode(internalInstance);
97 } else {
93 - var rootNodeID = injectedFindRootNodeID(component);
94 - if (rootNodeID) {
95 - return rootNodeID;
98 + if (component) {
99 + return component;
100 } else {
101 invariant(
102 // Native
@@ -115,14 +119,4 @@ function findNodeHandle(componentOrHandle: any): any {
119 }
120 }
121
118 -// Fiber and stack implementations differ; each must inject a strategy
119 -findNodeHandle.injection = {
120 - injectFindNode(findNode) {
121 - injectedFindNode = findNode;
122 - },
123 - injectFindRootNodeID(findRootNodeID) {
124 - injectedFindRootNodeID = findRootNodeID;
125 - },
126 -};
127 -
122 module.exports = findNodeHandle;
src/renderers/native/findNumericNodeHandleFiber.js new
+29
@@ -0,0 +1,29 @@
1 +/**
2 + * Copyright (c) 2015-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule findNumericNodeHandleFiber
10 + * @flow
11 + */
12 +'use strict';
13 +
14 +var findNodeHandle = require('findNodeHandle');
15 +
16 +/**
17 + * External users of findNodeHandle() expect the host tag number return type.
18 + * The injected findNodeHandle() strategy returns the instance wrapper though.
19 + * See NativeMethodsMixin#setNativeProps for more info on why this is done.
20 + */
21 +module.exports = function findNumericNodeHandleFiber(
22 + componentOrHandle: any,
23 +): ?number {
24 + const instance: any = findNodeHandle(componentOrHandle);
25 + if (instance == null || typeof instance === 'number') {
26 + return instance;
27 + }
28 + return instance._nativeTag;
29 +};
src/renderers/native/findNumericNodeHandleStack.js new
+29
@@ -0,0 +1,29 @@
1 +/**
2 + * Copyright (c) 2015-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule findNumericNodeHandleStack
10 + * @flow
11 + */
12 +'use strict';
13 +
14 +var findNodeHandle = require('findNodeHandle');
15 +
16 +/**
17 + * External users of findNodeHandle() expect the host tag number return type.
18 + * The injected findNodeHandle() strategy returns the instance wrapper though.
19 + * See NativeMethodsMixin#setNativeProps for more info on why this is done.
20 + */
21 +module.exports = function findNumericNodeHandleStack(
22 + componentOrHandle: any,
23 +): ?number {
24 + const nodeHandle = findNodeHandle(componentOrHandle);
25 + if (nodeHandle == null || typeof nodeHandle === 'number') {
26 + return nodeHandle;
27 + }
28 + return nodeHandle.getHostNode();
29 +};
src/renderers/native/takeSnapshot.js
+7 -3
@@ -11,11 +11,15 @@
11 */
12 'use strict';
13
14 -var ReactNative = require('ReactNative');
15 -var UIManager = require('UIManager');
14 +const ReactNativeFeatureFlags = require('ReactNativeFeatureFlags');
15 +const UIManager = require('UIManager');
16
17 import type {Element} from 'React';
18
19 +const findNumericNodeHandle = ReactNativeFeatureFlags.useFiber
20 + ? require('findNumericNodeHandleFiber')
21 + : require('findNumericNodeHandleStack');
22 +
23 /**
24 * Capture an image of the screen, window or an individual view. The image
25 * will be stored in a temporary file that will only exist for as long as the
@@ -43,7 +47,7 @@ function takeSnapshot(
47 },
48 ): Promise<any> {
49 if (typeof view !== 'number' && view !== 'window') {
46 - view = ReactNative.findNodeHandle(view) || 'window';
50 + view = findNumericNodeHandle(view) || 'window';
51 }
52
53 // Call the hidden '__takeSnapshot' method; the main one throws an error to
src/renderers/shared/fiber/ReactChildFiber.js
+1 -2
@@ -13,8 +13,7 @@
13 'use strict';
14
15 import type {ReactElement} from 'ReactElementType';
16 -import type {ReactCoroutine, ReactYield} from 'ReactCoroutine';
17 -import type {ReactPortal} from 'ReactPortal';
16 +import type {ReactCoroutine, ReactPortal, ReactYield} from 'ReactTypes';
17 import type {Fiber} from 'ReactFiber';
18 import type {ReactInstance} from 'ReactInstanceType';
19 import type {PriorityLevel} from 'ReactPriorityLevel';
src/renderers/shared/fiber/ReactFiber.js
+6 -3
@@ -14,9 +14,12 @@
14
15 import type {ReactElement, Source} from 'ReactElementType';
16 import type {ReactInstance, DebugID} from 'ReactInstanceType';
17 -import type {ReactFragment} from 'ReactTypes';
18 -import type {ReactCoroutine, ReactYield} from 'ReactCoroutine';
19 -import type {ReactPortal} from 'ReactPortal';
17 +import type {
18 + ReactCoroutine,
19 + ReactFragment,
20 + ReactPortal,
21 + ReactYield,
22 +} from 'ReactTypes';
23 import type {TypeOfWork} from 'ReactTypeOfWork';
24 import type {TypeOfInternalContext} from 'ReactTypeOfInternalContext';
25 import type {TypeOfSideEffect} from 'ReactTypeOfSideEffect';
src/renderers/shared/fiber/ReactFiberBeginWork.js
+1 -1
@@ -12,7 +12,7 @@
12
13 'use strict';
14
15 -import type {ReactCoroutine} from 'ReactCoroutine';
15 +import type {ReactCoroutine} from 'ReactTypes';
16 import type {Fiber} from 'ReactFiber';
17 import type {HostContext} from 'ReactFiberHostContext';
18 import type {FiberRoot} from 'ReactFiberRoot';
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+1 -1
@@ -12,7 +12,7 @@
12
13 'use strict';
14
15 -import type {ReactCoroutine} from 'ReactCoroutine';
15 +import type {ReactCoroutine} from 'ReactTypes';
16 import type {Fiber} from 'ReactFiber';
17 import type {HostContext} from 'ReactFiberHostContext';
18 import type {FiberRoot} from 'ReactFiberRoot';
src/renderers/shared/fiber/isomorphic/ReactCoroutine.js
+1 -14
@@ -12,7 +12,7 @@
12
13 'use strict';
14
15 -import type {ReactNodeList} from 'ReactTypes';
15 +import type {ReactCoroutine, ReactNodeList, ReactYield} from 'ReactTypes';
16
17 // The Symbol used to tag the special React types. If there is no native Symbol
18 // nor polyfill, then a plain number is used for performance.
@@ -28,19 +28,6 @@ if (typeof Symbol === 'function' && Symbol.for) {
28
29 type CoroutineHandler<T> = (props: T, yields: Array<mixed>) => ReactNodeList;
30
31 -export type ReactCoroutine = {
32 - $$typeof: Symbol | number,
33 - key: null | string,
34 - children: any,
35 - // This should be a more specific CoroutineHandler
36 - handler: (props: any, yields: Array<mixed>) => ReactNodeList,
37 - props: any,
38 -};
39 -export type ReactYield = {
40 - $$typeof: Symbol | number,
41 - value: mixed,
42 -};
43 -
31 exports.createCoroutine = function<T>(
32 children: mixed,
33 handler: CoroutineHandler<T>,
src/renderers/shared/fiber/isomorphic/ReactPortal.js
+1 -10
@@ -12,7 +12,7 @@
12
13 'use strict';
14
15 -import type {ReactNodeList} from 'ReactTypes';
15 +import type {ReactNodeList, ReactPortal} from 'ReactTypes';
16
17 // The Symbol used to tag the special React types. If there is no native Symbol
18 // nor polyfill, then a plain number is used for performance.
@@ -20,15 +20,6 @@ var REACT_PORTAL_TYPE =
20 (typeof Symbol === 'function' && Symbol.for && Symbol.for('react.portal')) ||
21 0xeaca;
22
23 -export type ReactPortal = {
24 - $$typeof: Symbol | number,
25 - key: null | string,
26 - containerInfo: any,
27 - children: ReactNodeList,
28 - // TODO: figure out the API for cross-renderer implementation.
29 - implementation: any,
30 -};
31 -
23 exports.createPortal = function(
24 children: ReactNodeList,
25 containerInfo: any,
src/renderers/shared/fiber/isomorphic/ReactTypes.js
+23 -3
@@ -12,9 +12,6 @@
12
13 'use strict';
14
15 -import type {ReactCoroutine, ReactYield} from 'ReactCoroutine';
16 -import type {ReactPortal} from 'ReactPortal';
17 -
15 export type ReactNode =
16 | ReactElement<any>
17 | ReactCoroutine
@@ -30,3 +27,26 @@ export type ReactNodeList = ReactEmpty | ReactNode;
27 export type ReactText = string | number;
28
29 export type ReactEmpty = null | void | boolean;
30 +
31 +export type ReactCoroutine = {
32 + $$typeof: Symbol | number,
33 + key: null | string,
34 + children: any,
35 + // This should be a more specific CoroutineHandler
36 + handler: (props: any, yields: Array<mixed>) => ReactNodeList,
37 + props: any,
38 +};
39 +
40 +export type ReactYield = {
41 + $$typeof: Symbol | number,
42 + value: mixed,
43 +};
44 +
45 +export type ReactPortal = {
46 + $$typeof: Symbol | number,
47 + key: null | string,
48 + containerInfo: any,
49 + children: ReactNodeList,
50 + // TODO: figure out the API for cross-renderer implementation.
51 + implementation: any,
52 +};