diff --git a/packages/react-art/src/ReactART.js b/packages/react-art/src/ReactART.js index 670e2a349bbbe..04478434e8b66 100644 --- a/packages/react-art/src/ReactART.js +++ b/packages/react-art/src/ReactART.js @@ -7,7 +7,7 @@ import React from 'react'; import ReactFiberReconciler from 'react-reconciler'; -import * as ReactDOMFrameScheduling from 'shared/ReactDOMFrameScheduling'; +import * as ReactScheduler from 'react-scheduler'; import Mode from 'art/modes/current'; import FastNoSideEffects from 'art/modes/fast-noSideEffects'; import Transform from 'art/core/transform'; @@ -468,7 +468,7 @@ const ARTRenderer = ReactFiberReconciler({ return emptyObject; }, - scheduleDeferredCallback: ReactDOMFrameScheduling.rIC, + scheduleDeferredCallback: ReactScheduler.rIC, shouldSetTextContent(type, props) { return ( @@ -476,7 +476,7 @@ const ARTRenderer = ReactFiberReconciler({ ); }, - now: ReactDOMFrameScheduling.now, + now: ReactScheduler.now, mutation: { appendChild(parentInstance, child) { diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js index 1bb0c86ed24b7..82032f1d1d212 100644 --- a/packages/react-dom/src/client/ReactDOM.js +++ b/packages/react-dom/src/client/ReactDOM.js @@ -29,7 +29,7 @@ import * as EventPluginRegistry from 'events/EventPluginRegistry'; import * as EventPropagators from 'events/EventPropagators'; import * as ReactInstanceMap from 'shared/ReactInstanceMap'; import ReactVersion from 'shared/ReactVersion'; -import * as ReactDOMFrameScheduling from 'shared/ReactDOMFrameScheduling'; +import * as ReactScheduler from 'react-scheduler'; import {ReactCurrentOwner} from 'shared/ReactGlobalSharedState'; import getComponentName from 'shared/getComponentName'; import invariant from 'fbjs/lib/invariant'; @@ -688,7 +688,7 @@ const DOMRenderer = ReactFiberReconciler({ return textNode; }, - now: ReactDOMFrameScheduling.now, + now: ReactScheduler.now, mutation: { commitMount( @@ -984,8 +984,8 @@ const DOMRenderer = ReactFiberReconciler({ }, }, - scheduleDeferredCallback: ReactDOMFrameScheduling.rIC, - cancelDeferredCallback: ReactDOMFrameScheduling.cIC, + scheduleDeferredCallback: ReactScheduler.rIC, + cancelDeferredCallback: ReactScheduler.cIC, }); ReactGenericBatching.injection.injectRenderer(DOMRenderer); diff --git a/packages/react-scheduler/README.md b/packages/react-scheduler/README.md new file mode 100644 index 0000000000000..481b6f8f1a980 --- /dev/null +++ b/packages/react-scheduler/README.md @@ -0,0 +1,4 @@ +# React Scheduler + +This is a work in progress - we are building a utility to better coordinate +React and other JavaScript work. diff --git a/packages/react-scheduler/index.js b/packages/react-scheduler/index.js new file mode 100644 index 0000000000000..9eceea596698a --- /dev/null +++ b/packages/react-scheduler/index.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +export * from './src/ReactScheduler'; diff --git a/packages/react-scheduler/npm/index.js b/packages/react-scheduler/npm/index.js new file mode 100644 index 0000000000000..777fe2f80d4dd --- /dev/null +++ b/packages/react-scheduler/npm/index.js @@ -0,0 +1,7 @@ +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/react-scheduler.production.min.js'); +} else { + module.exports = require('./cjs/react-scheduler.development.js'); +} diff --git a/packages/react-scheduler/package.json b/packages/react-scheduler/package.json new file mode 100644 index 0000000000000..b16a07e99b38d --- /dev/null +++ b/packages/react-scheduler/package.json @@ -0,0 +1,23 @@ +{ + "name": "react-scheduler", + "version": "0.1.0-alpha-1", + "private": true, + "description": "unstable scheduling helper for coordinating React and other JS libraries", + "main": "index.js", + "repository": "facebook/react", + "license": "MIT", + "keywords": [ + "react" + ], + "bugs": { + "url": "https://github.com/facebook/react/issues" + }, + "homepage": "https://reactjs.org/", + "files": [ + "LICENSE", + "README.md", + "index.js", + "cjs/", + "umd/" + ] +} diff --git a/packages/shared/ReactDOMFrameScheduling.js b/packages/react-scheduler/src/ReactScheduler.js similarity index 94% rename from packages/shared/ReactDOMFrameScheduling.js rename to packages/react-scheduler/src/ReactScheduler.js index 514ca07c22e36..a7983dfeaf75a 100644 --- a/packages/shared/ReactDOMFrameScheduling.js +++ b/packages/react-scheduler/src/ReactScheduler.js @@ -7,6 +7,21 @@ * @flow */ +'use strict'; + +/** + * A scheduling library to allow scheduling work with more granular priority and + * control than requestAnimationFrame and requestIdleCallback. + * Current TODO items: + * X- Pull out the rIC polyfill built into React + * - Initial test coverage + * - Support for multiple callbacks + * - Support for two priorities; serial and deferred + * - Better test coverage + * - Better docblock + * - Polish documentation, API + */ + // This is a built-in polyfill for requestIdleCallback. It works by scheduling // a requestAnimationFrame, storing the time for the start of the frame, then // scheduling a postMessage which gets scheduled after paint. Within the diff --git a/packages/react-scheduler/src/__tests__/ReactScheduler-test.js b/packages/react-scheduler/src/__tests__/ReactScheduler-test.js new file mode 100644 index 0000000000000..cbcdfee4542ea --- /dev/null +++ b/packages/react-scheduler/src/__tests__/ReactScheduler-test.js @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @emails react-core + */ + +'use strict'; + +// TODO: delete or change this test. +describe('ReactDOMFrameScheduling', () => { + it('warns when requestAnimationFrame is not polyfilled in the browser', () => { + const previousRAF = global.requestAnimationFrame; + try { + global.requestAnimationFrame = undefined; + jest.resetModules(); + expect(() => require('react-dom')).toWarnDev( + 'React depends on requestAnimationFrame.', + ); + } finally { + global.requestAnimationFrame = previousRAF; + } + }); + + // We're just testing importing, not using it. + // It is important because even isomorphic components may import it. + it('can import findDOMNode in Node environment', () => { + const previousRAF = global.requestAnimationFrame; + const previousRIC = global.requestIdleCallback; + const prevWindow = global.window; + try { + global.requestAnimationFrame = undefined; + global.requestIdleCallback = undefined; + // Simulate the Node environment: + delete global.window; + jest.resetModules(); + expect(() => { + require('react-dom'); + }).not.toThrow(); + } finally { + global.requestAnimationFrame = previousRAF; + global.requestIdleCallback = previousRIC; + global.window = prevWindow; + } + }); +}); diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 18dbe1bb7f12c..c646eccdada16 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -264,6 +264,16 @@ const bundles = [ global: 'createSubscription', externals: ['react'], }, + + /******* React Scheduler (experimental) *******/ + { + label: 'react-scheduler', + bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD], + moduleType: ISOMORPHIC, + entry: 'react-scheduler', + global: 'ReactScheduler', + externals: [], + }, ]; // Based on deep-freeze by substack (public domain)