From 477efbe72ad6094bed02beb9b710251333f979a2 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 29 Aug 2018 07:29:18 -0700 Subject: [PATCH 01/12] Add interaction-tracking FB+www builds --- scripts/rollup/bundles.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index a656c4be24396..70aa78238e493 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -402,7 +402,16 @@ const bundles = [ /******* interaction-tracking (experimental) *******/ { label: 'interaction-tracking', - bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD], + bundleTypes: [ + FB_WWW_DEV, + FB_WWW_PROD, + FB_WWW_PROFILING, + NODE_DEV, + NODE_PROD, + NODE_PROFILING, + UMD_DEV, + UMD_PROD, + ], moduleType: ISOMORPHIC, entry: 'interaction-tracking', global: 'InteractionTracking', @@ -411,7 +420,16 @@ const bundles = [ { label: 'interaction-tracking-subscriptions', - bundleTypes: [NODE_DEV, NODE_PROD, UMD_DEV, UMD_PROD], + bundleTypes: [ + FB_WWW_DEV, + FB_WWW_PROD, + FB_WWW_PROFILING, + NODE_DEV, + NODE_PROD, + NODE_PROFILING, + UMD_DEV, + UMD_PROD, + ], moduleType: ISOMORPHIC, entry: 'interaction-tracking/subscriptions', global: 'InteractionTrackingSubscriptions', From 1f5ee619aee21006e826f87482932e949e14f329 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 29 Aug 2018 10:16:17 -0700 Subject: [PATCH 02/12] Strip no-side-effect imports from Rollup bundles --- scripts/rollup/build.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index fa1c8f90c6630..75bf3955ca803 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -408,6 +408,33 @@ function shouldSkipBundle(bundle, bundleType) { return false; } +// Strip unused require() statements for pure externals modules from the bundle. +// Rollup's treeshake option should do this, but it doesn't work. +function stripNoSideEffectImports(bundleType, pureExternalModules, filePath) { + const isProduction = isProductionBundleType(bundleType); + + // Dead code elimintation is only applied to production bundles. + if (!isProduction) { + return; + } + + const codeIn = fs.readFileSync(filePath, 'utf-8'); + let codeOut = codeIn; + + pureExternalModules.forEach(module => { + const regExp = new RegExp( + `(? Date: Wed, 29 Aug 2018 16:24:48 -0700 Subject: [PATCH 03/12] Access interaction-tracking API through React.unstable_interactions 1. For CJS bundles, this will just re-export the interaction-tracking package but for UMD builds, it will inline the functionality to avoid breaking backwards compatibility. 2. All new interaction-tracking APIs are tagged as unstabled (e.g. React.unstable_interactions.wrap, import { unstable_track } from 'interaction-tracking') --- .../suspense/src/components/App.js | 5 +- fixtures/unstable-async/suspense/src/index.js | 5 +- fixtures/unstable-async/suspense/yarn.lock | 21 +- .../interaction-tracking/npm/subscriptions.js | 7 + packages/interaction-tracking/package.json | 2 +- .../src/InteractionTracking.js | 10 +- .../src/InteractionTrackingSubscriptions.js | 4 +- .../InteractionTracking-test.internal.js | 152 +++++----- ...tionTrackingSubscriptions-test.internal.js | 188 ++++++++----- .../react-reconciler/src/ReactFiberRoot.js | 4 +- .../src/ReactFiberScheduler.js | 3 +- packages/react/package.json | 1 + packages/react/src/React.js | 28 ++ .../__tests__/ReactProfiler-test.internal.js | 260 +++++++++--------- ...ofilerDevToolsIntegration-test.internal.js | 4 +- scripts/rollup/build.js | 30 -- scripts/rollup/bundles.js | 22 +- scripts/rollup/modules.js | 3 +- 18 files changed, 416 insertions(+), 333 deletions(-) create mode 100644 packages/interaction-tracking/npm/subscriptions.js diff --git a/fixtures/unstable-async/suspense/src/components/App.js b/fixtures/unstable-async/suspense/src/components/App.js index 88e0cd011ff99..28b2c9b677898 100644 --- a/fixtures/unstable-async/suspense/src/components/App.js +++ b/fixtures/unstable-async/suspense/src/components/App.js @@ -1,10 +1,11 @@ -import {track, wrap} from 'interaction-tracking'; -import React, {Placeholder, PureComponent} from 'react'; +import React, {Placeholder, PureComponent, unstable_interactions} from 'react'; import {createResource} from 'simple-cache-provider'; import {cache} from '../cache'; import Spinner from './Spinner'; import ContributorListPage from './ContributorListPage'; +const {track, wrap} = unstable_interactions; + const UserPageResource = createResource(() => import('./UserPage')); function UserPageLoader(props) { diff --git a/fixtures/unstable-async/suspense/src/index.js b/fixtures/unstable-async/suspense/src/index.js index a2c047e810a1a..847c50debc3ce 100644 --- a/fixtures/unstable-async/suspense/src/index.js +++ b/fixtures/unstable-async/suspense/src/index.js @@ -1,5 +1,4 @@ -import {track} from 'interaction-tracking'; -import React, {Fragment, PureComponent} from 'react'; +import React, {Fragment, PureComponent, unstable_interactions} from 'react'; import {unstable_createRoot, render} from 'react-dom'; import {cache} from './cache'; import { @@ -12,6 +11,8 @@ import App from './components/App'; import Draggable from 'react-draggable'; import './index.css'; +const {track} = unstable_interactions; + let handleReset; class Shell extends PureComponent { diff --git a/fixtures/unstable-async/suspense/yarn.lock b/fixtures/unstable-async/suspense/yarn.lock index f80f812083ff8..08591ca46dcff 100644 --- a/fixtures/unstable-async/suspense/yarn.lock +++ b/fixtures/unstable-async/suspense/yarn.lock @@ -3483,7 +3483,11 @@ inquirer@3.3.0, inquirer@^3.0.6: through "^2.3.6" interaction-tracking@../../../build/node_modules/interaction-tracking: + version "16.4.3-alpha.0" + +interaction-tracking@16.4.3-alpha.0: version "0.0.1" + resolved "https://registry.yarnpkg.com/interaction-tracking/-/interaction-tracking-0.0.1.tgz#08877accb2ec479f2af83d7de7a9ae60b80e8dc5" internal-ip@1.2.0: version "1.2.0" @@ -4102,6 +4106,10 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + js-yaml@^3.4.3, js-yaml@^3.7.0, js-yaml@^3.9.1: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" @@ -4389,12 +4397,18 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: js-tokens "^3.0.0" +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -5720,7 +5734,7 @@ react-dev-utils@^5.0.1: text-table "0.2.0" react-dom@../../../build/node_modules/react-dom: - version "16.4.1" + version "16.4.3-alpha.0" dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -5783,8 +5797,9 @@ react-scripts@^1.1.4: fsevents "^1.1.3" react@../../../build/node_modules/react: - version "16.4.1" + version "16.4.3-alpha.0" dependencies: + interaction-tracking "16.4.3-alpha.0" loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" diff --git a/packages/interaction-tracking/npm/subscriptions.js b/packages/interaction-tracking/npm/subscriptions.js new file mode 100644 index 0000000000000..b675e27f36784 --- /dev/null +++ b/packages/interaction-tracking/npm/subscriptions.js @@ -0,0 +1,7 @@ +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/interaction-tracking-subscriptions.production.min.js'); +} else { + module.exports = require('./cjs/interaction-tracking-subscriptions.development.js'); +} diff --git a/packages/interaction-tracking/package.json b/packages/interaction-tracking/package.json index 2bb9bb4e780c5..0513e6fc76c5f 100644 --- a/packages/interaction-tracking/package.json +++ b/packages/interaction-tracking/package.json @@ -1,7 +1,7 @@ { "name": "interaction-tracking", "description": "utility for tracking interaction events", - "version": "0.0.1", + "version": "16.4.3-alpha.0", "license": "MIT", "files": [ "LICENSE", diff --git a/packages/interaction-tracking/src/InteractionTracking.js b/packages/interaction-tracking/src/InteractionTracking.js index 7b69678b19dbd..04511ad99fa87 100644 --- a/packages/interaction-tracking/src/InteractionTracking.js +++ b/packages/interaction-tracking/src/InteractionTracking.js @@ -83,7 +83,7 @@ if (enableInteractionTracking) { // They should not typically be accessed directly. export {interactionsRef as __interactionsRef, subscriberRef as __subscriberRef}; -export function clear(callback: Function): any { +export function unstable_clear(callback: Function): any { if (!enableInteractionTracking) { return callback(); } @@ -98,7 +98,7 @@ export function clear(callback: Function): any { } } -export function getCurrent(): Set | null { +export function unstable_getCurrent(): Set | null { if (!enableInteractionTracking) { return null; } else { @@ -106,11 +106,11 @@ export function getCurrent(): Set | null { } } -export function getThreadID(): number { +export function unstable_getThreadID(): number { return ++threadIDCounter; } -export function track( +export function unstable_track( name: string, timestamp: number, callback: Function, @@ -174,7 +174,7 @@ export function track( return returnValue; } -export function wrap( +export function unstable_wrap( callback: Function, threadID: number = DEFAULT_THREAD_ID, ): Function { diff --git a/packages/interaction-tracking/src/InteractionTrackingSubscriptions.js b/packages/interaction-tracking/src/InteractionTrackingSubscriptions.js index da53178f16113..7ec33232a57f1 100644 --- a/packages/interaction-tracking/src/InteractionTrackingSubscriptions.js +++ b/packages/interaction-tracking/src/InteractionTrackingSubscriptions.js @@ -17,13 +17,13 @@ if (enableInteractionTracking) { subscribers = new Set(); } -export function subscribe(subscriber: Subscriber): void { +export function unstable_subscribe(subscriber: Subscriber): void { if (enableInteractionTracking) { subscribers.add(subscriber); } } -export function unsubscribe(subscriber: Subscriber): void { +export function unstable_unsubscribe(subscriber: Subscriber): void { if (enableInteractionTracking) { subscribers.delete(subscriber); } diff --git a/packages/interaction-tracking/src/__tests__/InteractionTracking-test.internal.js b/packages/interaction-tracking/src/__tests__/InteractionTracking-test.internal.js index 0b26591315d1c..16dae7a8d0037 100644 --- a/packages/interaction-tracking/src/__tests__/InteractionTracking-test.internal.js +++ b/packages/interaction-tracking/src/__tests__/InteractionTracking-test.internal.js @@ -37,26 +37,26 @@ describe('InteractionTracking', () => { it('should return the value of a tracked function', () => { expect( - InteractionTracking.track('arbitrary', currentTime, () => 123), + InteractionTracking.unstable_track('arbitrary', currentTime, () => 123), ).toBe(123); }); it('should return the value of a clear function', () => { - expect(InteractionTracking.clear(() => 123)).toBe(123); + expect(InteractionTracking.unstable_clear(() => 123)).toBe(123); }); it('should return the value of a wrapped function', () => { let wrapped; - InteractionTracking.track('arbitrary', currentTime, () => { - wrapped = InteractionTracking.wrap(() => 123); + InteractionTracking.unstable_track('arbitrary', currentTime, () => { + wrapped = InteractionTracking.unstable_wrap(() => 123); }); expect(wrapped()).toBe(123); }); it('should pass arguments through to a wrapped function', done => { let wrapped; - InteractionTracking.track('arbitrary', currentTime, () => { - wrapped = InteractionTracking.wrap((param1, param2) => { + InteractionTracking.unstable_track('arbitrary', currentTime, () => { + wrapped = InteractionTracking.unstable_wrap((param1, param2) => { expect(param1).toBe('foo'); expect(param2).toBe('bar'); done(); @@ -66,14 +66,16 @@ describe('InteractionTracking', () => { }); it('should return an empty set when outside of a tracked event', () => { - expect(InteractionTracking.getCurrent()).toContainNoInteractions(); + expect( + InteractionTracking.unstable_getCurrent(), + ).toContainNoInteractions(); }); it('should report the tracked interaction from within the track callback', done => { advanceTimeBy(100); - InteractionTracking.track('some event', currentTime, () => { - const interactions = InteractionTracking.getCurrent(); + InteractionTracking.unstable_track('some event', currentTime, () => { + const interactions = InteractionTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'some event', timestamp: 100}, ]); @@ -86,7 +88,7 @@ describe('InteractionTracking', () => { let wrappedIndirection; function indirection() { - const interactions = InteractionTracking.getCurrent(); + const interactions = InteractionTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'some event', timestamp: 100}, ]); @@ -96,8 +98,8 @@ describe('InteractionTracking', () => { advanceTimeBy(100); - InteractionTracking.track('some event', currentTime, () => { - wrappedIndirection = InteractionTracking.wrap(indirection); + InteractionTracking.unstable_track('some event', currentTime, () => { + wrappedIndirection = InteractionTracking.unstable_wrap(indirection); }); advanceTimeBy(50); @@ -108,24 +110,26 @@ describe('InteractionTracking', () => { it('should clear the interaction stack for tracked callbacks', () => { let innerTestReached = false; - InteractionTracking.track('outer event', currentTime, () => { - expect(InteractionTracking.getCurrent()).toMatchInteractions([ + InteractionTracking.unstable_track('outer event', currentTime, () => { + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); - InteractionTracking.clear(() => { - expect(InteractionTracking.getCurrent()).toMatchInteractions([]); + InteractionTracking.unstable_clear(() => { + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [], + ); - InteractionTracking.track('inner event', currentTime, () => { - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - {name: 'inner event'}, - ]); + InteractionTracking.unstable_track('inner event', currentTime, () => { + expect( + InteractionTracking.unstable_getCurrent(), + ).toMatchInteractions([{name: 'inner event'}]); innerTestReached = true; }); }); - expect(InteractionTracking.getCurrent()).toMatchInteractions([ + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); }); @@ -138,29 +142,31 @@ describe('InteractionTracking', () => { let wrappedIndirection; const indirection = jest.fn(() => { - expect(InteractionTracking.getCurrent()).toMatchInteractions([ + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); - InteractionTracking.clear(() => { - expect(InteractionTracking.getCurrent()).toMatchInteractions([]); + InteractionTracking.unstable_clear(() => { + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [], + ); - InteractionTracking.track('inner event', currentTime, () => { - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - {name: 'inner event'}, - ]); + InteractionTracking.unstable_track('inner event', currentTime, () => { + expect( + InteractionTracking.unstable_getCurrent(), + ).toMatchInteractions([{name: 'inner event'}]); innerTestReached = true; }); }); - expect(InteractionTracking.getCurrent()).toMatchInteractions([ + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); }); - InteractionTracking.track('outer event', currentTime, () => { - wrappedIndirection = InteractionTracking.wrap(indirection); + InteractionTracking.unstable_track('outer event', currentTime, () => { + wrappedIndirection = InteractionTracking.unstable_wrap(indirection); }); wrappedIndirection(); @@ -175,7 +181,7 @@ describe('InteractionTracking', () => { let outerIndirectionTracked = false; function innerIndirection() { - const interactions = InteractionTracking.getCurrent(); + const interactions = InteractionTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, {name: 'inner event', timestamp: 150}, @@ -185,7 +191,7 @@ describe('InteractionTracking', () => { } function outerIndirection() { - const interactions = InteractionTracking.getCurrent(); + const interactions = InteractionTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, ]); @@ -193,16 +199,16 @@ describe('InteractionTracking', () => { outerIndirectionTracked = true; } - InteractionTracking.track('outer event', currentTime, () => { + InteractionTracking.unstable_track('outer event', currentTime, () => { // Verify the current tracked event - let interactions = InteractionTracking.getCurrent(); + let interactions = InteractionTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, ]); advanceTimeBy(50); - const wrapperOuterIndirection = InteractionTracking.wrap( + const wrapperOuterIndirection = InteractionTracking.unstable_wrap( outerIndirection, ); @@ -210,8 +216,8 @@ describe('InteractionTracking', () => { let innerEventTracked = false; // Verify that a nested event is properly tracked - InteractionTracking.track('inner event', currentTime, () => { - interactions = InteractionTracking.getCurrent(); + InteractionTracking.unstable_track('inner event', currentTime, () => { + interactions = InteractionTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, {name: 'inner event', timestamp: 150}, @@ -221,7 +227,9 @@ describe('InteractionTracking', () => { wrapperOuterIndirection(); expect(outerIndirectionTracked).toBe(true); - wrapperInnerIndirection = InteractionTracking.wrap(innerIndirection); + wrapperInnerIndirection = InteractionTracking.unstable_wrap( + innerIndirection, + ); innerEventTracked = true; }); @@ -229,7 +237,7 @@ describe('InteractionTracking', () => { expect(innerEventTracked).toBe(true); // Verify that the original event is restored - interactions = InteractionTracking.getCurrent(); + interactions = InteractionTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, ]); @@ -246,16 +254,20 @@ describe('InteractionTracking', () => { it('should reset state appropriately when an error occurs in a track callback', done => { advanceTimeBy(100); - InteractionTracking.track('outer event', currentTime, () => { + InteractionTracking.unstable_track('outer event', currentTime, () => { expect(() => { - InteractionTracking.track('inner event', currentTime, () => { - throw Error('intentional'); - }); + InteractionTracking.unstable_track( + 'inner event', + currentTime, + () => { + throw Error('intentional'); + }, + ); }).toThrow(); - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - {name: 'outer event', timestamp: 100}, - ]); + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [{name: 'outer event', timestamp: 100}], + ); done(); }); @@ -264,20 +276,20 @@ describe('InteractionTracking', () => { it('should reset state appropriately when an error occurs in a wrapped callback', done => { advanceTimeBy(100); - InteractionTracking.track('outer event', currentTime, () => { + InteractionTracking.unstable_track('outer event', currentTime, () => { let wrappedCallback; - InteractionTracking.track('inner event', currentTime, () => { - wrappedCallback = InteractionTracking.wrap(() => { + InteractionTracking.unstable_track('inner event', currentTime, () => { + wrappedCallback = InteractionTracking.unstable_wrap(() => { throw Error('intentional'); }); }); expect(wrappedCallback).toThrow(); - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - {name: 'outer event', timestamp: 100}, - ]); + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [{name: 'outer event', timestamp: 100}], + ); done(); }); @@ -286,29 +298,29 @@ describe('InteractionTracking', () => { describe('advanced integration', () => { it('should return a unique threadID per request', () => { - expect(InteractionTracking.getThreadID()).not.toBe( - InteractionTracking.getThreadID(), + expect(InteractionTracking.unstable_getThreadID()).not.toBe( + InteractionTracking.unstable_getThreadID(), ); }); it('should expose the current set of interactions to be externally manipulated', () => { - InteractionTracking.track('outer event', currentTime, () => { + InteractionTracking.unstable_track('outer event', currentTime, () => { expect(InteractionTracking.__interactionsRef.current).toBe( - InteractionTracking.getCurrent(), + InteractionTracking.unstable_getCurrent(), ); InteractionTracking.__interactionsRef.current = new Set([ {name: 'override event'}, ]); - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - {name: 'override event'}, - ]); + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [{name: 'override event'}], + ); }); }); it('should expose a subscriber ref to be externally manipulated', () => { - InteractionTracking.track('outer event', currentTime, () => { + InteractionTracking.unstable_track('outer event', currentTime, () => { expect(InteractionTracking.__subscriberRef).toEqual({ current: null, }); @@ -322,37 +334,37 @@ describe('InteractionTracking', () => { it('should return the value of a tracked function', () => { expect( - InteractionTracking.track('arbitrary', currentTime, () => 123), + InteractionTracking.unstable_track('arbitrary', currentTime, () => 123), ).toBe(123); }); it('should return the value of a wrapped function', () => { let wrapped; - InteractionTracking.track('arbitrary', currentTime, () => { - wrapped = InteractionTracking.wrap(() => 123); + InteractionTracking.unstable_track('arbitrary', currentTime, () => { + wrapped = InteractionTracking.unstable_wrap(() => 123); }); expect(wrapped()).toBe(123); }); it('should return null for tracked interactions', () => { - expect(InteractionTracking.getCurrent()).toBe(null); + expect(InteractionTracking.unstable_getCurrent()).toBe(null); }); it('should execute tracked callbacks', done => { - InteractionTracking.track('some event', currentTime, () => { - expect(InteractionTracking.getCurrent()).toBe(null); + InteractionTracking.unstable_track('some event', currentTime, () => { + expect(InteractionTracking.unstable_getCurrent()).toBe(null); done(); }); }); it('should return the value of a clear function', () => { - expect(InteractionTracking.clear(() => 123)).toBe(123); + expect(InteractionTracking.unstable_clear(() => 123)).toBe(123); }); it('should execute wrapped callbacks', done => { - const wrappedCallback = InteractionTracking.wrap(() => { - expect(InteractionTracking.getCurrent()).toBe(null); + const wrappedCallback = InteractionTracking.unstable_wrap(() => { + expect(InteractionTracking.unstable_getCurrent()).toBe(null); done(); }); diff --git a/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js b/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js index 4d259858c9cb3..1a4fd5950a5f3 100644 --- a/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js +++ b/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js @@ -102,8 +102,8 @@ describe('InteractionTracking', () => { onWorkStopped: jest.fn(), }; - InteractionTrackingSubscriptions.subscribe(firstSubscriber); - InteractionTrackingSubscriptions.subscribe(secondSubscriber); + InteractionTrackingSubscriptions.unstable_subscribe(firstSubscriber); + InteractionTrackingSubscriptions.unstable_subscribe(secondSubscriber); } describe('enabled', () => { @@ -111,13 +111,13 @@ describe('InteractionTracking', () => { describe('error handling', () => { it('should cover onInteractionTracked/onWorkStarted within', done => { - InteractionTracking.track(firstEvent.name, currentTime, () => { + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { const mock = jest.fn(); // It should call the callback before re-throwing throwInOnInteractionTracked = true; expect(() => - InteractionTracking.track( + InteractionTracking.unstable_track( secondEvent.name, currentTime, mock, @@ -129,7 +129,7 @@ describe('InteractionTracking', () => { throwInOnWorkStarted = true; expect(() => - InteractionTracking.track( + InteractionTracking.unstable_track( secondEvent.name, currentTime, mock, @@ -139,9 +139,9 @@ describe('InteractionTracking', () => { expect(mock).toHaveBeenCalledTimes(2); // It should restore the previous/outer interactions - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - firstEvent, - ]); + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [firstEvent], + ); // It should call other subscribers despite the earlier error expect(secondSubscriber.onInteractionTracked).toHaveBeenCalledTimes( @@ -154,22 +154,28 @@ describe('InteractionTracking', () => { }); it('should cover onWorkStopped within track', done => { - InteractionTracking.track(firstEvent.name, currentTime, () => { + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { let innerInteraction; const mock = jest.fn(() => { - innerInteraction = Array.from(InteractionTracking.getCurrent())[1]; + innerInteraction = Array.from( + InteractionTracking.unstable_getCurrent(), + )[1]; }); throwInOnWorkStopped = true; expect(() => - InteractionTracking.track(secondEvent.name, currentTime, mock), + InteractionTracking.unstable_track( + secondEvent.name, + currentTime, + mock, + ), ).toThrow('Expected error onWorkStopped'); throwInOnWorkStopped = false; // It should restore the previous/outer interactions - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - firstEvent, - ]); + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [firstEvent], + ); // It should update the interaction count so as not to interfere with subsequent calls expect(innerInteraction.__count).toBe(0); @@ -182,19 +188,23 @@ describe('InteractionTracking', () => { }); it('should cover onInteractionScheduledWorkCompleted within track', done => { - InteractionTracking.track(firstEvent.name, currentTime, () => { + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { const mock = jest.fn(); throwInOnInteractionScheduledWorkCompleted = true; expect(() => - InteractionTracking.track(secondEvent.name, currentTime, mock), + InteractionTracking.unstable_track( + secondEvent.name, + currentTime, + mock, + ), ).toThrow('Expected error onInteractionScheduledWorkCompleted'); throwInOnInteractionScheduledWorkCompleted = false; // It should restore the previous/outer interactions - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - firstEvent, - ]); + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [firstEvent], + ); // It should call other subscribers despite the earlier error expect( @@ -210,9 +220,13 @@ describe('InteractionTracking', () => { expect(onWorkStopped).not.toHaveBeenCalled(); expect(() => { - InteractionTracking.track(firstEvent.name, currentTime, () => { - throw Error('Expected error callback'); - }); + InteractionTracking.unstable_track( + firstEvent.name, + currentTime, + () => { + throw Error('Expected error callback'); + }, + ); }).toThrow('Expected error callback'); expect(onWorkStarted).toHaveBeenCalledTimes(1); @@ -222,12 +236,14 @@ describe('InteractionTracking', () => { }); it('should cover onWorkScheduled within wrap', done => { - InteractionTracking.track(firstEvent.name, currentTime, () => { - const interaction = Array.from(InteractionTracking.getCurrent())[0]; + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + const interaction = Array.from( + InteractionTracking.unstable_getCurrent(), + )[0]; const beforeCount = interaction.__count; throwInOnWorkScheduled = true; - expect(() => InteractionTracking.wrap(() => {})).toThrow( + expect(() => InteractionTracking.unstable_wrap(() => {})).toThrow( 'Expected error onWorkScheduled', ); @@ -244,9 +260,11 @@ describe('InteractionTracking', () => { it('should cover onWorkStarted within wrap', () => { const mock = jest.fn(); let interaction, wrapped; - InteractionTracking.track(firstEvent.name, currentTime, () => { - interaction = Array.from(InteractionTracking.getCurrent())[0]; - wrapped = InteractionTracking.wrap(mock); + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + interaction = Array.from( + InteractionTracking.unstable_getCurrent(), + )[0]; + wrapped = InteractionTracking.unstable_wrap(mock); }); expect(interaction.__count).toBe(1); @@ -264,24 +282,30 @@ describe('InteractionTracking', () => { }); it('should cover onWorkStopped within wrap', done => { - InteractionTracking.track(firstEvent.name, currentTime, () => { + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { const outerInteraction = Array.from( - InteractionTracking.getCurrent(), + InteractionTracking.unstable_getCurrent(), )[0]; expect(outerInteraction.__count).toBe(1); let wrapped; let innerInteraction; - InteractionTracking.track(secondEvent.name, currentTime, () => { - innerInteraction = Array.from(InteractionTracking.getCurrent())[1]; - expect(outerInteraction.__count).toBe(1); - expect(innerInteraction.__count).toBe(1); - - wrapped = InteractionTracking.wrap(jest.fn()); - expect(outerInteraction.__count).toBe(2); - expect(innerInteraction.__count).toBe(2); - }); + InteractionTracking.unstable_track( + secondEvent.name, + currentTime, + () => { + innerInteraction = Array.from( + InteractionTracking.unstable_getCurrent(), + )[1]; + expect(outerInteraction.__count).toBe(1); + expect(innerInteraction.__count).toBe(1); + + wrapped = InteractionTracking.unstable_wrap(jest.fn()); + expect(outerInteraction.__count).toBe(2); + expect(innerInteraction.__count).toBe(2); + }, + ); expect(outerInteraction.__count).toBe(2); expect(innerInteraction.__count).toBe(1); @@ -291,9 +315,9 @@ describe('InteractionTracking', () => { throwInOnWorkStopped = false; // It should restore the previous interactions - expect(InteractionTracking.getCurrent()).toMatchInteractions([ - outerInteraction, - ]); + expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + [outerInteraction], + ); // It should update the interaction count so as not to interfere with subsequent calls expect(outerInteraction.__count).toBe(1); @@ -311,9 +335,11 @@ describe('InteractionTracking', () => { let wrapped; let interaction; - InteractionTracking.track(firstEvent.name, currentTime, () => { - interaction = Array.from(InteractionTracking.getCurrent())[0]; - wrapped = InteractionTracking.wrap(() => { + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + interaction = Array.from( + InteractionTracking.unstable_getCurrent(), + )[0]; + wrapped = InteractionTracking.unstable_wrap(() => { throw Error('Expected error wrap'); }); }); @@ -332,9 +358,11 @@ describe('InteractionTracking', () => { it('should cover onWorkCanceled within wrap', () => { let interaction, wrapped; - InteractionTracking.track(firstEvent.name, currentTime, () => { - interaction = Array.from(InteractionTracking.getCurrent())[0]; - wrapped = InteractionTracking.wrap(jest.fn()); + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + interaction = Array.from( + InteractionTracking.unstable_getCurrent(), + )[0]; + wrapped = InteractionTracking.unstable_wrap(jest.fn()); }); expect(interaction.__count).toBe(1); @@ -358,7 +386,7 @@ describe('InteractionTracking', () => { expect(onInteractionTracked).not.toHaveBeenCalled(); expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); - InteractionTracking.track( + InteractionTracking.unstable_track( firstEvent.name, currentTime, () => { @@ -374,7 +402,7 @@ describe('InteractionTracking', () => { ); expect(onWorkStopped).not.toHaveBeenCalled(); - InteractionTracking.track( + InteractionTracking.unstable_track( secondEvent.name, currentTime, () => { @@ -426,25 +454,29 @@ describe('InteractionTracking', () => { const unwrapped = jest.fn(); let wrapped; - InteractionTracking.track(firstEvent.name, currentTime, () => { + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { expect(onInteractionTracked).toHaveBeenCalledTimes(1); expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( firstEvent, ); - InteractionTracking.track(secondEvent.name, currentTime, () => { - expect(onInteractionTracked).toHaveBeenCalledTimes(2); - expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( - secondEvent, - ); - - wrapped = InteractionTracking.wrap(unwrapped, threadID); - expect(onWorkScheduled).toHaveBeenCalledTimes(1); - expect(onWorkScheduled).toHaveBeenLastNotifiedOfWork( - new Set([firstEvent, secondEvent]), - threadID, - ); - }); + InteractionTracking.unstable_track( + secondEvent.name, + currentTime, + () => { + expect(onInteractionTracked).toHaveBeenCalledTimes(2); + expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( + secondEvent, + ); + + wrapped = InteractionTracking.unstable_wrap(unwrapped, threadID); + expect(onWorkScheduled).toHaveBeenCalledTimes(1); + expect(onWorkScheduled).toHaveBeenLastNotifiedOfWork( + new Set([firstEvent, secondEvent]), + threadID, + ); + }, + ); }); expect(onInteractionTracked).toHaveBeenCalledTimes(2); @@ -478,11 +510,15 @@ describe('InteractionTracking', () => { const fnOne = jest.fn(); const fnTwo = jest.fn(); let wrappedOne, wrappedTwo; - InteractionTracking.track(firstEvent.name, currentTime, () => { - wrappedOne = InteractionTracking.wrap(fnOne, threadID); - InteractionTracking.track(secondEvent.name, currentTime, () => { - wrappedTwo = InteractionTracking.wrap(fnTwo, threadID); - }); + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + wrappedOne = InteractionTracking.unstable_wrap(fnOne, threadID); + InteractionTracking.unstable_track( + secondEvent.name, + currentTime, + () => { + wrappedTwo = InteractionTracking.unstable_wrap(fnTwo, threadID); + }, + ); }); expect(onInteractionTracked).toHaveBeenCalledTimes(2); @@ -521,12 +557,12 @@ describe('InteractionTracking', () => { it('should not end an interaction twice if wrap is used to schedule follow up work within another wrap', () => { const fnOne = jest.fn(() => { - wrappedTwo = InteractionTracking.wrap(fnTwo, threadID); + wrappedTwo = InteractionTracking.unstable_wrap(fnTwo, threadID); }); const fnTwo = jest.fn(); let wrappedOne, wrappedTwo; - InteractionTracking.track(firstEvent.name, currentTime, () => { - wrappedOne = InteractionTracking.wrap(fnOne, threadID); + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + wrappedOne = InteractionTracking.unstable_wrap(fnOne, threadID); }); expect(onInteractionTracked).toHaveBeenCalledTimes(1); @@ -547,8 +583,12 @@ describe('InteractionTracking', () => { }); it('should unsubscribe', () => { - InteractionTrackingSubscriptions.unsubscribe(firstSubscriber); - InteractionTracking.track(firstEvent.name, currentTime, () => {}); + InteractionTrackingSubscriptions.unstable_unsubscribe(firstSubscriber); + InteractionTracking.unstable_track( + firstEvent.name, + currentTime, + () => {}, + ); expect(onInteractionTracked).not.toHaveBeenCalled(); }); diff --git a/packages/react-reconciler/src/ReactFiberRoot.js b/packages/react-reconciler/src/ReactFiberRoot.js index 2057ca6d59644..86c8fa50f4265 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.js +++ b/packages/react-reconciler/src/ReactFiberRoot.js @@ -12,11 +12,13 @@ import type {ExpirationTime} from './ReactFiberExpirationTime'; import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig'; import type {Interaction} from 'interaction-tracking/src/InteractionTracking'; +import React from 'react'; import {noTimeout} from './ReactFiberHostConfig'; import {createHostRootFiber} from './ReactFiber'; import {NoWork} from './ReactFiberExpirationTime'; import {enableInteractionTracking} from 'shared/ReactFeatureFlags'; -import {getThreadID} from 'interaction-tracking'; + +const {getThreadID} = React.unstable_interactions; // TODO: This should be lifted into the renderer. export type Batch = { diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index 9f053d6cece60..784453c30f964 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -12,7 +12,7 @@ import type {Batch, FiberRoot} from './ReactFiberRoot'; import type {ExpirationTime} from './ReactFiberExpirationTime'; import type {Interaction} from 'interaction-tracking/src/InteractionTracking'; -import {__interactionsRef, __subscriberRef} from 'interaction-tracking'; +import React from 'react'; import { invokeGuardedCallback, hasCaughtError, @@ -161,6 +161,7 @@ export type Thenable = { }; const {ReactCurrentOwner} = ReactSharedInternals; +const {__interactionsRef, __subscriberRef} = React.unstable_interactions; let didWarnAboutStateTransition; let didWarnSetStateChildContext; diff --git a/packages/react/package.json b/packages/react/package.json index 6c9ad1ad537f2..482dede2d4a5d 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -21,6 +21,7 @@ "node": ">=0.10.0" }, "dependencies": { + "interaction-tracking": "16.4.3-alpha.0", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2" diff --git a/packages/react/src/React.js b/packages/react/src/React.js index 85e1207a90262..97d8417bfb295 100644 --- a/packages/react/src/React.js +++ b/packages/react/src/React.js @@ -33,6 +33,19 @@ import { cloneElementWithValidation, } from './ReactElementValidator'; import ReactSharedInternals from './ReactSharedInternals'; +import { + __interactionsRef, + __subscriberRef, + unstable_clear as clear, + unstable_getCurrent as getCurrent, + unstable_getThreadID as getThreadID, + unstable_track as track, + unstable_wrap as wrap, +} from 'interaction-tracking'; +import { + unstable_subscribe as subscribe, + unstable_unsubscribe as unsubscribe, +} from 'interaction-tracking/subscriptions'; const React = { Children: { @@ -62,6 +75,21 @@ const React = { version: ReactVersion, + // Re-export the interaction-tracking API for UMD bundles. + // This avoids introducing a dependency on a new UMD global in a minor update, + // Since this would be a breaking change. + unstable_interactions: { + __interactionsRef, + __subscriberRef, + clear, + getCurrent, + getThreadID, + subscribe, + track, + unsubscribe, + wrap, + }, + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals, }; diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 5ccc00f31a7f9..563f5a05eed4e 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -10,8 +10,6 @@ 'use strict'; -let InteractionTracking; -let InteractionTrackingSubscriptions; let React; let ReactFeatureFlags; let ReactNoop; @@ -42,8 +40,6 @@ function loadModules({ ReactFeatureFlags.enableSuspense = enableSuspense; ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = replayFailedUnitOfWorkWithInvokeGuardedCallback; - InteractionTracking = require('interaction-tracking'); - InteractionTrackingSubscriptions = require('interaction-tracking/subscriptions'); React = require('react'); if (useNoopRenderer) { @@ -1208,7 +1204,7 @@ describe('Profiler', () => { }); // Verify interaction subscriber methods are called as expected. - InteractionTrackingSubscriptions.subscribe({ + React.unstable_interactions.subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, @@ -1230,7 +1226,7 @@ describe('Profiler', () => { // Errors that happen inside of a subscriber should throw, throwInOnWorkScheduled = true; expect(() => { - InteractionTracking.track('event', mockNow(), () => { + React.unstable_interactions.track('event', mockNow(), () => { renderer = ReactTestRenderer.create(fail, { unstable_isAsync: true, }); @@ -1256,7 +1252,7 @@ describe('Profiler', () => { } let renderer; - InteractionTracking.track('event', mockNow(), () => { + React.unstable_interactions.track('event', mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1285,7 +1281,7 @@ describe('Profiler', () => { } let renderer; - InteractionTracking.track('event', mockNow(), () => { + React.unstable_interactions.track('event', mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1327,8 +1323,8 @@ describe('Profiler', () => { }; let renderer; - InteractionTracking.track(eventOne.name, mockNow(), () => { - InteractionTracking.track(eventTwo.name, mockNow(), () => { + React.unstable_interactions.track(eventOne.name, mockNow(), () => { + React.unstable_interactions.track(eventTwo.name, mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1382,16 +1378,20 @@ describe('Profiler', () => { const onRender = jest.fn(); let renderer; - InteractionTracking.track(interactionCreation.name, mockNow(), () => { - renderer = ReactTestRenderer.create( - - - , - { - unstable_isAsync: true, - }, - ); - }); + React.unstable_interactions.track( + interactionCreation.name, + mockNow(), + () => { + renderer = ReactTestRenderer.create( + + + , + { + unstable_isAsync: true, + }, + ); + }, + ); expect(onInteractionTracked).toHaveBeenCalledTimes(1); expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( @@ -1451,7 +1451,7 @@ describe('Profiler', () => { name: 'initial event', timestamp: mockNow(), }; - InteractionTracking.track(interactionOne.name, mockNow(), () => { + React.unstable_interactions.track(interactionOne.name, mockNow(), () => { instance.setState({count: 1}); // Update state again to verify our tracked interaction isn't registered twice @@ -1546,7 +1546,7 @@ describe('Profiler', () => { name: 'root update event', timestamp: mockNow(), }; - InteractionTracking.track(interactionTwo.name, mockNow(), () => { + React.unstable_interactions.track(interactionTwo.name, mockNow(), () => { renderer.update( @@ -1647,109 +1647,119 @@ describe('Profiler', () => { timestamp: mockNow(), }; - InteractionTracking.track(interactionLowPri.name, mockNow(), () => { - // Render a partially update, but don't finish. - first.setState({count: 1}); - - expect(onWorkScheduled).toHaveBeenCalled(); - expect(onWorkScheduled.mock.calls[0][0]).toMatchInteractions([ - interactionLowPri, - ]); - - expect(renderer).toFlushThrough(['FirstComponent']); - expect(onRender).not.toHaveBeenCalled(); - - expect(onInteractionTracked).toHaveBeenCalledTimes(1); - expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( - interactionLowPri, - ); - expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); - expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(1); - expect(getWorkForReactThreads(onWorkStarted)[0][0]).toMatchInteractions( - [interactionLowPri], - ); - expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0); + React.unstable_interactions.track( + interactionLowPri.name, + mockNow(), + () => { + // Render a partially update, but don't finish. + first.setState({count: 1}); - advanceTimeBy(100); + expect(onWorkScheduled).toHaveBeenCalled(); + expect(onWorkScheduled.mock.calls[0][0]).toMatchInteractions([ + interactionLowPri, + ]); - const interactionHighPri = { - id: 1, - name: 'highPri', - timestamp: mockNow(), - }; + expect(renderer).toFlushThrough(['FirstComponent']); + expect(onRender).not.toHaveBeenCalled(); - // Interrupt with higher priority work. - // This simulates a total of 37ms of actual render time. - renderer.unstable_flushSync(() => { - InteractionTracking.track(interactionHighPri.name, mockNow(), () => { - second.setState({count: 1}); + expect(onInteractionTracked).toHaveBeenCalledTimes(1); + expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( + interactionLowPri, + ); + expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); + expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(1); + expect( + getWorkForReactThreads(onWorkStarted)[0][0], + ).toMatchInteractions([interactionLowPri]); + expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0); + + advanceTimeBy(100); + + const interactionHighPri = { + id: 1, + name: 'highPri', + timestamp: mockNow(), + }; - expect(onInteractionTracked).toHaveBeenCalledTimes(2); - expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( - interactionHighPri, + // Interrupt with higher priority work. + // This simulates a total of 37ms of actual render time. + renderer.unstable_flushSync(() => { + React.unstable_interactions.track( + interactionHighPri.name, + mockNow(), + () => { + second.setState({count: 1}); + + expect(onInteractionTracked).toHaveBeenCalledTimes(2); + expect( + onInteractionTracked, + ).toHaveBeenLastNotifiedOfInteraction(interactionHighPri); + expect( + onInteractionScheduledWorkCompleted, + ).not.toHaveBeenCalled(); + + expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(1); + expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0); + }, ); - expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); - - expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(1); - expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0); }); - }); - expect(ReactTestRenderer).toClearYields(['SecondComponent']); - - expect(onInteractionTracked).toHaveBeenCalledTimes(2); - expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1); - expect( - onInteractionScheduledWorkCompleted, - ).toHaveBeenLastNotifiedOfInteraction(interactionHighPri); - - // Verify the high priority update was associated with the high priority event. - expect(onRender).toHaveBeenCalledTimes(1); - let call = onRender.mock.calls[0]; - expect(call[0]).toEqual('test'); - expect(call[5]).toEqual(mockNow()); - expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking - ? [interactionLowPri, interactionHighPri] - : [], - ); + expect(ReactTestRenderer).toClearYields(['SecondComponent']); + + expect(onInteractionTracked).toHaveBeenCalledTimes(2); + expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1); + expect( + onInteractionScheduledWorkCompleted, + ).toHaveBeenLastNotifiedOfInteraction(interactionHighPri); + + // Verify the high priority update was associated with the high priority event. + expect(onRender).toHaveBeenCalledTimes(1); + let call = onRender.mock.calls[0]; + expect(call[0]).toEqual('test'); + expect(call[5]).toEqual(mockNow()); + expect(call[6]).toMatchInteractions( + ReactFeatureFlags.enableInteractionTracking + ? [interactionLowPri, interactionHighPri] + : [], + ); - onRender.mockClear(); + onRender.mockClear(); - advanceTimeBy(100); + advanceTimeBy(100); - // Resume the original low priority update, with rebased state. - // Verify the low priority update was retained. - renderer.unstable_flushAll(['FirstComponent']); - expect(onRender).toHaveBeenCalledTimes(1); - call = onRender.mock.calls[0]; - expect(call[0]).toEqual('test'); - expect(call[5]).toEqual(mockNow()); - expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking - ? [interactionLowPri] - : [], - ); - - expect(onInteractionTracked).toHaveBeenCalledTimes(2); - expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1); + // Resume the original low priority update, with rebased state. + // Verify the low priority update was retained. + renderer.unstable_flushAll(['FirstComponent']); + expect(onRender).toHaveBeenCalledTimes(1); + call = onRender.mock.calls[0]; + expect(call[0]).toEqual('test'); + expect(call[5]).toEqual(mockNow()); + expect(call[6]).toMatchInteractions( + ReactFeatureFlags.enableInteractionTracking + ? [interactionLowPri] + : [], + ); - // Work might be started multiple times before being completed. - // This is okay; it's part of the interaction-tracking subscriber contract. - expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(3); - expect(getWorkForReactThreads(onWorkStarted)[1][0]).toMatchInteractions( - [interactionLowPri, interactionHighPri], - ); - expect(getWorkForReactThreads(onWorkStarted)[2][0]).toMatchInteractions( - [interactionLowPri], - ); - expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(2); - expect(getWorkForReactThreads(onWorkStopped)[0][0]).toMatchInteractions( - [interactionLowPri, interactionHighPri], - ); - expect(getWorkForReactThreads(onWorkStopped)[1][0]).toMatchInteractions( - [interactionLowPri], - ); - }); + expect(onInteractionTracked).toHaveBeenCalledTimes(2); + expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1); + + // Work might be started multiple times before being completed. + // This is okay; it's part of the interaction-tracking subscriber contract. + expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(3); + expect( + getWorkForReactThreads(onWorkStarted)[1][0], + ).toMatchInteractions([interactionLowPri, interactionHighPri]); + expect( + getWorkForReactThreads(onWorkStarted)[2][0], + ).toMatchInteractions([interactionLowPri]); + expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(2); + expect( + getWorkForReactThreads(onWorkStopped)[0][0], + ).toMatchInteractions([interactionLowPri, interactionHighPri]); + expect( + getWorkForReactThreads(onWorkStopped)[1][0], + ).toMatchInteractions([interactionLowPri]); + }, + ); expect(onInteractionTracked).toHaveBeenCalledTimes(2); expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2); @@ -1793,7 +1803,7 @@ describe('Profiler', () => { const onRender = jest.fn(); let firstCommitTime = mockNow(); let renderer; - InteractionTracking.track(interactionOne.name, mockNow(), () => { + React.unstable_interactions.track(interactionOne.name, mockNow(), () => { renderer = ReactTestRenderer.create( @@ -1855,7 +1865,7 @@ describe('Profiler', () => { }; // Cause an tracked, async update - InteractionTracking.track(interactionTwo.name, mockNow(), () => { + React.unstable_interactions.track(interactionTwo.name, mockNow(), () => { instance.setState({count: 2}); }); expect(onRender).not.toHaveBeenCalled(); @@ -1921,9 +1931,13 @@ describe('Profiler', () => { function callback() { instance.setState({count: 6}); } - InteractionTracking.track(interactionThree.name, mockNow(), () => { - instance.setState({count: 5}, callback); - }); + React.unstable_interactions.track( + interactionThree.name, + mockNow(), + () => { + instance.setState({count: 5}, callback); + }, + ); expect(onRender).not.toHaveBeenCalled(); expect(onInteractionTracked).toHaveBeenCalledTimes(3); @@ -2014,7 +2028,7 @@ describe('Profiler', () => { timestamp: mockNow(), }; - InteractionTracking.track(interaction.name, mockNow(), () => { + React.unstable_interactions.track(interaction.name, mockNow(), () => { parentInstance.setState({count: 1}); }); @@ -2060,7 +2074,7 @@ describe('Profiler', () => { }); // Re-register since we've reloaded modules - InteractionTrackingSubscriptions.subscribe({ + React.unstable_interactions.subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, @@ -2127,7 +2141,7 @@ describe('Profiler', () => { }; const onRender = jest.fn(); - InteractionTracking.track(interaction.name, mockNow(), () => { + React.unstable_interactions.track(interaction.name, mockNow(), () => { ReactNoop.render( }> diff --git a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js index 201c9a1803c7f..f304ce983188e 100644 --- a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js +++ b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js @@ -14,7 +14,6 @@ describe('ReactProfiler DevTools integration', () => { let React; let ReactFeatureFlags; let ReactTestRenderer; - let InteractionTracking; let AdvanceTime; let advanceTimeBy; let hook; @@ -41,7 +40,6 @@ describe('ReactProfiler DevTools integration', () => { ReactFeatureFlags.enableInteractionTracking = true; React = require('react'); ReactTestRenderer = require('react-test-renderer'); - InteractionTracking = require('interaction-tracking'); ReactTestRenderer.unstable_setNowImplementation(mockNow); advanceTimeBy = amount => { @@ -180,7 +178,7 @@ describe('ReactProfiler DevTools integration', () => { const eventTime = mockNow(); // Render with an interaction - InteractionTracking.track('some event', eventTime, () => { + React.unstable_interactions.track('some event', eventTime, () => { rendered.update(
); }); diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 75bf3955ca803..fa1c8f90c6630 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -408,33 +408,6 @@ function shouldSkipBundle(bundle, bundleType) { return false; } -// Strip unused require() statements for pure externals modules from the bundle. -// Rollup's treeshake option should do this, but it doesn't work. -function stripNoSideEffectImports(bundleType, pureExternalModules, filePath) { - const isProduction = isProductionBundleType(bundleType); - - // Dead code elimintation is only applied to production bundles. - if (!isProduction) { - return; - } - - const codeIn = fs.readFileSync(filePath, 'utf-8'); - let codeOut = codeIn; - - pureExternalModules.forEach(module => { - const regExp = new RegExp( - `(? Date: Wed, 29 Aug 2018 16:34:48 -0700 Subject: [PATCH 04/12] Add InteractionTracking production bundle test --- .../src/__tests__/InteractionTracking-test.js | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 packages/interaction-tracking/src/__tests__/InteractionTracking-test.js diff --git a/packages/interaction-tracking/src/__tests__/InteractionTracking-test.js b/packages/interaction-tracking/src/__tests__/InteractionTracking-test.js new file mode 100644 index 0000000000000..1130882d96424 --- /dev/null +++ b/packages/interaction-tracking/src/__tests__/InteractionTracking-test.js @@ -0,0 +1,51 @@ +/** + * 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. + * + * @jest-environment node + */ +'use strict'; + +describe('InteractionTracking', () => { + let InteractionTracking; + + beforeEach(() => { + jest.resetModules(); + + InteractionTracking = require('interaction-tracking'); + }); + + it('should return the value of a tracked function', () => { + expect(InteractionTracking.unstable_track('arbitrary', 0, () => 123)).toBe( + 123, + ); + }); + + it('should return the value of a wrapped function', () => { + let wrapped; + InteractionTracking.unstable_track('arbitrary', 0, () => { + wrapped = InteractionTracking.unstable_wrap(() => 123); + }); + expect(wrapped()).toBe(123); + }); + + it('should execute tracked callbacks', done => { + InteractionTracking.unstable_track('some event', 0, () => { + done(); + }); + }); + + it('should return the value of a clear function', () => { + expect(InteractionTracking.unstable_clear(() => 123)).toBe(123); + }); + + it('should execute wrapped callbacks', done => { + const wrappedCallback = InteractionTracking.unstable_wrap(() => { + done(); + }); + + wrappedCallback(); + }); +}); From 9448d38c0549d80cbb2ee91a63d6ccdb549f79b4 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 29 Aug 2018 16:48:00 -0700 Subject: [PATCH 05/12] Edge case guard against a wrapped function being run multiple times --- .../src/InteractionTracking.js | 27 ++++++++++----- ...tionTrackingSubscriptions-test.internal.js | 33 +++++++++++++++++++ 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/packages/interaction-tracking/src/InteractionTracking.js b/packages/interaction-tracking/src/InteractionTracking.js index 04511ad99fa87..6b00118bb5749 100644 --- a/packages/interaction-tracking/src/InteractionTracking.js +++ b/packages/interaction-tracking/src/InteractionTracking.js @@ -195,6 +195,8 @@ export function unstable_wrap( interaction.__count++; }); + let hasRun = false; + function wrapped() { const prevInteractions = interactionsRef.current; interactionsRef.current = wrappedInteractions; @@ -222,16 +224,23 @@ export function unstable_wrap( return returnValue; } finally { - // Update pending async counts for all wrapped interactions. - // If this was the last scheduled async work for any of them, - // Mark them as completed. - wrappedInteractions.forEach(interaction => { - interaction.__count--; + if (!hasRun) { + // We only expect a wrapped function to be executed once, + // But in the event that it's executed more than once– + // Only decrement the outstanding interaction counts once. + hasRun = true; + + // Update pending async counts for all wrapped interactions. + // If this was the last scheduled async work for any of them, + // Mark them as completed. + wrappedInteractions.forEach(interaction => { + interaction.__count--; - if (subscriber !== null && interaction.__count === 0) { - subscriber.onInteractionScheduledWorkCompleted(interaction); - } - }); + if (subscriber !== null && interaction.__count === 0) { + subscriber.onInteractionScheduledWorkCompleted(interaction); + } + }); + } } } diff --git a/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js b/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js index 1a4fd5950a5f3..17d8afa5cd8e7 100644 --- a/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js +++ b/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js @@ -582,6 +582,39 @@ describe('InteractionTracking', () => { ).toHaveBeenLastNotifiedOfInteraction(firstEvent); }); + it('should not decrement the interaction count twice if a wrapped function is run twice', () => { + const unwrappedOne = jest.fn(); + const unwrappedTwo = jest.fn(); + let wrappedOne, wrappedTwo; + InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + wrappedOne = InteractionTracking.unstable_wrap(unwrappedOne, threadID); + wrappedTwo = InteractionTracking.unstable_wrap(unwrappedTwo, threadID); + }); + + expect(onInteractionTracked).toHaveBeenCalledTimes(1); + expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); + + wrappedOne(); + + expect(unwrappedOne).toHaveBeenCalledTimes(1); + expect(onInteractionTracked).toHaveBeenCalledTimes(1); + expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); + + wrappedOne(); + + expect(unwrappedOne).toHaveBeenCalledTimes(2); + expect(onInteractionTracked).toHaveBeenCalledTimes(1); + expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); + + wrappedTwo(); + + expect(onInteractionTracked).toHaveBeenCalledTimes(1); + expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1); + expect( + onInteractionScheduledWorkCompleted, + ).toHaveBeenLastNotifiedOfInteraction(firstEvent); + }); + it('should unsubscribe', () => { InteractionTrackingSubscriptions.unstable_unsubscribe(firstSubscriber); InteractionTracking.unstable_track( From b77673baa4c32e53ea9982260c53682ac86f7c79 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Wed, 29 Aug 2018 17:13:37 -0700 Subject: [PATCH 06/12] Fixed fixtures/packaging --- .../packaging/browserify/dev/package.json | 1 + fixtures/packaging/browserify/dev/yarn.lock | 92 +------------------ .../packaging/browserify/prod/package.json | 1 + fixtures/packaging/browserify/prod/yarn.lock | 92 +------------------ fixtures/packaging/brunch/dev/package.json | 1 + fixtures/packaging/brunch/dev/yarn.lock | 81 +++------------- fixtures/packaging/brunch/prod/package.json | 1 + fixtures/packaging/brunch/prod/yarn.lock | 81 +++------------- fixtures/packaging/rjs/dev/config.js | 2 + fixtures/packaging/rjs/prod/config.js | 2 + .../packaging/systemjs-builder/dev/config.js | 2 + .../packaging/systemjs-builder/prod/config.js | 2 + 12 files changed, 46 insertions(+), 312 deletions(-) diff --git a/fixtures/packaging/browserify/dev/package.json b/fixtures/packaging/browserify/dev/package.json index 059ce202ba8b3..4c7246ea3618e 100644 --- a/fixtures/packaging/browserify/dev/package.json +++ b/fixtures/packaging/browserify/dev/package.json @@ -3,6 +3,7 @@ "name": "browserify-dev-fixture", "dependencies": { "browserify": "^13.3.0", + "interaction-tracking": "link:../../../../build/node_modules/interaction-tracking", "react": "link:../../../../build/node_modules/react", "react-dom": "link:../../../../build/node_modules/react-dom" }, diff --git a/fixtures/packaging/browserify/dev/yarn.lock b/fixtures/packaging/browserify/dev/yarn.lock index b1a8fa7a87ac8..cd132ad43a59a 100644 --- a/fixtures/packaging/browserify/dev/yarn.lock +++ b/fixtures/packaging/browserify/dev/yarn.lock @@ -25,10 +25,6 @@ array-reduce@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - asn1.js@^4.0.0: version "4.9.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" @@ -254,10 +250,6 @@ convert-source-map@~1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -365,12 +357,6 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - events@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -382,18 +368,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -fbjs@^0.8.16: - version "0.8.16" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.9" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -455,10 +429,6 @@ https-browserify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -iconv-lite@~0.4.13: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" @@ -501,14 +471,14 @@ insert-module-globals@^7.0.0: through2 "^2.0.0" xtend "^4.0.0" +"interaction-tracking@link:../../../../build/node_modules/interaction-tracking": + version "0.0.0" + uid "" + is-buffer@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" -is-stream@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -517,17 +487,6 @@ isarray@~0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - -js-tokens@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - json-stable-stringify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" @@ -560,12 +519,6 @@ lodash.memoize@~3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" - dependencies: - js-tokens "^3.0.0" - md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -618,17 +571,6 @@ module-deps@^4.0.8: through2 "^2.0.0" xtend "^4.0.0" -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - -object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -693,20 +635,6 @@ process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - dependencies: - asap "~2.0.3" - -prop-types@^15.6.0: - version "15.6.0" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" - dependencies: - fbjs "^0.8.16" - loose-envify "^1.3.1" - object-assign "^4.1.1" - public-encrypt@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" @@ -797,10 +725,6 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: version "2.4.9" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.9.tgz#98f64880474b74f4a38b8da9d3c0f2d104633e7d" @@ -910,10 +834,6 @@ typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -ua-parser-js@^0.7.9: - version "0.7.17" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" - umd@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" @@ -941,10 +861,6 @@ vm-browserify@~0.0.1: dependencies: indexof "0.0.1" -whatwg-fetch@>=0.10.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" - wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" diff --git a/fixtures/packaging/browserify/prod/package.json b/fixtures/packaging/browserify/prod/package.json index d966e899e405f..acb8b3152f4d6 100644 --- a/fixtures/packaging/browserify/prod/package.json +++ b/fixtures/packaging/browserify/prod/package.json @@ -3,6 +3,7 @@ "name": "browserify-prod-fixture", "dependencies": { "browserify": "^13.3.0", + "interaction-tracking": "link:../../../../build/node_modules/interaction-tracking", "react": "link:../../../../build/node_modules/react", "react-dom": "link:../../../../build/node_modules/react-dom" }, diff --git a/fixtures/packaging/browserify/prod/yarn.lock b/fixtures/packaging/browserify/prod/yarn.lock index 64b3dd9df4289..6b6b3894e5bc4 100644 --- a/fixtures/packaging/browserify/prod/yarn.lock +++ b/fixtures/packaging/browserify/prod/yarn.lock @@ -25,10 +25,6 @@ array-reduce@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - asn1.js@^4.0.0: version "4.9.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" @@ -254,10 +250,6 @@ convert-source-map@~1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -365,12 +357,6 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - envify@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/envify/-/envify-4.1.0.tgz#f39ad3db9d6801b4e6b478b61028d3f0b6819f7e" @@ -393,18 +379,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -fbjs@^0.8.16: - version "0.8.16" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.9" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -466,10 +440,6 @@ https-browserify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -iconv-lite@~0.4.13: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" @@ -512,14 +482,14 @@ insert-module-globals@^7.0.0: through2 "^2.0.0" xtend "^4.0.0" +"interaction-tracking@link:../../../../build/node_modules/interaction-tracking": + version "0.0.0" + uid "" + is-buffer@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" -is-stream@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -528,17 +498,6 @@ isarray@~0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - -js-tokens@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - json-stable-stringify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" @@ -571,12 +530,6 @@ lodash.memoize@~3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" - dependencies: - js-tokens "^3.0.0" - md5.js@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.4.tgz#e9bdbde94a20a5ac18b04340fc5764d5b09d901d" @@ -629,17 +582,6 @@ module-deps@^4.0.8: through2 "^2.0.0" xtend "^4.0.0" -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - -object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -704,20 +646,6 @@ process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - dependencies: - asap "~2.0.3" - -prop-types@^15.6.0: - version "15.6.0" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" - dependencies: - fbjs "^0.8.16" - loose-envify "^1.3.1" - object-assign "^4.1.1" - public-encrypt@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" @@ -808,10 +736,6 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: version "2.4.9" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.9.tgz#98f64880474b74f4a38b8da9d3c0f2d104633e7d" @@ -921,10 +845,6 @@ typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -ua-parser-js@^0.7.9: - version "0.7.17" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" - umd@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" @@ -952,10 +872,6 @@ vm-browserify@~0.0.1: dependencies: indexof "0.0.1" -whatwg-fetch@>=0.10.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" - wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" diff --git a/fixtures/packaging/brunch/dev/package.json b/fixtures/packaging/brunch/dev/package.json index 69a572eeb3bb6..74ccd7be3c8ab 100644 --- a/fixtures/packaging/brunch/dev/package.json +++ b/fixtures/packaging/brunch/dev/package.json @@ -4,6 +4,7 @@ "devDependencies": { "brunch": "^2.9.1", "javascript-brunch": "^2.0.0", + "interaction-tracking": "link:../../../../build/node_modules/interaction-tracking", "react": "link:../../../../build/node_modules/react", "react-dom": "link:../../../../build/node_modules/react-dom" }, diff --git a/fixtures/packaging/brunch/dev/yarn.lock b/fixtures/packaging/brunch/dev/yarn.lock index 610a93e9f0572..a9d59113869a4 100644 --- a/fixtures/packaging/brunch/dev/yarn.lock +++ b/fixtures/packaging/brunch/dev/yarn.lock @@ -78,10 +78,6 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - asn1.js@^4.0.0: version "4.9.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" @@ -413,10 +409,6 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -604,12 +596,6 @@ encodeurl@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - es-abstract@^1.6.1: version "1.9.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" @@ -726,18 +712,6 @@ fast-levenshtein@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9" -fbjs@^0.8.16: - version "0.8.16" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.9" - fcache@~0.3: version "0.3.0" resolved "https://registry.yarnpkg.com/fcache/-/fcache-0.3.0.tgz#d45f2f908642b91b798e88195ec47881a51c3d44" @@ -1027,7 +1001,7 @@ https-browserify@~0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -iconv-lite@0.4.19, iconv-lite@~0.4.13: +iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -1070,6 +1044,14 @@ init-skeleton@~1.0: ncp "^2.0.0" normalize-git-url "~3.0.1" +interaction-tracking@16.4.3-alpha.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/interaction-tracking/-/interaction-tracking-0.0.1.tgz#08877accb2ec479f2af83d7de7a9ae60b80e8dc5" + +"interaction-tracking@link:../../../../build/node_modules/interaction-tracking": + version "0.0.0" + uid "" + ipaddr.js@1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" @@ -1152,10 +1134,6 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" -is-stream@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" @@ -1182,13 +1160,6 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -1264,7 +1235,7 @@ loggy@~0.3.0: ansicolors "~0.3.2" growl "~1.8.1" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: +loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -1423,13 +1394,6 @@ node-browser-modules@^0.1.0: util "~0.10.3" vm-browserify "~0.0.4" -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - node-pre-gyp@^0.6.36: version "0.6.38" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d" @@ -1605,17 +1569,10 @@ promise.prototype.finally@^2: es-abstract "^1.6.1" function-bind "^1.1.0" -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" +prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: - asap "~2.0.3" - -prop-types@^15.6.0: - version "15.6.0" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" - dependencies: - fbjs "^0.8.16" loose-envify "^1.3.1" object-assign "^4.1.1" @@ -1870,10 +1827,6 @@ set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" @@ -2053,10 +2006,6 @@ type-is@~1.6.15: media-typer "0.3.0" mime-types "~2.1.15" -ua-parser-js@^0.7.9: - version "0.7.17" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" - uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -2118,10 +2067,6 @@ vm-browserify@~0.0.4: dependencies: indexof "0.0.1" -whatwg-fetch@>=0.10.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" - which@^1.2.12: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" diff --git a/fixtures/packaging/brunch/prod/package.json b/fixtures/packaging/brunch/prod/package.json index 065461bafd8ad..34046ef401785 100644 --- a/fixtures/packaging/brunch/prod/package.json +++ b/fixtures/packaging/brunch/prod/package.json @@ -4,6 +4,7 @@ "devDependencies": { "brunch": "^2.9.1", "javascript-brunch": "^2.0.0", + "interaction-tracking": "link:../../../../build/node_modules/interaction-tracking", "react": "link:../../../../build/node_modules/react", "react-dom": "link:../../../../build/node_modules/react-dom" }, diff --git a/fixtures/packaging/brunch/prod/yarn.lock b/fixtures/packaging/brunch/prod/yarn.lock index 610a93e9f0572..a9d59113869a4 100644 --- a/fixtures/packaging/brunch/prod/yarn.lock +++ b/fixtures/packaging/brunch/prod/yarn.lock @@ -78,10 +78,6 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - asn1.js@^4.0.0: version "4.9.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" @@ -413,10 +409,6 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -604,12 +596,6 @@ encodeurl@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" -encoding@^0.1.11: - version "0.1.12" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" - dependencies: - iconv-lite "~0.4.13" - es-abstract@^1.6.1: version "1.9.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" @@ -726,18 +712,6 @@ fast-levenshtein@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9" -fbjs@^0.8.16: - version "0.8.16" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.9" - fcache@~0.3: version "0.3.0" resolved "https://registry.yarnpkg.com/fcache/-/fcache-0.3.0.tgz#d45f2f908642b91b798e88195ec47881a51c3d44" @@ -1027,7 +1001,7 @@ https-browserify@~0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -iconv-lite@0.4.19, iconv-lite@~0.4.13: +iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -1070,6 +1044,14 @@ init-skeleton@~1.0: ncp "^2.0.0" normalize-git-url "~3.0.1" +interaction-tracking@16.4.3-alpha.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/interaction-tracking/-/interaction-tracking-0.0.1.tgz#08877accb2ec479f2af83d7de7a9ae60b80e8dc5" + +"interaction-tracking@link:../../../../build/node_modules/interaction-tracking": + version "0.0.0" + uid "" + ipaddr.js@1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" @@ -1152,10 +1134,6 @@ is-regex@^1.0.4: dependencies: has "^1.0.1" -is-stream@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" @@ -1182,13 +1160,6 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isomorphic-fetch@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" - dependencies: - node-fetch "^1.0.1" - whatwg-fetch ">=0.10.0" - isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -1264,7 +1235,7 @@ loggy@~0.3.0: ansicolors "~0.3.2" growl "~1.8.1" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: +loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -1423,13 +1394,6 @@ node-browser-modules@^0.1.0: util "~0.10.3" vm-browserify "~0.0.4" -node-fetch@^1.0.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - node-pre-gyp@^0.6.36: version "0.6.38" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d" @@ -1605,17 +1569,10 @@ promise.prototype.finally@^2: es-abstract "^1.6.1" function-bind "^1.1.0" -promise@^7.1.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" +prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: - asap "~2.0.3" - -prop-types@^15.6.0: - version "15.6.0" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" - dependencies: - fbjs "^0.8.16" loose-envify "^1.3.1" object-assign "^4.1.1" @@ -1870,10 +1827,6 @@ set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" @@ -2053,10 +2006,6 @@ type-is@~1.6.15: media-typer "0.3.0" mime-types "~2.1.15" -ua-parser-js@^0.7.9: - version "0.7.17" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" - uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -2118,10 +2067,6 @@ vm-browserify@~0.0.4: dependencies: indexof "0.0.1" -whatwg-fetch@>=0.10.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" - which@^1.2.12: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" diff --git a/fixtures/packaging/rjs/dev/config.js b/fixtures/packaging/rjs/dev/config.js index b955f32efe97c..e46833b7ae5f1 100644 --- a/fixtures/packaging/rjs/dev/config.js +++ b/fixtures/packaging/rjs/dev/config.js @@ -4,6 +4,8 @@ module.exports = { out: 'output.js', optimize: 'none', paths: { + 'interaction-tracking': + '../../../../build/dist/interaction-tracking.development', react: '../../../../build/dist/react.development', 'react-dom': '../../../../build/dist/react-dom.development', }, diff --git a/fixtures/packaging/rjs/prod/config.js b/fixtures/packaging/rjs/prod/config.js index 86d76331a2220..291da0e546388 100644 --- a/fixtures/packaging/rjs/prod/config.js +++ b/fixtures/packaging/rjs/prod/config.js @@ -4,6 +4,8 @@ module.exports = { out: 'output.js', optimize: 'none', paths: { + 'interaction-tracking': + '../../../../build/dist/interaction-tracking.production.min', react: '../../../../build/dist/react.production.min', 'react-dom': '../../../../build/dist/react-dom.production.min', }, diff --git a/fixtures/packaging/systemjs-builder/dev/config.js b/fixtures/packaging/systemjs-builder/dev/config.js index 2cd1b3d66f9ce..36cfd28e3f6b8 100644 --- a/fixtures/packaging/systemjs-builder/dev/config.js +++ b/fixtures/packaging/systemjs-builder/dev/config.js @@ -1,5 +1,7 @@ System.config({ paths: { + 'interaction-tracking': + '../../../../build/dist/interaction-tracking.development.js', react: '../../../../build/dist/react.development.js', 'react-dom': '../../../../build/dist/react-dom.development.js', }, diff --git a/fixtures/packaging/systemjs-builder/prod/config.js b/fixtures/packaging/systemjs-builder/prod/config.js index bb981fe2b7e59..0ab9c6804e534 100644 --- a/fixtures/packaging/systemjs-builder/prod/config.js +++ b/fixtures/packaging/systemjs-builder/prod/config.js @@ -1,5 +1,7 @@ System.config({ paths: { + 'interaction-tracking': + '../../../../build/dist/interaction-tracking.production.min.js', react: '../../../../build/dist/react.production.min.js', 'react-dom': '../../../../build/dist/react-dom.production.min.js', }, From 4eec46b8abce3711b273a6d678b39287a1ed3dee Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 30 Aug 2018 10:51:27 -0700 Subject: [PATCH 07/12] Export subset of interaction-tracking API required by reconciler via SECRET_INTERNALS This is being done so that UMD builds will continue to work without requiring a backwards breaking change. Application code should consume the new interaction-tracking API directly from NPM. Reconciler code will access the subset of the API it needs from the SECRET_INTERNALS object in order to avoid breaking UMD builds. As a result of this, interaction-tracking will not be supported for UMD builds. --- .../suspense/src/components/App.js | 8 ++-- fixtures/unstable-async/suspense/src/index.js | 5 +-- .../react-reconciler/src/ReactFiberRoot.js | 8 +++- .../src/ReactFiberScheduler.js | 10 +++-- packages/react/package.json | 2 +- packages/react/src/React.js | 28 -------------- packages/react/src/ReactSharedInternals.js | 13 +++++++ .../__tests__/ReactProfiler-test.internal.js | 38 ++++++++++--------- ...ofilerDevToolsIntegration-test.internal.js | 4 +- .../ReactFeatureFlags.native-fabric-fb.js | 2 +- .../ReactFeatureFlags.native-fabric-oss.js | 2 +- .../forks/ReactFeatureFlags.native-fb.js | 2 +- .../forks/ReactFeatureFlags.native-oss.js | 2 +- .../forks/ReactFeatureFlags.persistent.js | 2 +- 14 files changed, 63 insertions(+), 63 deletions(-) diff --git a/fixtures/unstable-async/suspense/src/components/App.js b/fixtures/unstable-async/suspense/src/components/App.js index 28b2c9b677898..77f7a7e3c606f 100644 --- a/fixtures/unstable-async/suspense/src/components/App.js +++ b/fixtures/unstable-async/suspense/src/components/App.js @@ -1,11 +1,13 @@ -import React, {Placeholder, PureComponent, unstable_interactions} from 'react'; +import React, {Placeholder, PureComponent} from 'react'; +import { + unstable_track as track, + unstable_wrap as wrap, +} from 'interaction-tracking'; import {createResource} from 'simple-cache-provider'; import {cache} from '../cache'; import Spinner from './Spinner'; import ContributorListPage from './ContributorListPage'; -const {track, wrap} = unstable_interactions; - const UserPageResource = createResource(() => import('./UserPage')); function UserPageLoader(props) { diff --git a/fixtures/unstable-async/suspense/src/index.js b/fixtures/unstable-async/suspense/src/index.js index 847c50debc3ce..eda669478a1b7 100644 --- a/fixtures/unstable-async/suspense/src/index.js +++ b/fixtures/unstable-async/suspense/src/index.js @@ -1,5 +1,6 @@ -import React, {Fragment, PureComponent, unstable_interactions} from 'react'; +import React, {Fragment, PureComponent} from 'react'; import {unstable_createRoot, render} from 'react-dom'; +import {unstable_track as track} from 'interaction-tracking'; import {cache} from './cache'; import { setFakeRequestTime, @@ -11,8 +12,6 @@ import App from './components/App'; import Draggable from 'react-draggable'; import './index.css'; -const {track} = unstable_interactions; - let handleReset; class Shell extends PureComponent { diff --git a/packages/react-reconciler/src/ReactFiberRoot.js b/packages/react-reconciler/src/ReactFiberRoot.js index 86c8fa50f4265..603748842ca1d 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.js +++ b/packages/react-reconciler/src/ReactFiberRoot.js @@ -12,13 +12,17 @@ import type {ExpirationTime} from './ReactFiberExpirationTime'; import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig'; import type {Interaction} from 'interaction-tracking/src/InteractionTracking'; -import React from 'react'; import {noTimeout} from './ReactFiberHostConfig'; import {createHostRootFiber} from './ReactFiber'; import {NoWork} from './ReactFiberExpirationTime'; +import ReactSharedInternals from 'shared/ReactSharedInternals'; import {enableInteractionTracking} from 'shared/ReactFeatureFlags'; -const {getThreadID} = React.unstable_interactions; +// Access the interaction-tracking API from React's internal re-export. +// This will be a re-export of the interaction-tracking package for CJS bundles, +// And an embedded version for UMD bundles. +// This is being done so that we don't break backwards compat for existing UMD apps. +const {getThreadID} = ReactSharedInternals.InteractionTracking; // TODO: This should be lifted into the renderer. export type Batch = { diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index 784453c30f964..9c1e959fd87c6 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -12,7 +12,6 @@ import type {Batch, FiberRoot} from './ReactFiberRoot'; import type {ExpirationTime} from './ReactFiberExpirationTime'; import type {Interaction} from 'interaction-tracking/src/InteractionTracking'; -import React from 'react'; import { invokeGuardedCallback, hasCaughtError, @@ -160,8 +159,13 @@ export type Thenable = { then(resolve: () => mixed, reject?: () => mixed): mixed, }; -const {ReactCurrentOwner} = ReactSharedInternals; -const {__interactionsRef, __subscriberRef} = React.unstable_interactions; +const {InteractionTracking, ReactCurrentOwner} = ReactSharedInternals; + +// Access the interaction-tracking API from React's internal re-export. +// This will be a re-export of the interaction-tracking package for CJS bundles, +// And an embedded version for UMD bundles. +// This is being done so that we don't break backwards compat for existing UMD apps. +const {__interactionsRef, __subscriberRef} = InteractionTracking; let didWarnAboutStateTransition; let didWarnSetStateChildContext; diff --git a/packages/react/package.json b/packages/react/package.json index 482dede2d4a5d..a643a46ea7232 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -21,7 +21,7 @@ "node": ">=0.10.0" }, "dependencies": { - "interaction-tracking": "16.4.3-alpha.0", + "interaction-tracking": "^16.4.3-alpha.0", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "prop-types": "^15.6.2" diff --git a/packages/react/src/React.js b/packages/react/src/React.js index 97d8417bfb295..85e1207a90262 100644 --- a/packages/react/src/React.js +++ b/packages/react/src/React.js @@ -33,19 +33,6 @@ import { cloneElementWithValidation, } from './ReactElementValidator'; import ReactSharedInternals from './ReactSharedInternals'; -import { - __interactionsRef, - __subscriberRef, - unstable_clear as clear, - unstable_getCurrent as getCurrent, - unstable_getThreadID as getThreadID, - unstable_track as track, - unstable_wrap as wrap, -} from 'interaction-tracking'; -import { - unstable_subscribe as subscribe, - unstable_unsubscribe as unsubscribe, -} from 'interaction-tracking/subscriptions'; const React = { Children: { @@ -75,21 +62,6 @@ const React = { version: ReactVersion, - // Re-export the interaction-tracking API for UMD bundles. - // This avoids introducing a dependency on a new UMD global in a minor update, - // Since this would be a breaking change. - unstable_interactions: { - __interactionsRef, - __subscriberRef, - clear, - getCurrent, - getThreadID, - subscribe, - track, - unsubscribe, - wrap, - }, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals, }; diff --git a/packages/react/src/ReactSharedInternals.js b/packages/react/src/ReactSharedInternals.js index 8b179aff8422c..95ec6631bef45 100644 --- a/packages/react/src/ReactSharedInternals.js +++ b/packages/react/src/ReactSharedInternals.js @@ -5,6 +5,11 @@ * LICENSE file in the root directory of this source tree. */ +import { + __interactionsRef, + __subscriberRef, + unstable_getThreadID as getThreadID, +} from 'interaction-tracking'; import assign from 'object-assign'; import ReactCurrentOwner from './ReactCurrentOwner'; import ReactDebugCurrentFrame from './ReactDebugCurrentFrame'; @@ -13,6 +18,14 @@ const ReactSharedInternals = { ReactCurrentOwner, // Used by renderers to avoid bundling object-assign twice in UMD bundles: assign, + // Re-export the interaction-tracking API for UMD bundles. + // This avoids introducing a dependency on a new UMD global in a minor update, + // Since this would be a breaking change. + InteractionTracking: { + __interactionsRef, + __subscriberRef, + getThreadID, + }, }; if (__DEV__) { diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 563f5a05eed4e..7bb97a13d8ef8 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -15,6 +15,8 @@ let ReactFeatureFlags; let ReactNoop; let ReactTestRenderer; let advanceTimeBy; +let InteractionTracking; +let InteractionTrackingSubscriptions; let mockNow; let AdvanceTime; @@ -41,6 +43,8 @@ function loadModules({ ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = replayFailedUnitOfWorkWithInvokeGuardedCallback; React = require('react'); + InteractionTracking = require('interaction-tracking'); + InteractionTrackingSubscriptions = require('interaction-tracking/subscriptions'); if (useNoopRenderer) { ReactNoop = require('react-noop-renderer'); @@ -1204,7 +1208,7 @@ describe('Profiler', () => { }); // Verify interaction subscriber methods are called as expected. - React.unstable_interactions.subscribe({ + InteractionTrackingSubscriptions.unstable_subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, @@ -1226,7 +1230,7 @@ describe('Profiler', () => { // Errors that happen inside of a subscriber should throw, throwInOnWorkScheduled = true; expect(() => { - React.unstable_interactions.track('event', mockNow(), () => { + InteractionTracking.unstable_track('event', mockNow(), () => { renderer = ReactTestRenderer.create(fail, { unstable_isAsync: true, }); @@ -1252,7 +1256,7 @@ describe('Profiler', () => { } let renderer; - React.unstable_interactions.track('event', mockNow(), () => { + InteractionTracking.unstable_track('event', mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1281,7 +1285,7 @@ describe('Profiler', () => { } let renderer; - React.unstable_interactions.track('event', mockNow(), () => { + InteractionTracking.unstable_track('event', mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1323,8 +1327,8 @@ describe('Profiler', () => { }; let renderer; - React.unstable_interactions.track(eventOne.name, mockNow(), () => { - React.unstable_interactions.track(eventTwo.name, mockNow(), () => { + InteractionTracking.unstable_track(eventOne.name, mockNow(), () => { + InteractionTracking.unstable_track(eventTwo.name, mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1378,7 +1382,7 @@ describe('Profiler', () => { const onRender = jest.fn(); let renderer; - React.unstable_interactions.track( + InteractionTracking.unstable_track( interactionCreation.name, mockNow(), () => { @@ -1451,7 +1455,7 @@ describe('Profiler', () => { name: 'initial event', timestamp: mockNow(), }; - React.unstable_interactions.track(interactionOne.name, mockNow(), () => { + InteractionTracking.unstable_track(interactionOne.name, mockNow(), () => { instance.setState({count: 1}); // Update state again to verify our tracked interaction isn't registered twice @@ -1546,7 +1550,7 @@ describe('Profiler', () => { name: 'root update event', timestamp: mockNow(), }; - React.unstable_interactions.track(interactionTwo.name, mockNow(), () => { + InteractionTracking.unstable_track(interactionTwo.name, mockNow(), () => { renderer.update( @@ -1647,7 +1651,7 @@ describe('Profiler', () => { timestamp: mockNow(), }; - React.unstable_interactions.track( + InteractionTracking.unstable_track( interactionLowPri.name, mockNow(), () => { @@ -1684,7 +1688,7 @@ describe('Profiler', () => { // Interrupt with higher priority work. // This simulates a total of 37ms of actual render time. renderer.unstable_flushSync(() => { - React.unstable_interactions.track( + InteractionTracking.unstable_track( interactionHighPri.name, mockNow(), () => { @@ -1803,7 +1807,7 @@ describe('Profiler', () => { const onRender = jest.fn(); let firstCommitTime = mockNow(); let renderer; - React.unstable_interactions.track(interactionOne.name, mockNow(), () => { + InteractionTracking.unstable_track(interactionOne.name, mockNow(), () => { renderer = ReactTestRenderer.create( @@ -1865,7 +1869,7 @@ describe('Profiler', () => { }; // Cause an tracked, async update - React.unstable_interactions.track(interactionTwo.name, mockNow(), () => { + InteractionTracking.unstable_track(interactionTwo.name, mockNow(), () => { instance.setState({count: 2}); }); expect(onRender).not.toHaveBeenCalled(); @@ -1931,7 +1935,7 @@ describe('Profiler', () => { function callback() { instance.setState({count: 6}); } - React.unstable_interactions.track( + InteractionTracking.unstable_track( interactionThree.name, mockNow(), () => { @@ -2028,7 +2032,7 @@ describe('Profiler', () => { timestamp: mockNow(), }; - React.unstable_interactions.track(interaction.name, mockNow(), () => { + InteractionTracking.unstable_track(interaction.name, mockNow(), () => { parentInstance.setState({count: 1}); }); @@ -2074,7 +2078,7 @@ describe('Profiler', () => { }); // Re-register since we've reloaded modules - React.unstable_interactions.subscribe({ + InteractionTrackingSubscriptions.unstable_subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, @@ -2141,7 +2145,7 @@ describe('Profiler', () => { }; const onRender = jest.fn(); - React.unstable_interactions.track(interaction.name, mockNow(), () => { + InteractionTracking.unstable_track(interaction.name, mockNow(), () => { ReactNoop.render( }> diff --git a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js index f304ce983188e..3f55ba2b8be9d 100644 --- a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js +++ b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js @@ -11,6 +11,7 @@ 'use strict'; describe('ReactProfiler DevTools integration', () => { + let InteractionTracking; let React; let ReactFeatureFlags; let ReactTestRenderer; @@ -38,6 +39,7 @@ describe('ReactProfiler DevTools integration', () => { ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.enableProfilerTimer = true; ReactFeatureFlags.enableInteractionTracking = true; + InteractionTracking = require('interaction-tracking'); React = require('react'); ReactTestRenderer = require('react-test-renderer'); @@ -178,7 +180,7 @@ describe('ReactProfiler DevTools integration', () => { const eventTime = mockNow(); // Render with an interaction - React.unstable_interactions.track('some event', eventTime, () => { + InteractionTracking.unstable_track('some event', eventTime, () => { rendered.update(
); }); diff --git a/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js index 49e6d6397f1a0..3333c0225286e 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = __DEV__; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = false; +export const enableInteractionTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js b/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js index 907efd059e6a3..982ecfc01a1ab 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = false; +export const enableInteractionTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 2915c31bfef46..414fb60566a6c 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -26,7 +26,7 @@ export const { export const enableUserTimingAPI = __DEV__; export const warnAboutLegacyContextAPI = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = false; +export const enableInteractionTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index dfcf41a618d29..e9891d89c4f49 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -21,7 +21,7 @@ export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = false; +export const enableInteractionTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.persistent.js b/packages/shared/forks/ReactFeatureFlags.persistent.js index ada769a931b65..59189ef85de7b 100644 --- a/packages/shared/forks/ReactFeatureFlags.persistent.js +++ b/packages/shared/forks/ReactFeatureFlags.persistent.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = false; +export const enableInteractionTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { From f889734c56f8588963d6696f62b79597af90c088 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Fri, 31 Aug 2018 10:16:53 -0700 Subject: [PATCH 08/12] Merged interaction-tracking package into react-scheduler React UMD bundles inlines the new react-scheduler package and exposes the API via the SECRET_INTERNALS object. UMD bundles of e.g. ReactDOM access the API this way. This avoids breaking backwards compat for UMD bundles (since it avoids requiring a new + + + + + + + diff --git a/fixtures/unstable-async/suspense/package.json b/fixtures/unstable-async/suspense/package.json index e2364a2c63965..1b6f96186692d 100644 --- a/fixtures/unstable-async/suspense/package.json +++ b/fixtures/unstable-async/suspense/package.json @@ -10,10 +10,10 @@ "dependencies": { "clipboard": "^1.7.1", "github-fork-ribbon-css": "^0.2.1", - "interaction-tracking": "../../../build/node_modules/interaction-tracking", "react": "../../../build/node_modules/react", "react-dom": "../../../build/node_modules/react-dom", "react-draggable": "^3.0.5", + "react-scheduler": "../../../build/node_modules/react-scheduler", "simple-cache-provider": "../../../build/node_modules/simple-cache-provider" }, "scripts": { diff --git a/fixtures/unstable-async/suspense/src/components/App.js b/fixtures/unstable-async/suspense/src/components/App.js index 77f7a7e3c606f..f40506d51afd4 100644 --- a/fixtures/unstable-async/suspense/src/components/App.js +++ b/fixtures/unstable-async/suspense/src/components/App.js @@ -2,7 +2,7 @@ import React, {Placeholder, PureComponent} from 'react'; import { unstable_track as track, unstable_wrap as wrap, -} from 'interaction-tracking'; +} from 'react-scheduler/tracking'; import {createResource} from 'simple-cache-provider'; import {cache} from '../cache'; import Spinner from './Spinner'; diff --git a/fixtures/unstable-async/suspense/src/index.js b/fixtures/unstable-async/suspense/src/index.js index eda669478a1b7..1a6a82feb14ad 100644 --- a/fixtures/unstable-async/suspense/src/index.js +++ b/fixtures/unstable-async/suspense/src/index.js @@ -1,6 +1,6 @@ import React, {Fragment, PureComponent} from 'react'; import {unstable_createRoot, render} from 'react-dom'; -import {unstable_track as track} from 'interaction-tracking'; +import {unstable_track as track} from 'react-scheduler/tracking'; import {cache} from './cache'; import { setFakeRequestTime, diff --git a/fixtures/unstable-async/suspense/yarn.lock b/fixtures/unstable-async/suspense/yarn.lock index 08591ca46dcff..5b2ffc6706c04 100644 --- a/fixtures/unstable-async/suspense/yarn.lock +++ b/fixtures/unstable-async/suspense/yarn.lock @@ -3482,13 +3482,6 @@ inquirer@3.3.0, inquirer@^3.0.6: strip-ansi "^4.0.0" through "^2.3.6" -interaction-tracking@../../../build/node_modules/interaction-tracking: - version "16.4.3-alpha.0" - -interaction-tracking@16.4.3-alpha.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/interaction-tracking/-/interaction-tracking-0.0.1.tgz#08877accb2ec479f2af83d7de7a9ae60b80e8dc5" - internal-ip@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" @@ -5739,6 +5732,7 @@ react-dom@../../../build/node_modules/react-dom: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" + react-scheduler "^0.1.0-alpha-1" react-draggable@^3.0.5: version "3.0.5" @@ -5751,6 +5745,15 @@ react-error-overlay@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4" +react-scheduler@../../../build/node_modules/react-scheduler: + version "0.1.0-alpha-1" + dependencies: + object-assign "^4.1.1" + +react-scheduler@^0.1.0-alpha-1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/react-scheduler/-/react-scheduler-0.1.0.tgz#d16c0ee90d2895ff1941e0d681293dbe4f4b4f38" + react-scripts@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-1.1.4.tgz#d5c230e707918d6dd2d06f303b10f5222d017c88" @@ -5799,10 +5802,10 @@ react-scripts@^1.1.4: react@../../../build/node_modules/react: version "16.4.3-alpha.0" dependencies: - interaction-tracking "16.4.3-alpha.0" loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" + react-scheduler "^0.1.0-alpha-1" read-pkg-up@^1.0.1: version "1.0.1" diff --git a/packages/interaction-tracking/README.md b/packages/interaction-tracking/README.md deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/packages/interaction-tracking/npm/index.js b/packages/interaction-tracking/npm/index.js deleted file mode 100644 index 6f7a570506f7d..0000000000000 --- a/packages/interaction-tracking/npm/index.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -if (process.env.NODE_ENV === 'production') { - module.exports = require('./cjs/interaction-tracking.production.min.js'); -} else { - module.exports = require('./cjs/interaction-tracking.development.js'); -} diff --git a/packages/interaction-tracking/npm/subscriptions.js b/packages/interaction-tracking/npm/subscriptions.js deleted file mode 100644 index b675e27f36784..0000000000000 --- a/packages/interaction-tracking/npm/subscriptions.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -if (process.env.NODE_ENV === 'production') { - module.exports = require('./cjs/interaction-tracking-subscriptions.production.min.js'); -} else { - module.exports = require('./cjs/interaction-tracking-subscriptions.development.js'); -} diff --git a/packages/interaction-tracking/package.json b/packages/interaction-tracking/package.json deleted file mode 100644 index 0513e6fc76c5f..0000000000000 --- a/packages/interaction-tracking/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "interaction-tracking", - "description": "utility for tracking interaction events", - "version": "16.4.3-alpha.0", - "license": "MIT", - "files": [ - "LICENSE", - "README.md", - "index.js", - "subscriptions.js", - "cjs/", - "umd/" - ], - "keywords": [ - "interaction", - "tracking", - "react" - ], - "repository": "https://github.com/facebook/react", - "bugs": { - "url": "https://github.com/facebook/react/issues" - }, - "homepage": "https://reactjs.org/" -} diff --git a/packages/react-art/package.json b/packages/react-art/package.json index a33b1e4823372..8b5818de97151 100644 --- a/packages/react-art/package.json +++ b/packages/react-art/package.json @@ -22,7 +22,8 @@ "create-react-class": "^15.6.2", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "prop-types": "^15.6.2", + "react-scheduler": "^0.1.0-alpha-1" }, "peerDependencies": { "react": "^16.0.0" diff --git a/packages/react-art/src/ReactARTHostConfig.js b/packages/react-art/src/ReactARTHostConfig.js index e6ce862766fb0..a904477cc33c7 100644 --- a/packages/react-art/src/ReactARTHostConfig.js +++ b/packages/react-art/src/ReactARTHostConfig.js @@ -5,7 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import * as ReactScheduler from 'shared/ReactScheduler'; +export { + unstable_now as now, + unstable_scheduleWork as scheduleDeferredCallback, + unstable_cancelScheduledWork as cancelDeferredCallback, +} from 'react-scheduler'; import Transform from 'art/core/transform'; import Mode from 'art/modes/current'; import invariant from 'shared/invariant'; @@ -329,9 +333,6 @@ export function getChildHostContext() { return NO_CONTEXT; } -export const scheduleDeferredCallback = ReactScheduler.scheduleWork; -export const cancelDeferredCallback = ReactScheduler.cancelScheduledWork; - export const scheduleTimeout = setTimeout; export const cancelTimeout = clearTimeout; export const noTimeout = -1; @@ -342,8 +343,6 @@ export function shouldSetTextContent(type, props) { ); } -export const now = ReactScheduler.now; - // The ART renderer is secondary to the React DOM renderer. export const isPrimaryRenderer = false; diff --git a/packages/react-dom/package.json b/packages/react-dom/package.json index 9f89e24c767da..4f587172cb975 100644 --- a/packages/react-dom/package.json +++ b/packages/react-dom/package.json @@ -15,7 +15,8 @@ "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "prop-types": "^15.6.2", + "react-scheduler": "^0.1.0-alpha-1" }, "peerDependencies": { "react": "^16.0.0" diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index 4d74569760ca1..8a5c0578a8229 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -61,10 +61,10 @@ export type TimeoutHandle = TimeoutID; export type NoTimeout = -1; export { - now, - scheduleWork as scheduleDeferredCallback, - cancelScheduledWork as cancelDeferredCallback, -} from 'shared/ReactScheduler'; + unstable_now as now, + unstable_scheduleWork as scheduleDeferredCallback, + unstable_cancelScheduledWork as cancelDeferredCallback, +} from 'react-scheduler'; let SUPPRESS_HYDRATION_WARNING; if (__DEV__) { diff --git a/packages/react-native-renderer/package.json b/packages/react-native-renderer/package.json index e50924169b848..5aa9a77937a34 100644 --- a/packages/react-native-renderer/package.json +++ b/packages/react-native-renderer/package.json @@ -5,7 +5,8 @@ "repository": "facebook/react", "dependencies": { "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "prop-types": "^15.6.2", + "react-scheduler": "^0.1.0-alpha-1" }, "peerDependencies": { "react": "^16.0.0" diff --git a/packages/react-reconciler/package.json b/packages/react-reconciler/package.json index c6b033176a0fb..66c7dc53a9796 100644 --- a/packages/react-reconciler/package.json +++ b/packages/react-reconciler/package.json @@ -27,7 +27,8 @@ "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "prop-types": "^15.6.2", + "react-scheduler": "^0.1.0-alpha-1" }, "browserify": { "transform": [ diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.js b/packages/react-reconciler/src/ReactFiberCommitWork.js index 11317e99cf7b1..e677c62725ed8 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.js @@ -20,7 +20,7 @@ import type {ExpirationTime} from './ReactFiberExpirationTime'; import type {CapturedValue, CapturedError} from './ReactCapturedValue'; import { - enableInteractionTracking, + enableSchedulerTracking, enableProfilerTimer, enableSuspense, } from 'shared/ReactFeatureFlags'; @@ -845,7 +845,7 @@ function commitWork( if (enableProfilerTimer) { const onRender = finishedWork.memoizedProps.onRender; - if (enableInteractionTracking) { + if (enableSchedulerTracking) { onRender( finishedWork.memoizedProps.id, current === null ? 'mount' : 'update', diff --git a/packages/react-reconciler/src/ReactFiberRoot.js b/packages/react-reconciler/src/ReactFiberRoot.js index 603748842ca1d..427e4ac8704ab 100644 --- a/packages/react-reconciler/src/ReactFiberRoot.js +++ b/packages/react-reconciler/src/ReactFiberRoot.js @@ -10,19 +10,13 @@ import type {Fiber} from './ReactFiber'; import type {ExpirationTime} from './ReactFiberExpirationTime'; import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig'; -import type {Interaction} from 'interaction-tracking/src/InteractionTracking'; +import type {Interaction} from 'react-scheduler/src/Tracking'; import {noTimeout} from './ReactFiberHostConfig'; import {createHostRootFiber} from './ReactFiber'; import {NoWork} from './ReactFiberExpirationTime'; -import ReactSharedInternals from 'shared/ReactSharedInternals'; -import {enableInteractionTracking} from 'shared/ReactFeatureFlags'; - -// Access the interaction-tracking API from React's internal re-export. -// This will be a re-export of the interaction-tracking package for CJS bundles, -// And an embedded version for UMD bundles. -// This is being done so that we don't break backwards compat for existing UMD apps. -const {getThreadID} = ReactSharedInternals.InteractionTracking; +import {enableSchedulerTracking} from 'shared/ReactFeatureFlags'; +import {unstable_getThreadID} from 'react-scheduler/tracking'; // TODO: This should be lifted into the renderer. export type Batch = { @@ -88,7 +82,7 @@ type BaseFiberRootProperties = {| // The following attributes are only used by interaction tracking builds. // They enable interactions to be associated with their async work, // And expose interaction metadata to the React DevTools Profiler plugin. -// Note that these attributes are only defined when the enableInteractionTracking flag is enabled. +// Note that these attributes are only defined when the enableSchedulerTracking flag is enabled. type ProfilingOnlyFiberRootProperties = {| interactionThreadID: number, memoizedInteractions: Set, @@ -97,9 +91,9 @@ type ProfilingOnlyFiberRootProperties = {| // Exported FiberRoot type includes all properties, // To avoid requiring potentially error-prone :any casts throughout the project. -// Profiling properties are only safe to access in profiling builds (when enableInteractionTracking is true). +// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracking is true). // The types are defined separately within this file to ensure they stay in sync. -// (We don't have to use an inline :any cast when enableInteractionTracking is disabled.) +// (We don't have to use an inline :any cast when enableSchedulerTracking is disabled.) export type FiberRoot = { ...BaseFiberRootProperties, ...ProfilingOnlyFiberRootProperties, @@ -115,7 +109,7 @@ export function createFiberRoot( const uninitializedFiber = createHostRootFiber(isAsync); let root; - if (enableInteractionTracking) { + if (enableSchedulerTracking) { root = ({ current: uninitializedFiber, containerInfo: containerInfo, @@ -140,7 +134,7 @@ export function createFiberRoot( firstBatch: null, nextScheduledRoot: null, - interactionThreadID: getThreadID(), + interactionThreadID: unstable_getThreadID(), memoizedInteractions: new Set(), pendingInteractionMap: new Map(), }: FiberRoot); @@ -174,8 +168,8 @@ export function createFiberRoot( uninitializedFiber.stateNode = root; // The reason for the way the Flow types are structured in this file, - // Is to avoid needing :any casts everywhere interaction-tracking fields are used. - // Unfortunately that requires an :any cast for non-interaction-tracking capable builds. + // Is to avoid needing :any casts everywhere interaction tracking fields are used. + // Unfortunately that requires an :any cast for non-interaction tracking capable builds. // $FlowFixMe Remove this :any cast and replace it with something better. return ((root: any): FiberRoot); } diff --git a/packages/react-reconciler/src/ReactFiberScheduler.js b/packages/react-reconciler/src/ReactFiberScheduler.js index 9c1e959fd87c6..dd27947cc42bf 100644 --- a/packages/react-reconciler/src/ReactFiberScheduler.js +++ b/packages/react-reconciler/src/ReactFiberScheduler.js @@ -10,8 +10,16 @@ import type {Fiber} from './ReactFiber'; import type {Batch, FiberRoot} from './ReactFiberRoot'; import type {ExpirationTime} from './ReactFiberExpirationTime'; -import type {Interaction} from 'interaction-tracking/src/InteractionTracking'; +import type { + Interaction, + InteractionsRef, + SubscriberRef, +} from 'react-scheduler/src/Tracking'; +import { + __getInteractionsRef, + __getSubscriberRef, +} from 'react-scheduler/tracking'; import { invokeGuardedCallback, hasCaughtError, @@ -43,7 +51,7 @@ import { HostPortal, } from 'shared/ReactWorkTags'; import { - enableInteractionTracking, + enableSchedulerTracking, enableProfilerTimer, enableUserTimingAPI, replayFailedUnitOfWorkWithInvokeGuardedCallback, @@ -159,13 +167,14 @@ export type Thenable = { then(resolve: () => mixed, reject?: () => mixed): mixed, }; -const {InteractionTracking, ReactCurrentOwner} = ReactSharedInternals; +const {ReactCurrentOwner} = ReactSharedInternals; -// Access the interaction-tracking API from React's internal re-export. -// This will be a re-export of the interaction-tracking package for CJS bundles, -// And an embedded version for UMD bundles. -// This is being done so that we don't break backwards compat for existing UMD apps. -const {__interactionsRef, __subscriberRef} = InteractionTracking; +let interactionsRef: InteractionsRef = (null: any); +let subscriberRef: SubscriberRef = (null: any); +if (enableSchedulerTracking) { + interactionsRef = __getInteractionsRef(); + subscriberRef = __getSubscriberRef(); +} let didWarnAboutStateTransition; let didWarnSetStateChildContext; @@ -558,14 +567,14 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void { markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit); let prevInteractions: Set = (null: any); - let committedInteractions: Array = enableInteractionTracking + let committedInteractions: Array = enableSchedulerTracking ? [] : (null: any); - if (enableInteractionTracking) { + if (enableSchedulerTracking) { // Restore any pending interactions at this point, // So that cascading work triggered during the render phase will be accounted for. - prevInteractions = __interactionsRef.current; - __interactionsRef.current = root.memoizedInteractions; + prevInteractions = interactionsRef.current; + interactionsRef.current = root.memoizedInteractions; // We are potentially finished with the current batch of interactions. // So we should clear them out of the pending interaction map. @@ -759,13 +768,13 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void { } onCommit(root, earliestRemainingTimeAfterCommit); - if (enableInteractionTracking) { - __interactionsRef.current = prevInteractions; + if (enableSchedulerTracking) { + interactionsRef.current = prevInteractions; let subscriber; try { - subscriber = __subscriberRef.current; + subscriber = subscriberRef.current; if (subscriber !== null && root.memoizedInteractions.size > 0) { const threadID = computeThreadID( committedExpirationTime, @@ -1167,11 +1176,11 @@ function renderRoot( const expirationTime = root.nextExpirationTimeToWorkOn; let prevInteractions: Set = (null: any); - if (enableInteractionTracking) { + if (enableSchedulerTracking) { // We're about to start new tracked work. // Restore pending interactions so cascading work triggered during the render phase will be accounted for. - prevInteractions = __interactionsRef.current; - __interactionsRef.current = root.memoizedInteractions; + prevInteractions = interactionsRef.current; + interactionsRef.current = root.memoizedInteractions; } // Check if we're starting from a fresh stack, or if we're resuming from @@ -1192,7 +1201,7 @@ function renderRoot( ); root.pendingCommitExpirationTime = NoWork; - if (enableInteractionTracking) { + if (enableSchedulerTracking) { // Determine which interactions this batch of work currently includes, // So that we can accurately attribute time spent working on it, // And so that cascading work triggered during the render phase will be associated with it. @@ -1214,7 +1223,7 @@ function renderRoot( root.memoizedInteractions = interactions; if (interactions.size > 0) { - const subscriber = __subscriberRef.current; + const subscriber = subscriberRef.current; if (subscriber !== null) { const threadID = computeThreadID( expirationTime, @@ -1223,7 +1232,7 @@ function renderRoot( try { subscriber.onWorkStarted(interactions, threadID); } catch (error) { - // Work thrown by a interaction-tracking subscriber should be rethrown, + // Work thrown by an interaction tracking subscriber should be rethrown, // But only once it's safe (to avoid leaveing the scheduler in an invalid state). // Store the error for now and we'll re-throw in finishRendering(). if (!hasUnhandledError) { @@ -1297,9 +1306,9 @@ function renderRoot( break; } while (true); - if (enableInteractionTracking) { + if (enableSchedulerTracking) { // Tracked work is done for now; restore the previous interactions. - __interactionsRef.current = prevInteractions; + interactionsRef.current = prevInteractions; } // We're done performing work. Time to clean up. @@ -1606,15 +1615,15 @@ function retrySuspendedRoot( scheduleWorkToRoot(fiber, retryTime); const rootExpirationTime = root.expirationTime; if (rootExpirationTime !== NoWork) { - if (enableInteractionTracking) { + if (enableSchedulerTracking) { // Restore previous interactions so that new work is associated with them. - let prevInteractions = __interactionsRef.current; - __interactionsRef.current = root.memoizedInteractions; + let prevInteractions = interactionsRef.current; + interactionsRef.current = root.memoizedInteractions; // Because suspense timeouts do not decrement the interaction count, // Continued suspense work should also not increment the count. storeInteractionsForExpirationTime(root, rootExpirationTime, false); requestWork(root, rootExpirationTime); - __interactionsRef.current = prevInteractions; + interactionsRef.current = prevInteractions; } else { requestWork(root, rootExpirationTime); } @@ -1677,11 +1686,11 @@ function storeInteractionsForExpirationTime( expirationTime: ExpirationTime, updateInteractionCounts: boolean, ): void { - if (!enableInteractionTracking) { + if (!enableSchedulerTracking) { return; } - const interactions = __interactionsRef.current; + const interactions = interactionsRef.current; if (interactions.size > 0) { const pendingInteractions = root.pendingInteractionMap.get(expirationTime); if (pendingInteractions != null) { @@ -1704,7 +1713,7 @@ function storeInteractionsForExpirationTime( } } - const subscriber = __subscriberRef.current; + const subscriber = subscriberRef.current; if (subscriber !== null) { const threadID = computeThreadID( expirationTime, @@ -1736,7 +1745,7 @@ function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) { return; } - if (enableInteractionTracking) { + if (enableSchedulerTracking) { storeInteractionsForExpirationTime(root, expirationTime, true); } @@ -1927,7 +1936,7 @@ function onTimeout(root, finishedWork, suspendedExpirationTime) { recomputeCurrentRendererTime(); currentSchedulerTime = currentRendererTime; - if (enableInteractionTracking) { + if (enableSchedulerTracking) { // Don't update pending interaction counts for suspense timeouts, // Because we know we still need to do more work in this case. suspenseDidTimeout = true; diff --git a/packages/react-scheduler/npm/tracking-subscriptions.js b/packages/react-scheduler/npm/tracking-subscriptions.js new file mode 100644 index 0000000000000..f32e47d0429e4 --- /dev/null +++ b/packages/react-scheduler/npm/tracking-subscriptions.js @@ -0,0 +1,7 @@ +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/react-scheduler-tracking-subscriptions.production.min.js'); +} else { + module.exports = require('./cjs/react-scheduler-tracking-subscriptions.development.js'); +} diff --git a/packages/react-scheduler/npm/tracking.js b/packages/react-scheduler/npm/tracking.js new file mode 100644 index 0000000000000..997edc5a81389 --- /dev/null +++ b/packages/react-scheduler/npm/tracking.js @@ -0,0 +1,7 @@ +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/react-scheduler-tracking.production.min.js'); +} else { + module.exports = require('./cjs/react-scheduler-tracking.development.js'); +} diff --git a/packages/react-scheduler/package.json b/packages/react-scheduler/package.json index 633f48859bcd6..ac1a170ebed2e 100644 --- a/packages/react-scheduler/package.json +++ b/packages/react-scheduler/package.json @@ -20,6 +20,8 @@ "LICENSE", "README.md", "index.js", + "tracking.js", + "tracking-subscriptions.js", "cjs/", "umd/" ] diff --git a/packages/react-scheduler/src/ReactScheduler.js b/packages/react-scheduler/src/ReactScheduler.js index 550d064a9b82d..aff461781c852 100644 --- a/packages/react-scheduler/src/ReactScheduler.js +++ b/packages/react-scheduler/src/ReactScheduler.js @@ -465,4 +465,8 @@ if (!canUseDOM) { }; } -export {now, scheduleWork, cancelScheduledWork}; +export { + now as unstable_now, + scheduleWork as unstable_scheduleWork, + cancelScheduledWork as unstable_cancelScheduledWork, +}; diff --git a/packages/interaction-tracking/src/InteractionTracking.js b/packages/react-scheduler/src/Tracking.js similarity index 94% rename from packages/interaction-tracking/src/InteractionTracking.js rename to packages/react-scheduler/src/Tracking.js index 6b00118bb5749..6678ad3cc9a1d 100644 --- a/packages/interaction-tracking/src/InteractionTracking.js +++ b/packages/react-scheduler/src/Tracking.js @@ -7,7 +7,7 @@ * @flow */ -import {enableInteractionTracking} from 'shared/ReactFeatureFlags'; +import {enableSchedulerTracking} from 'shared/ReactFeatureFlags'; export type Interaction = {| __count: number, @@ -70,7 +70,7 @@ let interactionsRef: InteractionsRef = (null: any); // Listener(s) to notify when interactions begin and end. let subscriberRef: SubscriberRef = (null: any); -if (enableInteractionTracking) { +if (enableSchedulerTracking) { interactionsRef = { current: new Set(), }; @@ -81,10 +81,16 @@ if (enableInteractionTracking) { // These values are exported for libraries with advanced use cases (i.e. React). // They should not typically be accessed directly. -export {interactionsRef as __interactionsRef, subscriberRef as __subscriberRef}; +export function __getInteractionsRef(): InteractionsRef { + return interactionsRef; +} + +export function __getSubscriberRef(): SubscriberRef { + return subscriberRef; +} export function unstable_clear(callback: Function): any { - if (!enableInteractionTracking) { + if (!enableSchedulerTracking) { return callback(); } @@ -99,7 +105,7 @@ export function unstable_clear(callback: Function): any { } export function unstable_getCurrent(): Set | null { - if (!enableInteractionTracking) { + if (!enableSchedulerTracking) { return null; } else { return interactionsRef.current; @@ -116,7 +122,7 @@ export function unstable_track( callback: Function, threadID: number = DEFAULT_THREAD_ID, ): any { - if (!enableInteractionTracking) { + if (!enableSchedulerTracking) { return callback(); } @@ -178,7 +184,7 @@ export function unstable_wrap( callback: Function, threadID: number = DEFAULT_THREAD_ID, ): Function { - if (!enableInteractionTracking) { + if (!enableSchedulerTracking) { return callback; } diff --git a/packages/interaction-tracking/src/InteractionTrackingSubscriptions.js b/packages/react-scheduler/src/TrackingSubscriptions.js similarity index 89% rename from packages/interaction-tracking/src/InteractionTrackingSubscriptions.js rename to packages/react-scheduler/src/TrackingSubscriptions.js index 7ec33232a57f1..539213af2fdcc 100644 --- a/packages/interaction-tracking/src/InteractionTrackingSubscriptions.js +++ b/packages/react-scheduler/src/TrackingSubscriptions.js @@ -7,24 +7,24 @@ * @flow */ -import type {Interaction, Subscriber} from './InteractionTracking'; +import type {Interaction, Subscriber} from './Tracking'; -import {enableInteractionTracking} from 'shared/ReactFeatureFlags'; -import {__subscriberRef} from 'interaction-tracking'; +import {enableSchedulerTracking} from 'shared/ReactFeatureFlags'; +import {__getSubscriberRef} from 'react-scheduler/tracking'; let subscribers: Set = (null: any); -if (enableInteractionTracking) { +if (enableSchedulerTracking) { subscribers = new Set(); } export function unstable_subscribe(subscriber: Subscriber): void { - if (enableInteractionTracking) { + if (enableSchedulerTracking) { subscribers.add(subscriber); } } export function unstable_unsubscribe(subscriber: Subscriber): void { - if (enableInteractionTracking) { + if (enableSchedulerTracking) { subscribers.delete(subscriber); } } @@ -155,8 +155,9 @@ function onWorkCanceled( } } -if (enableInteractionTracking) { - __subscriberRef.current = { +if (enableSchedulerTracking) { + const subscriberRef = __getSubscriberRef(); + subscriberRef.current = { onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, diff --git a/packages/react-scheduler/src/__tests__/ReactScheduler-test.js b/packages/react-scheduler/src/__tests__/ReactScheduler-test.js index a1070dbff67e6..3577daf1877c3 100644 --- a/packages/react-scheduler/src/__tests__/ReactScheduler-test.js +++ b/packages/react-scheduler/src/__tests__/ReactScheduler-test.js @@ -99,7 +99,7 @@ describe('ReactScheduler', () => { describe('scheduleWork', () => { it('calls the callback within the frame when not blocked', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const cb = jest.fn(); scheduleWork(cb); advanceOneFrame({timeLeftInFrame: 15}); @@ -111,7 +111,7 @@ describe('ReactScheduler', () => { describe('with multiple callbacks', () => { it('accepts multiple callbacks and calls within frame when not blocked', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => callbackLog.push('A')); const callbackB = jest.fn(() => callbackLog.push('B')); @@ -137,7 +137,7 @@ describe('ReactScheduler', () => { }); it("accepts callbacks betweeen animationFrame and postMessage and doesn't stall", () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => callbackLog.push('A')); const callbackB = jest.fn(() => callbackLog.push('B')); @@ -167,7 +167,7 @@ describe('ReactScheduler', () => { 'schedules callbacks in correct order and' + 'keeps calling them if there is time', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => { callbackLog.push('A'); @@ -194,7 +194,7 @@ describe('ReactScheduler', () => { ); it('schedules callbacks in correct order when callbacks have many nested scheduleWork calls', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => { callbackLog.push('A'); @@ -229,7 +229,7 @@ describe('ReactScheduler', () => { }); it('schedules callbacks in correct order when they use scheduleWork to schedule themselves', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; let callbackAIterations = 0; const callbackA = jest.fn(() => { @@ -260,7 +260,7 @@ describe('ReactScheduler', () => { describe('when there is no more time left in the frame', () => { it('calls any callback which has timed out, waits for others', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; startOfLatestFrame = 1000000000000; currentTime = startOfLatestFrame - 10; const callbackLog = []; @@ -295,7 +295,7 @@ describe('ReactScheduler', () => { describe('when there is some time left in the frame', () => { it('calls timed out callbacks and then any more pending callbacks, defers others if time runs out', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; startOfLatestFrame = 1000000000000; currentTime = startOfLatestFrame - 10; const callbackLog = []; @@ -343,7 +343,10 @@ describe('ReactScheduler', () => { describe('cancelScheduledWork', () => { it('cancels the scheduled callback', () => { - const {scheduleWork, cancelScheduledWork} = ReactScheduler; + const { + unstable_scheduleWork: scheduleWork, + unstable_cancelScheduledWork: cancelScheduledWork, + } = ReactScheduler; const cb = jest.fn(); const callbackId = scheduleWork(cb); expect(cb).toHaveBeenCalledTimes(0); @@ -354,7 +357,10 @@ describe('ReactScheduler', () => { describe('with multiple callbacks', () => { it('when called more than once', () => { - const {scheduleWork, cancelScheduledWork} = ReactScheduler; + const { + unstable_scheduleWork: scheduleWork, + unstable_cancelScheduledWork: cancelScheduledWork, + } = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => callbackLog.push('A')); const callbackB = jest.fn(() => callbackLog.push('B')); @@ -375,7 +381,10 @@ describe('ReactScheduler', () => { }); it('when one callback cancels the next one', () => { - const {scheduleWork, cancelScheduledWork} = ReactScheduler; + const { + unstable_scheduleWork: scheduleWork, + unstable_cancelScheduledWork: cancelScheduledWork, + } = ReactScheduler; const callbackLog = []; let callbackBId; const callbackA = jest.fn(() => { @@ -412,7 +421,7 @@ describe('ReactScheduler', () => { * */ it('still calls all callbacks within same frame', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => callbackLog.push('A')); const callbackB = jest.fn(() => { @@ -458,7 +467,7 @@ describe('ReactScheduler', () => { * */ it('and with some timed out callbacks, still calls all callbacks within same frame', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => { callbackLog.push('A'); @@ -504,7 +513,7 @@ describe('ReactScheduler', () => { * */ it('still calls all callbacks within same frame', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => { callbackLog.push('A'); @@ -565,7 +574,7 @@ describe('ReactScheduler', () => { * */ it('and with all timed out callbacks, still calls all callbacks within same frame', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; const callbackLog = []; const callbackA = jest.fn(() => { callbackLog.push('A'); @@ -646,7 +655,7 @@ describe('ReactScheduler', () => { * */ it('still calls all callbacks within same frame', () => { - const {scheduleWork} = ReactScheduler; + const {unstable_scheduleWork: scheduleWork} = ReactScheduler; startOfLatestFrame = 1000000000000; currentTime = startOfLatestFrame - 10; catchPostMessageErrors = true; diff --git a/packages/interaction-tracking/src/__tests__/InteractionTracking-test.internal.js b/packages/react-scheduler/src/__tests__/Tracking-test.internal.js similarity index 55% rename from packages/interaction-tracking/src/__tests__/InteractionTracking-test.internal.js rename to packages/react-scheduler/src/__tests__/Tracking-test.internal.js index 16dae7a8d0037..f64fce3ecda85 100644 --- a/packages/interaction-tracking/src/__tests__/InteractionTracking-test.internal.js +++ b/packages/react-scheduler/src/__tests__/Tracking-test.internal.js @@ -8,14 +8,14 @@ */ 'use strict'; -describe('InteractionTracking', () => { - let InteractionTracking; +describe('SchedulerTracking', () => { + let SchedulerTracking; let ReactFeatureFlags; let advanceTimeBy; let currentTime; - function loadModules({enableInteractionTracking}) { + function loadModules({enableSchedulerTracking}) { jest.resetModules(); jest.useFakeTimers(); @@ -27,36 +27,36 @@ describe('InteractionTracking', () => { }; ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.enableInteractionTracking = enableInteractionTracking; + ReactFeatureFlags.enableSchedulerTracking = enableSchedulerTracking; - InteractionTracking = require('interaction-tracking'); + SchedulerTracking = require('react-scheduler/tracking'); } - describe('enableInteractionTracking enabled', () => { - beforeEach(() => loadModules({enableInteractionTracking: true})); + describe('enableSchedulerTracking enabled', () => { + beforeEach(() => loadModules({enableSchedulerTracking: true})); it('should return the value of a tracked function', () => { expect( - InteractionTracking.unstable_track('arbitrary', currentTime, () => 123), + SchedulerTracking.unstable_track('arbitrary', currentTime, () => 123), ).toBe(123); }); it('should return the value of a clear function', () => { - expect(InteractionTracking.unstable_clear(() => 123)).toBe(123); + expect(SchedulerTracking.unstable_clear(() => 123)).toBe(123); }); it('should return the value of a wrapped function', () => { let wrapped; - InteractionTracking.unstable_track('arbitrary', currentTime, () => { - wrapped = InteractionTracking.unstable_wrap(() => 123); + SchedulerTracking.unstable_track('arbitrary', currentTime, () => { + wrapped = SchedulerTracking.unstable_wrap(() => 123); }); expect(wrapped()).toBe(123); }); it('should pass arguments through to a wrapped function', done => { let wrapped; - InteractionTracking.unstable_track('arbitrary', currentTime, () => { - wrapped = InteractionTracking.unstable_wrap((param1, param2) => { + SchedulerTracking.unstable_track('arbitrary', currentTime, () => { + wrapped = SchedulerTracking.unstable_wrap((param1, param2) => { expect(param1).toBe('foo'); expect(param2).toBe('bar'); done(); @@ -66,16 +66,14 @@ describe('InteractionTracking', () => { }); it('should return an empty set when outside of a tracked event', () => { - expect( - InteractionTracking.unstable_getCurrent(), - ).toContainNoInteractions(); + expect(SchedulerTracking.unstable_getCurrent()).toContainNoInteractions(); }); it('should report the tracked interaction from within the track callback', done => { advanceTimeBy(100); - InteractionTracking.unstable_track('some event', currentTime, () => { - const interactions = InteractionTracking.unstable_getCurrent(); + SchedulerTracking.unstable_track('some event', currentTime, () => { + const interactions = SchedulerTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'some event', timestamp: 100}, ]); @@ -88,7 +86,7 @@ describe('InteractionTracking', () => { let wrappedIndirection; function indirection() { - const interactions = InteractionTracking.unstable_getCurrent(); + const interactions = SchedulerTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'some event', timestamp: 100}, ]); @@ -98,8 +96,8 @@ describe('InteractionTracking', () => { advanceTimeBy(100); - InteractionTracking.unstable_track('some event', currentTime, () => { - wrappedIndirection = InteractionTracking.unstable_wrap(indirection); + SchedulerTracking.unstable_track('some event', currentTime, () => { + wrappedIndirection = SchedulerTracking.unstable_wrap(indirection); }); advanceTimeBy(50); @@ -110,26 +108,26 @@ describe('InteractionTracking', () => { it('should clear the interaction stack for tracked callbacks', () => { let innerTestReached = false; - InteractionTracking.unstable_track('outer event', currentTime, () => { - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ + SchedulerTracking.unstable_track('outer event', currentTime, () => { + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); - InteractionTracking.unstable_clear(() => { - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + SchedulerTracking.unstable_clear(() => { + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions( [], ); - InteractionTracking.unstable_track('inner event', currentTime, () => { - expect( - InteractionTracking.unstable_getCurrent(), - ).toMatchInteractions([{name: 'inner event'}]); + SchedulerTracking.unstable_track('inner event', currentTime, () => { + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions( + [{name: 'inner event'}], + ); innerTestReached = true; }); }); - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); }); @@ -142,31 +140,31 @@ describe('InteractionTracking', () => { let wrappedIndirection; const indirection = jest.fn(() => { - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); - InteractionTracking.unstable_clear(() => { - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( + SchedulerTracking.unstable_clear(() => { + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions( [], ); - InteractionTracking.unstable_track('inner event', currentTime, () => { - expect( - InteractionTracking.unstable_getCurrent(), - ).toMatchInteractions([{name: 'inner event'}]); + SchedulerTracking.unstable_track('inner event', currentTime, () => { + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions( + [{name: 'inner event'}], + ); innerTestReached = true; }); }); - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions([ + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ {name: 'outer event'}, ]); }); - InteractionTracking.unstable_track('outer event', currentTime, () => { - wrappedIndirection = InteractionTracking.unstable_wrap(indirection); + SchedulerTracking.unstable_track('outer event', currentTime, () => { + wrappedIndirection = SchedulerTracking.unstable_wrap(indirection); }); wrappedIndirection(); @@ -181,7 +179,7 @@ describe('InteractionTracking', () => { let outerIndirectionTracked = false; function innerIndirection() { - const interactions = InteractionTracking.unstable_getCurrent(); + const interactions = SchedulerTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, {name: 'inner event', timestamp: 150}, @@ -191,7 +189,7 @@ describe('InteractionTracking', () => { } function outerIndirection() { - const interactions = InteractionTracking.unstable_getCurrent(); + const interactions = SchedulerTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, ]); @@ -199,16 +197,16 @@ describe('InteractionTracking', () => { outerIndirectionTracked = true; } - InteractionTracking.unstable_track('outer event', currentTime, () => { + SchedulerTracking.unstable_track('outer event', currentTime, () => { // Verify the current tracked event - let interactions = InteractionTracking.unstable_getCurrent(); + let interactions = SchedulerTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, ]); advanceTimeBy(50); - const wrapperOuterIndirection = InteractionTracking.unstable_wrap( + const wrapperOuterIndirection = SchedulerTracking.unstable_wrap( outerIndirection, ); @@ -216,8 +214,8 @@ describe('InteractionTracking', () => { let innerEventTracked = false; // Verify that a nested event is properly tracked - InteractionTracking.unstable_track('inner event', currentTime, () => { - interactions = InteractionTracking.unstable_getCurrent(); + SchedulerTracking.unstable_track('inner event', currentTime, () => { + interactions = SchedulerTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, {name: 'inner event', timestamp: 150}, @@ -227,7 +225,7 @@ describe('InteractionTracking', () => { wrapperOuterIndirection(); expect(outerIndirectionTracked).toBe(true); - wrapperInnerIndirection = InteractionTracking.unstable_wrap( + wrapperInnerIndirection = SchedulerTracking.unstable_wrap( innerIndirection, ); @@ -237,7 +235,7 @@ describe('InteractionTracking', () => { expect(innerEventTracked).toBe(true); // Verify that the original event is restored - interactions = InteractionTracking.unstable_getCurrent(); + interactions = SchedulerTracking.unstable_getCurrent(); expect(interactions).toMatchInteractions([ {name: 'outer event', timestamp: 100}, ]); @@ -254,20 +252,16 @@ describe('InteractionTracking', () => { it('should reset state appropriately when an error occurs in a track callback', done => { advanceTimeBy(100); - InteractionTracking.unstable_track('outer event', currentTime, () => { + SchedulerTracking.unstable_track('outer event', currentTime, () => { expect(() => { - InteractionTracking.unstable_track( - 'inner event', - currentTime, - () => { - throw Error('intentional'); - }, - ); + SchedulerTracking.unstable_track('inner event', currentTime, () => { + throw Error('intentional'); + }); }).toThrow(); - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( - [{name: 'outer event', timestamp: 100}], - ); + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ + {name: 'outer event', timestamp: 100}, + ]); done(); }); @@ -276,20 +270,20 @@ describe('InteractionTracking', () => { it('should reset state appropriately when an error occurs in a wrapped callback', done => { advanceTimeBy(100); - InteractionTracking.unstable_track('outer event', currentTime, () => { + SchedulerTracking.unstable_track('outer event', currentTime, () => { let wrappedCallback; - InteractionTracking.unstable_track('inner event', currentTime, () => { - wrappedCallback = InteractionTracking.unstable_wrap(() => { + SchedulerTracking.unstable_track('inner event', currentTime, () => { + wrappedCallback = SchedulerTracking.unstable_wrap(() => { throw Error('intentional'); }); }); expect(wrappedCallback).toThrow(); - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( - [{name: 'outer event', timestamp: 100}], - ); + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ + {name: 'outer event', timestamp: 100}, + ]); done(); }); @@ -298,30 +292,30 @@ describe('InteractionTracking', () => { describe('advanced integration', () => { it('should return a unique threadID per request', () => { - expect(InteractionTracking.unstable_getThreadID()).not.toBe( - InteractionTracking.unstable_getThreadID(), + expect(SchedulerTracking.unstable_getThreadID()).not.toBe( + SchedulerTracking.unstable_getThreadID(), ); }); it('should expose the current set of interactions to be externally manipulated', () => { - InteractionTracking.unstable_track('outer event', currentTime, () => { - expect(InteractionTracking.__interactionsRef.current).toBe( - InteractionTracking.unstable_getCurrent(), + SchedulerTracking.unstable_track('outer event', currentTime, () => { + expect(SchedulerTracking.__getInteractionsRef().current).toBe( + SchedulerTracking.unstable_getCurrent(), ); - InteractionTracking.__interactionsRef.current = new Set([ + SchedulerTracking.__getInteractionsRef().current = new Set([ {name: 'override event'}, ]); - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( - [{name: 'override event'}], - ); + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ + {name: 'override event'}, + ]); }); }); it('should expose a subscriber ref to be externally manipulated', () => { - InteractionTracking.unstable_track('outer event', currentTime, () => { - expect(InteractionTracking.__subscriberRef).toEqual({ + SchedulerTracking.unstable_track('outer event', currentTime, () => { + expect(SchedulerTracking.__getSubscriberRef()).toEqual({ current: null, }); }); @@ -329,42 +323,42 @@ describe('InteractionTracking', () => { }); }); - describe('enableInteractionTracking disabled', () => { - beforeEach(() => loadModules({enableInteractionTracking: false})); + describe('enableSchedulerTracking disabled', () => { + beforeEach(() => loadModules({enableSchedulerTracking: false})); it('should return the value of a tracked function', () => { expect( - InteractionTracking.unstable_track('arbitrary', currentTime, () => 123), + SchedulerTracking.unstable_track('arbitrary', currentTime, () => 123), ).toBe(123); }); it('should return the value of a wrapped function', () => { let wrapped; - InteractionTracking.unstable_track('arbitrary', currentTime, () => { - wrapped = InteractionTracking.unstable_wrap(() => 123); + SchedulerTracking.unstable_track('arbitrary', currentTime, () => { + wrapped = SchedulerTracking.unstable_wrap(() => 123); }); expect(wrapped()).toBe(123); }); it('should return null for tracked interactions', () => { - expect(InteractionTracking.unstable_getCurrent()).toBe(null); + expect(SchedulerTracking.unstable_getCurrent()).toBe(null); }); it('should execute tracked callbacks', done => { - InteractionTracking.unstable_track('some event', currentTime, () => { - expect(InteractionTracking.unstable_getCurrent()).toBe(null); + SchedulerTracking.unstable_track('some event', currentTime, () => { + expect(SchedulerTracking.unstable_getCurrent()).toBe(null); done(); }); }); it('should return the value of a clear function', () => { - expect(InteractionTracking.unstable_clear(() => 123)).toBe(123); + expect(SchedulerTracking.unstable_clear(() => 123)).toBe(123); }); it('should execute wrapped callbacks', done => { - const wrappedCallback = InteractionTracking.unstable_wrap(() => { - expect(InteractionTracking.unstable_getCurrent()).toBe(null); + const wrappedCallback = SchedulerTracking.unstable_wrap(() => { + expect(SchedulerTracking.unstable_getCurrent()).toBe(null); done(); }); @@ -374,7 +368,7 @@ describe('InteractionTracking', () => { describe('advanced integration', () => { it('should not create unnecessary objects', () => { - expect(InteractionTracking.__interactionsRef).toBe(null); + expect(SchedulerTracking.__getInteractionsRef()).toBe(null); }); }); }); diff --git a/packages/interaction-tracking/src/__tests__/InteractionTracking-test.js b/packages/react-scheduler/src/__tests__/Tracking-test.js similarity index 58% rename from packages/interaction-tracking/src/__tests__/InteractionTracking-test.js rename to packages/react-scheduler/src/__tests__/Tracking-test.js index 1130882d96424..ae4638ea31926 100644 --- a/packages/interaction-tracking/src/__tests__/InteractionTracking-test.js +++ b/packages/react-scheduler/src/__tests__/Tracking-test.js @@ -8,41 +8,41 @@ */ 'use strict'; -describe('InteractionTracking', () => { - let InteractionTracking; +describe('Tracking', () => { + let SchedulerTracking; beforeEach(() => { jest.resetModules(); - InteractionTracking = require('interaction-tracking'); + SchedulerTracking = require('react-scheduler/tracking'); }); it('should return the value of a tracked function', () => { - expect(InteractionTracking.unstable_track('arbitrary', 0, () => 123)).toBe( + expect(SchedulerTracking.unstable_track('arbitrary', 0, () => 123)).toBe( 123, ); }); it('should return the value of a wrapped function', () => { let wrapped; - InteractionTracking.unstable_track('arbitrary', 0, () => { - wrapped = InteractionTracking.unstable_wrap(() => 123); + SchedulerTracking.unstable_track('arbitrary', 0, () => { + wrapped = SchedulerTracking.unstable_wrap(() => 123); }); expect(wrapped()).toBe(123); }); it('should execute tracked callbacks', done => { - InteractionTracking.unstable_track('some event', 0, () => { + SchedulerTracking.unstable_track('some event', 0, () => { done(); }); }); it('should return the value of a clear function', () => { - expect(InteractionTracking.unstable_clear(() => 123)).toBe(123); + expect(SchedulerTracking.unstable_clear(() => 123)).toBe(123); }); it('should execute wrapped callbacks', done => { - const wrappedCallback = InteractionTracking.unstable_wrap(() => { + const wrappedCallback = SchedulerTracking.unstable_wrap(() => { done(); }); diff --git a/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js b/packages/react-scheduler/src/__tests__/TrackingSubscriptions-test.internal.js similarity index 77% rename from packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js rename to packages/react-scheduler/src/__tests__/TrackingSubscriptions-test.internal.js index 17d8afa5cd8e7..db7b124f65721 100644 --- a/packages/interaction-tracking/src/__tests__/InteractionTrackingSubscriptions-test.internal.js +++ b/packages/react-scheduler/src/__tests__/TrackingSubscriptions-test.internal.js @@ -8,9 +8,9 @@ */ 'use strict'; -describe('InteractionTracking', () => { - let InteractionTracking; - let InteractionTrackingSubscriptions; +describe('SchedulerTrackingSubscriptions', () => { + let SchedulerTracking; + let SchedulerTrackingSubscriptions; let ReactFeatureFlags; let currentTime; @@ -34,17 +34,17 @@ describe('InteractionTracking', () => { const secondEvent = {id: 1, name: 'second', timestamp: 0}; const threadID = 123; - function loadModules({enableInteractionTracking}) { + function loadModules({enableSchedulerTracking}) { jest.resetModules(); jest.useFakeTimers(); currentTime = 0; ReactFeatureFlags = require('shared/ReactFeatureFlags'); - ReactFeatureFlags.enableInteractionTracking = enableInteractionTracking; + ReactFeatureFlags.enableSchedulerTracking = enableSchedulerTracking; - InteractionTracking = require('interaction-tracking'); - InteractionTrackingSubscriptions = require('interaction-tracking/subscriptions'); + SchedulerTracking = require('react-scheduler/tracking'); + SchedulerTrackingSubscriptions = require('react-scheduler/tracking-subscriptions'); throwInOnInteractionScheduledWorkCompleted = false; throwInOnInteractionTracked = false; @@ -102,22 +102,22 @@ describe('InteractionTracking', () => { onWorkStopped: jest.fn(), }; - InteractionTrackingSubscriptions.unstable_subscribe(firstSubscriber); - InteractionTrackingSubscriptions.unstable_subscribe(secondSubscriber); + SchedulerTrackingSubscriptions.unstable_subscribe(firstSubscriber); + SchedulerTrackingSubscriptions.unstable_subscribe(secondSubscriber); } describe('enabled', () => { - beforeEach(() => loadModules({enableInteractionTracking: true})); + beforeEach(() => loadModules({enableSchedulerTracking: true})); describe('error handling', () => { it('should cover onInteractionTracked/onWorkStarted within', done => { - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { const mock = jest.fn(); // It should call the callback before re-throwing throwInOnInteractionTracked = true; expect(() => - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( secondEvent.name, currentTime, mock, @@ -129,7 +129,7 @@ describe('InteractionTracking', () => { throwInOnWorkStarted = true; expect(() => - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( secondEvent.name, currentTime, mock, @@ -139,9 +139,9 @@ describe('InteractionTracking', () => { expect(mock).toHaveBeenCalledTimes(2); // It should restore the previous/outer interactions - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( - [firstEvent], - ); + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ + firstEvent, + ]); // It should call other subscribers despite the earlier error expect(secondSubscriber.onInteractionTracked).toHaveBeenCalledTimes( @@ -154,17 +154,17 @@ describe('InteractionTracking', () => { }); it('should cover onWorkStopped within track', done => { - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { let innerInteraction; const mock = jest.fn(() => { innerInteraction = Array.from( - InteractionTracking.unstable_getCurrent(), + SchedulerTracking.unstable_getCurrent(), )[1]; }); throwInOnWorkStopped = true; expect(() => - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( secondEvent.name, currentTime, mock, @@ -173,9 +173,9 @@ describe('InteractionTracking', () => { throwInOnWorkStopped = false; // It should restore the previous/outer interactions - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( - [firstEvent], - ); + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ + firstEvent, + ]); // It should update the interaction count so as not to interfere with subsequent calls expect(innerInteraction.__count).toBe(0); @@ -188,12 +188,12 @@ describe('InteractionTracking', () => { }); it('should cover onInteractionScheduledWorkCompleted within track', done => { - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { const mock = jest.fn(); throwInOnInteractionScheduledWorkCompleted = true; expect(() => - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( secondEvent.name, currentTime, mock, @@ -202,9 +202,9 @@ describe('InteractionTracking', () => { throwInOnInteractionScheduledWorkCompleted = false; // It should restore the previous/outer interactions - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( - [firstEvent], - ); + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ + firstEvent, + ]); // It should call other subscribers despite the earlier error expect( @@ -220,13 +220,9 @@ describe('InteractionTracking', () => { expect(onWorkStopped).not.toHaveBeenCalled(); expect(() => { - InteractionTracking.unstable_track( - firstEvent.name, - currentTime, - () => { - throw Error('Expected error callback'); - }, - ); + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { + throw Error('Expected error callback'); + }); }).toThrow('Expected error callback'); expect(onWorkStarted).toHaveBeenCalledTimes(1); @@ -236,14 +232,14 @@ describe('InteractionTracking', () => { }); it('should cover onWorkScheduled within wrap', done => { - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { const interaction = Array.from( - InteractionTracking.unstable_getCurrent(), + SchedulerTracking.unstable_getCurrent(), )[0]; const beforeCount = interaction.__count; throwInOnWorkScheduled = true; - expect(() => InteractionTracking.unstable_wrap(() => {})).toThrow( + expect(() => SchedulerTracking.unstable_wrap(() => {})).toThrow( 'Expected error onWorkScheduled', ); @@ -260,11 +256,9 @@ describe('InteractionTracking', () => { it('should cover onWorkStarted within wrap', () => { const mock = jest.fn(); let interaction, wrapped; - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { - interaction = Array.from( - InteractionTracking.unstable_getCurrent(), - )[0]; - wrapped = InteractionTracking.unstable_wrap(mock); + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { + interaction = Array.from(SchedulerTracking.unstable_getCurrent())[0]; + wrapped = SchedulerTracking.unstable_wrap(mock); }); expect(interaction.__count).toBe(1); @@ -282,26 +276,26 @@ describe('InteractionTracking', () => { }); it('should cover onWorkStopped within wrap', done => { - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { const outerInteraction = Array.from( - InteractionTracking.unstable_getCurrent(), + SchedulerTracking.unstable_getCurrent(), )[0]; expect(outerInteraction.__count).toBe(1); let wrapped; let innerInteraction; - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( secondEvent.name, currentTime, () => { innerInteraction = Array.from( - InteractionTracking.unstable_getCurrent(), + SchedulerTracking.unstable_getCurrent(), )[1]; expect(outerInteraction.__count).toBe(1); expect(innerInteraction.__count).toBe(1); - wrapped = InteractionTracking.unstable_wrap(jest.fn()); + wrapped = SchedulerTracking.unstable_wrap(jest.fn()); expect(outerInteraction.__count).toBe(2); expect(innerInteraction.__count).toBe(2); }, @@ -315,9 +309,9 @@ describe('InteractionTracking', () => { throwInOnWorkStopped = false; // It should restore the previous interactions - expect(InteractionTracking.unstable_getCurrent()).toMatchInteractions( - [outerInteraction], - ); + expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([ + outerInteraction, + ]); // It should update the interaction count so as not to interfere with subsequent calls expect(outerInteraction.__count).toBe(1); @@ -335,11 +329,9 @@ describe('InteractionTracking', () => { let wrapped; let interaction; - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { - interaction = Array.from( - InteractionTracking.unstable_getCurrent(), - )[0]; - wrapped = InteractionTracking.unstable_wrap(() => { + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { + interaction = Array.from(SchedulerTracking.unstable_getCurrent())[0]; + wrapped = SchedulerTracking.unstable_wrap(() => { throw Error('Expected error wrap'); }); }); @@ -358,11 +350,9 @@ describe('InteractionTracking', () => { it('should cover onWorkCanceled within wrap', () => { let interaction, wrapped; - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { - interaction = Array.from( - InteractionTracking.unstable_getCurrent(), - )[0]; - wrapped = InteractionTracking.unstable_wrap(jest.fn()); + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { + interaction = Array.from(SchedulerTracking.unstable_getCurrent())[0]; + wrapped = SchedulerTracking.unstable_wrap(jest.fn()); }); expect(interaction.__count).toBe(1); @@ -386,7 +376,7 @@ describe('InteractionTracking', () => { expect(onInteractionTracked).not.toHaveBeenCalled(); expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( firstEvent.name, currentTime, () => { @@ -402,7 +392,7 @@ describe('InteractionTracking', () => { ); expect(onWorkStopped).not.toHaveBeenCalled(); - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( secondEvent.name, currentTime, () => { @@ -454,29 +444,25 @@ describe('InteractionTracking', () => { const unwrapped = jest.fn(); let wrapped; - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { expect(onInteractionTracked).toHaveBeenCalledTimes(1); expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( firstEvent, ); - InteractionTracking.unstable_track( - secondEvent.name, - currentTime, - () => { - expect(onInteractionTracked).toHaveBeenCalledTimes(2); - expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( - secondEvent, - ); - - wrapped = InteractionTracking.unstable_wrap(unwrapped, threadID); - expect(onWorkScheduled).toHaveBeenCalledTimes(1); - expect(onWorkScheduled).toHaveBeenLastNotifiedOfWork( - new Set([firstEvent, secondEvent]), - threadID, - ); - }, - ); + SchedulerTracking.unstable_track(secondEvent.name, currentTime, () => { + expect(onInteractionTracked).toHaveBeenCalledTimes(2); + expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction( + secondEvent, + ); + + wrapped = SchedulerTracking.unstable_wrap(unwrapped, threadID); + expect(onWorkScheduled).toHaveBeenCalledTimes(1); + expect(onWorkScheduled).toHaveBeenLastNotifiedOfWork( + new Set([firstEvent, secondEvent]), + threadID, + ); + }); }); expect(onInteractionTracked).toHaveBeenCalledTimes(2); @@ -510,15 +496,11 @@ describe('InteractionTracking', () => { const fnOne = jest.fn(); const fnTwo = jest.fn(); let wrappedOne, wrappedTwo; - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { - wrappedOne = InteractionTracking.unstable_wrap(fnOne, threadID); - InteractionTracking.unstable_track( - secondEvent.name, - currentTime, - () => { - wrappedTwo = InteractionTracking.unstable_wrap(fnTwo, threadID); - }, - ); + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { + wrappedOne = SchedulerTracking.unstable_wrap(fnOne, threadID); + SchedulerTracking.unstable_track(secondEvent.name, currentTime, () => { + wrappedTwo = SchedulerTracking.unstable_wrap(fnTwo, threadID); + }); }); expect(onInteractionTracked).toHaveBeenCalledTimes(2); @@ -557,12 +539,12 @@ describe('InteractionTracking', () => { it('should not end an interaction twice if wrap is used to schedule follow up work within another wrap', () => { const fnOne = jest.fn(() => { - wrappedTwo = InteractionTracking.unstable_wrap(fnTwo, threadID); + wrappedTwo = SchedulerTracking.unstable_wrap(fnTwo, threadID); }); const fnTwo = jest.fn(); let wrappedOne, wrappedTwo; - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { - wrappedOne = InteractionTracking.unstable_wrap(fnOne, threadID); + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { + wrappedOne = SchedulerTracking.unstable_wrap(fnOne, threadID); }); expect(onInteractionTracked).toHaveBeenCalledTimes(1); @@ -586,9 +568,9 @@ describe('InteractionTracking', () => { const unwrappedOne = jest.fn(); const unwrappedTwo = jest.fn(); let wrappedOne, wrappedTwo; - InteractionTracking.unstable_track(firstEvent.name, currentTime, () => { - wrappedOne = InteractionTracking.unstable_wrap(unwrappedOne, threadID); - wrappedTwo = InteractionTracking.unstable_wrap(unwrappedTwo, threadID); + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { + wrappedOne = SchedulerTracking.unstable_wrap(unwrappedOne, threadID); + wrappedTwo = SchedulerTracking.unstable_wrap(unwrappedTwo, threadID); }); expect(onInteractionTracked).toHaveBeenCalledTimes(1); @@ -616,19 +598,15 @@ describe('InteractionTracking', () => { }); it('should unsubscribe', () => { - InteractionTrackingSubscriptions.unstable_unsubscribe(firstSubscriber); - InteractionTracking.unstable_track( - firstEvent.name, - currentTime, - () => {}, - ); + SchedulerTrackingSubscriptions.unstable_unsubscribe(firstSubscriber); + SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {}); expect(onInteractionTracked).not.toHaveBeenCalled(); }); }); describe('disabled', () => { - beforeEach(() => loadModules({enableInteractionTracking: false})); + beforeEach(() => loadModules({enableSchedulerTracking: false})); // TODO }); diff --git a/packages/interaction-tracking/subscriptions.js b/packages/react-scheduler/tracking-subscriptions.js similarity index 79% rename from packages/interaction-tracking/subscriptions.js rename to packages/react-scheduler/tracking-subscriptions.js index 91bf6e66b9791..ce17901194ea0 100644 --- a/packages/interaction-tracking/subscriptions.js +++ b/packages/react-scheduler/tracking-subscriptions.js @@ -9,4 +9,4 @@ 'use strict'; -export * from './src/InteractionTrackingSubscriptions'; +export * from './src/TrackingSubscriptions'; diff --git a/packages/interaction-tracking/index.js b/packages/react-scheduler/tracking.js similarity index 83% rename from packages/interaction-tracking/index.js rename to packages/react-scheduler/tracking.js index ee8856443dfa3..19ce07381109f 100644 --- a/packages/interaction-tracking/index.js +++ b/packages/react-scheduler/tracking.js @@ -9,4 +9,4 @@ 'use strict'; -export * from './src/InteractionTracking'; +export * from './src/Tracking'; diff --git a/packages/react-test-renderer/package.json b/packages/react-test-renderer/package.json index 5ff1da8bf394e..51cc285a5ed2e 100644 --- a/packages/react-test-renderer/package.json +++ b/packages/react-test-renderer/package.json @@ -17,7 +17,8 @@ "dependencies": { "object-assign": "^4.1.1", "prop-types": "^15.6.2", - "react-is": "^16.4.3-alpha.0" + "react-is": "^16.4.3-alpha.0", + "react-scheduler": "^0.1.0-alpha-1" }, "peerDependencies": { "react": "^16.0.0" diff --git a/packages/react/package.json b/packages/react/package.json index a643a46ea7232..6597609f0970f 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -21,10 +21,10 @@ "node": ">=0.10.0" }, "dependencies": { - "interaction-tracking": "^16.4.3-alpha.0", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.2" + "prop-types": "^15.6.2", + "react-scheduler": "^0.1.0-alpha-1" }, "browserify": { "transform": [ diff --git a/packages/react/src/ReactSharedInternals.js b/packages/react/src/ReactSharedInternals.js index 95ec6631bef45..d8752a0290903 100644 --- a/packages/react/src/ReactSharedInternals.js +++ b/packages/react/src/ReactSharedInternals.js @@ -5,12 +5,25 @@ * LICENSE file in the root directory of this source tree. */ +import assign from 'object-assign'; +import { + unstable_cancelScheduledWork as cancelScheduledWork, + unstable_now as now, + unstable_scheduleWork as scheduleWork, +} from 'react-scheduler'; import { - __interactionsRef, - __subscriberRef, + __getInteractionsRef, + __getSubscriberRef, + unstable_clear as clear, + unstable_getCurrent as getCurrent, unstable_getThreadID as getThreadID, -} from 'interaction-tracking'; -import assign from 'object-assign'; + unstable_track as track, + unstable_wrap as wrap, +} from 'react-scheduler/tracking'; +import { + unstable_subscribe as subscribe, + unstable_unsubscribe as unsubscribe, +} from 'react-scheduler/tracking-subscriptions'; import ReactCurrentOwner from './ReactCurrentOwner'; import ReactDebugCurrentFrame from './ReactDebugCurrentFrame'; @@ -18,13 +31,26 @@ const ReactSharedInternals = { ReactCurrentOwner, // Used by renderers to avoid bundling object-assign twice in UMD bundles: assign, - // Re-export the interaction-tracking API for UMD bundles. + // Re-export the react-scheduler API(s) for UMD bundles. // This avoids introducing a dependency on a new UMD global in a minor update, - // Since this would be a breaking change. - InteractionTracking: { - __interactionsRef, - __subscriberRef, + // Since that would be a breaking change (e.g. for all existing CodeSandboxes). + Scheduler: { + cancelScheduledWork, + now, + scheduleWork, + }, + SchedulerTracking: { + __getInteractionsRef, + __getSubscriberRef, + clear, + getCurrent, getThreadID, + track, + wrap, + }, + SchedulerTrackingSubscriptions: { + subscribe, + unsubscribe, }, }; diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 7bb97a13d8ef8..46d68dafda38f 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -15,15 +15,15 @@ let ReactFeatureFlags; let ReactNoop; let ReactTestRenderer; let advanceTimeBy; -let InteractionTracking; -let InteractionTrackingSubscriptions; +let SchedulerTracking; +let SchedulerTrackingSubscriptions; let mockNow; let AdvanceTime; function loadModules({ enableProfilerTimer = true, enableSuspense = false, - enableInteractionTracking = true, + enableSchedulerTracking = true, replayFailedUnitOfWorkWithInvokeGuardedCallback = false, useNoopRenderer = false, } = {}) { @@ -38,13 +38,13 @@ function loadModules({ ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; ReactFeatureFlags.enableProfilerTimer = enableProfilerTimer; ReactFeatureFlags.enableGetDerivedStateFromCatch = true; - ReactFeatureFlags.enableInteractionTracking = enableInteractionTracking; + ReactFeatureFlags.enableSchedulerTracking = enableSchedulerTracking; ReactFeatureFlags.enableSuspense = enableSuspense; ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = replayFailedUnitOfWorkWithInvokeGuardedCallback; React = require('react'); - InteractionTracking = require('interaction-tracking'); - InteractionTrackingSubscriptions = require('interaction-tracking/subscriptions'); + SchedulerTracking = require('react-scheduler/tracking'); + SchedulerTrackingSubscriptions = require('react-scheduler/tracking-subscriptions'); if (useNoopRenderer) { ReactNoop = require('react-noop-renderer'); @@ -84,17 +84,17 @@ const mockDevToolsForTest = () => { describe('Profiler', () => { describe('works in profiling and non-profiling bundles', () => { - [true, false].forEach(enableInteractionTracking => { + [true, false].forEach(enableSchedulerTracking => { [true, false].forEach(enableProfilerTimer => { - describe(`enableInteractionTracking:${ - enableInteractionTracking ? 'enabled' : 'disabled' + describe(`enableSchedulerTracking:${ + enableSchedulerTracking ? 'enabled' : 'disabled' } enableProfilerTimer:${ enableProfilerTimer ? 'enabled' : 'disabled' }`, () => { beforeEach(() => { jest.resetModules(); - loadModules({enableInteractionTracking, enableProfilerTimer}); + loadModules({enableSchedulerTracking, enableProfilerTimer}); }); // This will throw in production too, @@ -167,12 +167,12 @@ describe('Profiler', () => { }); }); - [true, false].forEach(enableInteractionTracking => { + [true, false].forEach(enableSchedulerTracking => { describe('onRender callback', () => { beforeEach(() => { jest.resetModules(); - loadModules({enableInteractionTracking}); + loadModules({enableSchedulerTracking}); }); it('is not invoked until the commit phase', () => { @@ -233,7 +233,7 @@ describe('Profiler', () => { let [call] = callback.mock.calls; - expect(call).toHaveLength(enableInteractionTracking ? 7 : 6); + expect(call).toHaveLength(enableSchedulerTracking ? 7 : 6); expect(call[0]).toBe('test'); expect(call[1]).toBe('mount'); expect(call[2]).toBe(10); // actual time @@ -241,7 +241,7 @@ describe('Profiler', () => { expect(call[4]).toBe(5); // start time expect(call[5]).toBe(15); // commit time expect(call[6]).toEqual( - enableInteractionTracking ? new Set() : undefined, + enableSchedulerTracking ? new Set() : undefined, ); // interaction events callback.mockReset(); @@ -258,7 +258,7 @@ describe('Profiler', () => { [call] = callback.mock.calls; - expect(call).toHaveLength(enableInteractionTracking ? 7 : 6); + expect(call).toHaveLength(enableSchedulerTracking ? 7 : 6); expect(call[0]).toBe('test'); expect(call[1]).toBe('update'); expect(call[2]).toBe(10); // actual time @@ -266,7 +266,7 @@ describe('Profiler', () => { expect(call[4]).toBe(35); // start time expect(call[5]).toBe(45); // commit time expect(call[6]).toEqual( - enableInteractionTracking ? new Set() : undefined, + enableSchedulerTracking ? new Set() : undefined, ); // interaction events callback.mockReset(); @@ -283,7 +283,7 @@ describe('Profiler', () => { [call] = callback.mock.calls; - expect(call).toHaveLength(enableInteractionTracking ? 7 : 6); + expect(call).toHaveLength(enableSchedulerTracking ? 7 : 6); expect(call[0]).toBe('test'); expect(call[1]).toBe('update'); expect(call[2]).toBe(4); // actual time @@ -291,7 +291,7 @@ describe('Profiler', () => { expect(call[4]).toBe(65); // start time expect(call[5]).toBe(69); // commit time expect(call[6]).toEqual( - enableInteractionTracking ? new Set() : undefined, + enableSchedulerTracking ? new Set() : undefined, ); // interaction events }); @@ -1176,7 +1176,7 @@ describe('Profiler', () => { jest.resetModules(); loadModules({ - enableInteractionTracking: true, + enableSchedulerTracking: true, }); throwInOnInteractionScheduledWorkCompleted = false; @@ -1208,7 +1208,7 @@ describe('Profiler', () => { }); // Verify interaction subscriber methods are called as expected. - InteractionTrackingSubscriptions.unstable_subscribe({ + SchedulerTrackingSubscriptions.unstable_subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, @@ -1230,7 +1230,7 @@ describe('Profiler', () => { // Errors that happen inside of a subscriber should throw, throwInOnWorkScheduled = true; expect(() => { - InteractionTracking.unstable_track('event', mockNow(), () => { + SchedulerTracking.unstable_track('event', mockNow(), () => { renderer = ReactTestRenderer.create(fail, { unstable_isAsync: true, }); @@ -1256,7 +1256,7 @@ describe('Profiler', () => { } let renderer; - InteractionTracking.unstable_track('event', mockNow(), () => { + SchedulerTracking.unstable_track('event', mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1285,7 +1285,7 @@ describe('Profiler', () => { } let renderer; - InteractionTracking.unstable_track('event', mockNow(), () => { + SchedulerTracking.unstable_track('event', mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1327,8 +1327,8 @@ describe('Profiler', () => { }; let renderer; - InteractionTracking.unstable_track(eventOne.name, mockNow(), () => { - InteractionTracking.unstable_track(eventTwo.name, mockNow(), () => { + SchedulerTracking.unstable_track(eventOne.name, mockNow(), () => { + SchedulerTracking.unstable_track(eventTwo.name, mockNow(), () => { renderer = ReactTestRenderer.create(text, { unstable_isAsync: true, }); @@ -1382,7 +1382,7 @@ describe('Profiler', () => { const onRender = jest.fn(); let renderer; - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( interactionCreation.name, mockNow(), () => { @@ -1403,7 +1403,7 @@ describe('Profiler', () => { ); expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled(); - // The interaction-tracking package will notify of work started for the default thread, + // The react-scheduler/tracking package will notify of work started for the default thread, // But React shouldn't notify until it's been flushed. expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(0); expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0); @@ -1423,7 +1423,7 @@ describe('Profiler', () => { let call = onRender.mock.calls[0]; expect(call[0]).toEqual('test-profiler'); expect(call[5]).toEqual(mockNow()); - if (ReactFeatureFlags.enableInteractionTracking) { + if (ReactFeatureFlags.enableSchedulerTracking) { expect(call[6]).toMatchInteractions([interactionCreation]); } @@ -1455,13 +1455,13 @@ describe('Profiler', () => { name: 'initial event', timestamp: mockNow(), }; - InteractionTracking.unstable_track(interactionOne.name, mockNow(), () => { + SchedulerTracking.unstable_track(interactionOne.name, mockNow(), () => { instance.setState({count: 1}); // Update state again to verify our tracked interaction isn't registered twice instance.setState({count: 2}); - // The interaction-tracking package will notify of work started for the default thread, + // The react-scheduler/tracking package will notify of work started for the default thread, // But React shouldn't notify until it's been flushed. expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(0); expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0); @@ -1495,7 +1495,7 @@ describe('Profiler', () => { call = onRender.mock.calls[0]; expect(call[0]).toEqual('test-profiler'); expect(call[5]).toEqual(mockNow()); - if (ReactFeatureFlags.enableInteractionTracking) { + if (ReactFeatureFlags.enableSchedulerTracking) { expect(call[6]).toMatchInteractions([interactionOne]); } @@ -1528,7 +1528,7 @@ describe('Profiler', () => { call = onRender.mock.calls[0]; expect(call[0]).toEqual('test-profiler'); expect(call[5]).toEqual(mockNow()); - if (ReactFeatureFlags.enableInteractionTracking) { + if (ReactFeatureFlags.enableSchedulerTracking) { expect(call[6]).toMatchInteractions([]); } @@ -1550,7 +1550,7 @@ describe('Profiler', () => { name: 'root update event', timestamp: mockNow(), }; - InteractionTracking.unstable_track(interactionTwo.name, mockNow(), () => { + SchedulerTracking.unstable_track(interactionTwo.name, mockNow(), () => { renderer.update( @@ -1564,7 +1564,7 @@ describe('Profiler', () => { ); expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2); - // The interaction-tracking package will notify of work started for the default thread, + // The react-scheduler/tracking package will notify of work started for the default thread, // But React shouldn't notify until it's been flushed. expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(0); expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0); @@ -1584,7 +1584,7 @@ describe('Profiler', () => { call = onRender.mock.calls[0]; expect(call[0]).toEqual('test-profiler'); expect(call[5]).toEqual(mockNow()); - if (ReactFeatureFlags.enableInteractionTracking) { + if (ReactFeatureFlags.enableSchedulerTracking) { expect(call[6]).toMatchInteractions([interactionTwo]); } @@ -1651,7 +1651,7 @@ describe('Profiler', () => { timestamp: mockNow(), }; - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( interactionLowPri.name, mockNow(), () => { @@ -1688,7 +1688,7 @@ describe('Profiler', () => { // Interrupt with higher priority work. // This simulates a total of 37ms of actual render time. renderer.unstable_flushSync(() => { - InteractionTracking.unstable_track( + SchedulerTracking.unstable_track( interactionHighPri.name, mockNow(), () => { @@ -1721,7 +1721,7 @@ describe('Profiler', () => { expect(call[0]).toEqual('test'); expect(call[5]).toEqual(mockNow()); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking + ReactFeatureFlags.enableSchedulerTracking ? [interactionLowPri, interactionHighPri] : [], ); @@ -1738,7 +1738,7 @@ describe('Profiler', () => { expect(call[0]).toEqual('test'); expect(call[5]).toEqual(mockNow()); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking + ReactFeatureFlags.enableSchedulerTracking ? [interactionLowPri] : [], ); @@ -1747,7 +1747,7 @@ describe('Profiler', () => { expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1); // Work might be started multiple times before being completed. - // This is okay; it's part of the interaction-tracking subscriber contract. + // This is okay; it's part of the react-scheduler/tracking-subscriptions contract. expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(3); expect( getWorkForReactThreads(onWorkStarted)[1][0], @@ -1807,7 +1807,7 @@ describe('Profiler', () => { const onRender = jest.fn(); let firstCommitTime = mockNow(); let renderer; - InteractionTracking.unstable_track(interactionOne.name, mockNow(), () => { + SchedulerTracking.unstable_track(interactionOne.name, mockNow(), () => { renderer = ReactTestRenderer.create( @@ -1851,13 +1851,13 @@ describe('Profiler', () => { expect(call[0]).toEqual('test'); expect(call[5]).toEqual(firstCommitTime); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interactionOne] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interactionOne] : [], ); call = onRender.mock.calls[1]; expect(call[0]).toEqual('test'); expect(call[5]).toEqual(mockNow()); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interactionOne] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interactionOne] : [], ); onRender.mockClear(); @@ -1869,7 +1869,7 @@ describe('Profiler', () => { }; // Cause an tracked, async update - InteractionTracking.unstable_track(interactionTwo.name, mockNow(), () => { + SchedulerTracking.unstable_track(interactionTwo.name, mockNow(), () => { instance.setState({count: 2}); }); expect(onRender).not.toHaveBeenCalled(); @@ -1914,13 +1914,13 @@ describe('Profiler', () => { expect(call[0]).toEqual('test'); expect(call[5]).toEqual(firstCommitTime); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interactionTwo] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interactionTwo] : [], ); call = onRender.mock.calls[1]; expect(call[0]).toEqual('test'); expect(call[5]).toEqual(mockNow()); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interactionTwo] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interactionTwo] : [], ); onRender.mockClear(); @@ -1935,13 +1935,9 @@ describe('Profiler', () => { function callback() { instance.setState({count: 6}); } - InteractionTracking.unstable_track( - interactionThree.name, - mockNow(), - () => { - instance.setState({count: 5}, callback); - }, - ); + SchedulerTracking.unstable_track(interactionThree.name, mockNow(), () => { + instance.setState({count: 5}, callback); + }); expect(onRender).not.toHaveBeenCalled(); expect(onInteractionTracked).toHaveBeenCalledTimes(3); @@ -1983,13 +1979,13 @@ describe('Profiler', () => { expect(call[0]).toEqual('test'); expect(call[5]).toEqual(firstCommitTime); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interactionThree] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interactionThree] : [], ); call = onRender.mock.calls[1]; expect(call[0]).toEqual('test'); expect(call[5]).toEqual(mockNow()); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interactionThree] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interactionThree] : [], ); }); @@ -2032,7 +2028,7 @@ describe('Profiler', () => { timestamp: mockNow(), }; - InteractionTracking.unstable_track(interaction.name, mockNow(), () => { + SchedulerTracking.unstable_track(interaction.name, mockNow(), () => { parentInstance.setState({count: 1}); }); @@ -2050,7 +2046,7 @@ describe('Profiler', () => { let call = onRender.mock.calls[0]; expect(call[0]).toEqual('test-profiler'); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interaction] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interaction] : [], ); expect(onInteractionTracked).toHaveBeenCalledTimes(1); @@ -2074,11 +2070,11 @@ describe('Profiler', () => { loadModules({ useNoopRenderer: true, enableSuspense: true, - enableInteractionTracking: true, + enableSchedulerTracking: true, }); // Re-register since we've reloaded modules - InteractionTrackingSubscriptions.unstable_subscribe({ + SchedulerTrackingSubscriptions.unstable_subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, @@ -2145,7 +2141,7 @@ describe('Profiler', () => { }; const onRender = jest.fn(); - InteractionTracking.unstable_track(interaction.name, mockNow(), () => { + SchedulerTracking.unstable_track(interaction.name, mockNow(), () => { ReactNoop.render( }> @@ -2190,7 +2186,7 @@ describe('Profiler', () => { let call = onRender.mock.calls[0]; expect(call[0]).toEqual('test-profiler'); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interaction] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interaction] : [], ); expect(onInteractionTracked).toHaveBeenCalledTimes(1); @@ -2205,7 +2201,7 @@ describe('Profiler', () => { call = onRender.mock.calls[1]; expect(call[0]).toEqual('test-profiler'); expect(call[6]).toMatchInteractions( - ReactFeatureFlags.enableInteractionTracking ? [interaction] : [], + ReactFeatureFlags.enableSchedulerTracking ? [interaction] : [], ); expect(onInteractionTracked).toHaveBeenCalledTimes(1); diff --git a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js index 3f55ba2b8be9d..08e2e87bd2526 100644 --- a/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js +++ b/packages/react/src/__tests__/ReactProfilerDevToolsIntegration-test.internal.js @@ -11,10 +11,10 @@ 'use strict'; describe('ReactProfiler DevTools integration', () => { - let InteractionTracking; let React; let ReactFeatureFlags; let ReactTestRenderer; + let SchedulerTracking; let AdvanceTime; let advanceTimeBy; let hook; @@ -38,8 +38,8 @@ describe('ReactProfiler DevTools integration', () => { ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.enableProfilerTimer = true; - ReactFeatureFlags.enableInteractionTracking = true; - InteractionTracking = require('interaction-tracking'); + ReactFeatureFlags.enableSchedulerTracking = true; + SchedulerTracking = require('react-scheduler/tracking'); React = require('react'); ReactTestRenderer = require('react-test-renderer'); @@ -180,7 +180,7 @@ describe('ReactProfiler DevTools integration', () => { const eventTime = mockNow(); // Render with an interaction - InteractionTracking.unstable_track('some event', eventTime, () => { + SchedulerTracking.unstable_track('some event', eventTime, () => { rendered.update(
); }); diff --git a/packages/react/src/__tests__/__snapshots__/ReactProfiler-test.internal.js.snap b/packages/react/src/__tests__/__snapshots__/ReactProfiler-test.internal.js.snap index 06e00d35930c4..18f6f0ac516fa 100644 --- a/packages/react/src/__tests__/__snapshots__/ReactProfiler-test.internal.js.snap +++ b/packages/react/src/__tests__/__snapshots__/ReactProfiler-test.internal.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:disabled should render children 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:disabled should render children 1`] = `
outside span @@ -14,11 +14,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableInteraction
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 1`] = `null`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 1`] = `null`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 2`] = `
`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 2`] = `
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:disabled should support nested Profilers 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:disabled should support nested Profilers 1`] = ` Array [
outer functional component @@ -32,7 +32,7 @@ Array [ ] `; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:enabled should render children 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:enabled should render children 1`] = `
outside span @@ -46,11 +46,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableInteraction
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 1`] = `null`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 1`] = `null`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 2`] = `
`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 2`] = `
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:disabled enableProfilerTimer:enabled should support nested Profilers 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:enabled should support nested Profilers 1`] = ` Array [
outer functional component @@ -64,7 +64,7 @@ Array [ ] `; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:disabled should render children 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:disabled should render children 1`] = `
outside span @@ -78,11 +78,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableInteraction
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 1`] = `null`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 1`] = `null`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 2`] = `
`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 2`] = `
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:disabled should support nested Profilers 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:disabled should support nested Profilers 1`] = ` Array [
outer functional component @@ -96,7 +96,7 @@ Array [ ] `; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:enabled should render children 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:enabled should render children 1`] = `
outside span @@ -110,11 +110,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableInteraction
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 1`] = `null`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 1`] = `null`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 2`] = `
`; +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 2`] = `
`; -exports[`Profiler works in profiling and non-profiling bundles enableInteractionTracking:enabled enableProfilerTimer:enabled should support nested Profilers 1`] = ` +exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:enabled should support nested Profilers 1`] = ` Array [
outer functional component diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js index aa9fc017fca70..c0e53946eaa01 100644 --- a/packages/shared/ReactFeatureFlags.js +++ b/packages/shared/ReactFeatureFlags.js @@ -40,7 +40,7 @@ export const warnAboutLegacyContextAPI = false; export const enableProfilerTimer = __PROFILE__; // Track which interactions trigger each commit. -export const enableInteractionTracking = __PROFILE__; +export const enableSchedulerTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/ReactScheduler.js b/packages/shared/ReactScheduler.js index c65d28ecfaf7c..1e279f550bffa 100644 --- a/packages/shared/ReactScheduler.js +++ b/packages/shared/ReactScheduler.js @@ -9,9 +9,9 @@ 'use strict'; import { - now, - scheduleWork, - cancelScheduledWork, -} from 'react-scheduler/src/ReactScheduler'; + unstable_now as now, + unstable_scheduleWork as scheduleWork, + unstable_cancelScheduledWork as cancelScheduledWork, +} from 'react-scheduler'; export {now, scheduleWork, cancelScheduledWork}; diff --git a/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js index 3333c0225286e..634a9236aacd9 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fabric-fb.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = __DEV__; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = __PROFILE__; +export const enableSchedulerTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js b/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js index 982ecfc01a1ab..210e40c449f9a 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fabric-oss.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = __PROFILE__; +export const enableSchedulerTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js index 414fb60566a6c..f86dd8c5cfc35 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-fb.js +++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js @@ -26,7 +26,7 @@ export const { export const enableUserTimingAPI = __DEV__; export const warnAboutLegacyContextAPI = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = __PROFILE__; +export const enableSchedulerTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js index e9891d89c4f49..8097e29d959d8 100644 --- a/packages/shared/forks/ReactFeatureFlags.native-oss.js +++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js @@ -21,7 +21,7 @@ export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = __PROFILE__; +export const enableSchedulerTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.persistent.js b/packages/shared/forks/ReactFeatureFlags.persistent.js index 59189ef85de7b..0d78dacdf2e40 100644 --- a/packages/shared/forks/ReactFeatureFlags.persistent.js +++ b/packages/shared/forks/ReactFeatureFlags.persistent.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = __PROFILE__; +export const enableSchedulerTracking = __PROFILE__; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js index 773a1d6b2d8d3..280359f9997af 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false; export const enableProfilerTimer = false; -export const enableInteractionTracking = false; +export const enableSchedulerTracking = false; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js index 49bbec5025542..4fa93944f3066 100644 --- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js +++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js @@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false; export const warnAboutLegacyContextAPI = false; export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false; export const enableProfilerTimer = false; -export const enableInteractionTracking = false; +export const enableSchedulerTracking = false; // Only used in www builds. export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js index 37b88db984913..5baa9cdff0966 100644 --- a/packages/shared/forks/ReactFeatureFlags.www.js +++ b/packages/shared/forks/ReactFeatureFlags.www.js @@ -32,7 +32,7 @@ export const warnAboutLegacyContextAPI = __DEV__; export let enableUserTimingAPI = __DEV__; export const enableProfilerTimer = __PROFILE__; -export const enableInteractionTracking = __PROFILE__; +export const enableSchedulerTracking = __PROFILE__; let refCount = 0; export function addUserTimingListener() { diff --git a/packages/shared/forks/ReactScheduler.umd.js b/packages/shared/forks/ReactScheduler.umd.js new file mode 100644 index 0000000000000..cb074a848240b --- /dev/null +++ b/packages/shared/forks/ReactScheduler.umd.js @@ -0,0 +1,31 @@ +/** + * 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 + */ + +import React from 'react'; + +export function unstable_now() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.now.apply( + this, + arguments, + ); +} + +export function unstable_scheduleWork() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.scheduleWork.apply( + this, + arguments, + ); +} + +export function unstable_cancelScheduledWork() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.cancelScheduledWork.apply( + this, + arguments, + ); +} diff --git a/packages/shared/forks/ReactScheduler.www.js b/packages/shared/forks/ReactScheduler.www.js index 4f76345a1c20f..d18736eb838c3 100644 --- a/packages/shared/forks/ReactScheduler.www.js +++ b/packages/shared/forks/ReactScheduler.www.js @@ -8,4 +8,8 @@ 'use strict'; const {now, scheduleWork, cancelScheduledWork} = require('customSchedule'); -export {now, scheduleWork, cancelScheduledWork}; +export { + now as unstable_now, + scheduleWork as unstable_scheduleWork, + cancelScheduledWork as unstable_cancelScheduledWork, +}; diff --git a/packages/shared/forks/ReactSchedulerTracking.umd.js b/packages/shared/forks/ReactSchedulerTracking.umd.js new file mode 100644 index 0000000000000..358bf3e55b28e --- /dev/null +++ b/packages/shared/forks/ReactSchedulerTracking.umd.js @@ -0,0 +1,59 @@ +/** + * 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 + */ + +import React from 'react'; + +export function __getInteractionsRef() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.__getInteractionsRef.apply( + this, + arguments, + ); +} + +export function __getSubscriberRef() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.__getSubscriberRef.apply( + this, + arguments, + ); +} + +export function unstable_clear() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.clear.apply( + this, + arguments, + ); +} + +export function unstable_getCurrent() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.getCurrent.apply( + this, + arguments, + ); +} + +export function unstable_getThreadID() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.getThreadID.apply( + this, + arguments, + ); +} + +export function unstable_track() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.track.apply( + this, + arguments, + ); +} + +export function unstable_wrap() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.wrap.apply( + this, + arguments, + ); +} diff --git a/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js b/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js new file mode 100644 index 0000000000000..dc6e40bfe6c7f --- /dev/null +++ b/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js @@ -0,0 +1,24 @@ +/** + * 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 + */ + +import React from 'react'; + +export function unstable_subscribe() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.subscribe.apply( + this, + arguments, + ); +} + +export function unstable_unsubscribe() { + return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.unsubscribe.apply( + this, + arguments, + ); +} diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index fa1c8f90c6630..ce6ab6146a2f3 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -18,6 +18,7 @@ const Stats = require('./stats'); const Sync = require('./sync'); const sizes = require('./plugins/sizes-plugin'); const useForks = require('./plugins/use-forks-plugin'); +const stripUnusedImports = require('./plugins/strip-unused-imports'); const extractErrorCodes = require('../error-codes/extract-errors'); const Packaging = require('./packaging'); const {asyncCopyTo, asyncRimRaf} = require('./utils'); @@ -272,7 +273,8 @@ function getPlugins( bundleType, globalName, moduleType, - modulesToStub + modulesToStub, + pureExternalModules ) { const findAndRecordErrorCodes = extractErrorCodes(errorCodeOpts); const forks = Modules.getForks(bundleType, entry, moduleType); @@ -349,6 +351,9 @@ function getPlugins( renaming: !shouldStayReadable, }) ), + // HACK to work around the fact that Rollup isn't removing unused, pure-module imports. + // Note that this plugin must be called after closure applies DCE. + isProduction && stripUnusedImports(pureExternalModules), // Add the whitespace back if necessary. shouldStayReadable && prettier({parser: 'babylon'}), // License and haste headers, top-level `if` blocks. @@ -468,7 +473,8 @@ async function createBundle(bundle, bundleType) { bundleType, bundle.global, bundle.moduleType, - bundle.modulesToStub + bundle.modulesToStub, + pureExternalModules ), // We can't use getters in www. legacy: diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 7e12d53387931..167c5ff17bcec 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -397,10 +397,11 @@ const bundles = [ externals: [], }, - /******* interaction-tracking (experimental) *******/ { - label: 'interaction-tracking', + label: 'react-scheduler-tracking', bundleTypes: [ + UMD_DEV, + UMD_PROD, FB_WWW_DEV, FB_WWW_PROD, FB_WWW_PROFILING, @@ -409,14 +410,16 @@ const bundles = [ NODE_PROFILING, ], moduleType: ISOMORPHIC, - entry: 'interaction-tracking', - global: 'InteractionTracking', + entry: 'react-scheduler/tracking', + global: 'ReactSchedulerTracking', externals: [], }, { - label: 'interaction-tracking-subscriptions', + label: 'react-scheduler-tracking-subscriptions', bundleTypes: [ + UMD_DEV, + UMD_PROD, FB_WWW_DEV, FB_WWW_PROD, FB_WWW_PROFILING, @@ -425,9 +428,9 @@ const bundles = [ NODE_PROFILING, ], moduleType: ISOMORPHIC, - entry: 'interaction-tracking/subscriptions', - global: 'InteractionTrackingSubscriptions', - externals: ['interaction-tracking'], + entry: 'react-scheduler/tracking-subscriptions', + global: 'ReactSchedulerTrackingSubscriptions', + externals: ['react-scheduler-tracking'], }, ]; diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js index ba4a7fe3db282..4152ab037f8ee 100644 --- a/scripts/rollup/forks.js +++ b/scripts/rollup/forks.js @@ -114,12 +114,60 @@ const forks = Object.freeze({ return null; }, - 'shared/ReactScheduler': (bundleType, entry) => { + 'react-scheduler': (bundleType, entry, dependencies) => { switch (bundleType) { case FB_WWW_DEV: case FB_WWW_PROD: case FB_WWW_PROFILING: return 'shared/forks/ReactScheduler.www.js'; + case UMD_DEV: + case UMD_PROD: + if (dependencies.indexOf('react') === -1) { + // We can only apply the optimizations to bundle that depend on React + // because we read assign() from an object exposed on React internals. + return null; + } + // Optimization: for UMDs, use the API that is already a part of the React + // package instead of requiring it to be loaded via a separate - - + + + - + diff --git a/fixtures/tracking/script.js b/fixtures/tracking/script.js new file mode 100644 index 0000000000000..8536ed4929ff7 --- /dev/null +++ b/fixtures/tracking/script.js @@ -0,0 +1,213 @@ +function runTest(listItem, callback) { + try { + callback(); + listItem.className = 'correct'; + listItem.setAttribute('data-value', 'All checks pass'); + } catch (error) { + listItem.className = 'incorrect'; + listItem.setAttribute('data-value', error); + } +} + +function runAllTests() { + try { + checkSchedulerAPI(); + } finally { + try { + checkSchedulerTrackingAPI(); + } finally { + try { + checkSchedulerTrackingSubscriptionsAPI(); + } finally { + checkEndToEndIntegration(); + } + } + } +} + +function checkSchedulerAPI() { + runTest(document.getElementById('checkSchedulerAPI'), () => { + if ( + typeof ReactScheduler === 'undefined' || + typeof ReactScheduler.unstable_now !== 'function' || + typeof ReactScheduler.unstable_scheduleWork !== 'function' || + typeof ReactScheduler.unstable_cancelScheduledWork !== 'function' + ) { + throw 'API is not defined'; + } + + if (ReactScheduler.unstable_now() !== performance.now()) { + throw 'API does not work'; + } + + // There is no real way to verify that the two APIs are connected. + }); +} + +function checkSchedulerTrackingAPI() { + runTest(document.getElementById('checkSchedulerTrackingAPI'), () => { + if ( + typeof ReactSchedulerTracking === 'undefined' || + typeof ReactSchedulerTracking.__getInteractionsRef !== 'function' || + typeof ReactSchedulerTracking.__getSubscriberRef !== 'function' || + typeof ReactSchedulerTracking.unstable_clear !== 'function' || + typeof ReactSchedulerTracking.unstable_getCurrent !== 'function' || + typeof ReactSchedulerTracking.unstable_getThreadID !== 'function' || + typeof ReactSchedulerTracking.unstable_track !== 'function' || + typeof ReactSchedulerTracking.unstable_wrap !== 'function' + ) { + throw 'API is not defined'; + } + + try { + let interactionsSet; + ReactSchedulerTracking.unstable_track('test', 123, () => { + interactionsSet = ReactSchedulerTracking.__getInteractionsRef().current; + }); + if (interactionsSet.size !== 1) { + throw null; + } + const interaction = Array.from(interactionsSet)[0]; + if (interaction.name !== 'test' || interaction.timestamp !== 123) { + throw null; + } + } catch (error) { + throw 'API does not work'; + } + + const ForwardedSchedulerTracking = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED + .SchedulerTracking; + + if ( + ReactSchedulerTracking.unstable_getThreadID() === + ForwardedSchedulerTracking.unstable_getThreadID() + ) { + throw 'API forwarding is broken'; + } + }); +} + +function checkSchedulerTrackingSubscriptionsAPI() { + runTest( + document.getElementById('checkSchedulerTrackingSubscriptionsAPI'), + () => { + if ( + typeof ReactSchedulerTrackingSubscriptions === 'undefined' || + typeof ReactSchedulerTrackingSubscriptions.unstable_subscribe !== + 'function' || + typeof ReactSchedulerTrackingSubscriptions.unstable_unsubscribe !== + 'function' + ) { + throw 'API is not defined'; + } + + const onInteractionScheduledWorkCompletedCalls = []; + const onInteractionTrackedCalls = []; + const onWorkCanceledCalls = []; + const onWorkScheduledCalls = []; + const onWorkStartedCalls = []; + const onWorkStoppedCalls = []; + const subscriber = { + onInteractionScheduledWorkCompleted: (...args) => + onInteractionScheduledWorkCompletedCalls.push(args), + onInteractionTracked: (...args) => onInteractionTrackedCalls.push(args), + onWorkCanceled: (...args) => onWorkCanceledCalls.push(args), + onWorkScheduled: (...args) => onWorkScheduledCalls.push(args), + onWorkStarted: (...args) => onWorkStartedCalls.push(args), + onWorkStopped: (...args) => onWorkStoppedCalls.push(args), + }; + + try { + ReactSchedulerTrackingSubscriptions.unstable_subscribe(subscriber); + ReactSchedulerTracking.unstable_track('foo', 123, () => {}); + ReactSchedulerTrackingSubscriptions.unstable_unsubscribe(subscriber); + if (onInteractionTrackedCalls.length !== 1) { + throw null; + } + const interaction = onInteractionTrackedCalls[0][0]; + if (interaction.name !== 'foo' || interaction.timestamp !== 123) { + throw null; + } + ReactSchedulerTracking.unstable_track('bar', 456, () => {}); + if (onInteractionTrackedCalls.length !== 1) { + throw null; + } + } catch (error) { + throw 'API does not forward methods'; + } + + const ForwardedSchedulerTrackingSubscriptions = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED + .SchedulerTrackingSubscriptions; + const ForwardedSchedulerTracking = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED + .SchedulerTracking; + + try { + ForwardedSchedulerTrackingSubscriptions.unstable_subscribe(subscriber); + ReactSchedulerTracking.unstable_track('foo', 123, () => {}); + ForwardedSchedulerTracking.unstable_track('bar', 456, () => {}); + ReactSchedulerTrackingSubscriptions.unstable_unsubscribe(subscriber); + if (onInteractionTrackedCalls.length !== 3) { + throw null; + } + const interactionFoo = onInteractionTrackedCalls[1][0]; + const interactionBar = onInteractionTrackedCalls[2][0]; + if ( + interactionFoo.name !== 'foo' || + interactionFoo.timestamp !== 123 || + interactionBar.name !== 'bar' || + interactionBar.timestamp !== 456 + ) { + throw null; + } + ForwardedSchedulerTracking.unstable_track('baz', 789, () => {}); + if (onInteractionTrackedCalls.length !== 3) { + throw null; + } + } catch (error) { + throw 'API forwarding is broken'; + } + } + ); +} + +function checkEndToEndIntegration() { + runTest(document.getElementById('checkEndToEndIntegration'), () => { + try { + const onRenderCalls = []; + const onRender = (...args) => onRenderCalls.push(args); + const container = document.createElement('div'); + + ReactSchedulerTracking.unstable_track('render', 123, () => { + ReactDOM.render( + React.createElement( + React.unstable_Profiler, + {id: 'profiler', onRender}, + React.createElement('div', null, 'hi') + ), + container + ); + }); + + if (container.textContent !== 'hi') { + throw null; + } + + if (onRenderCalls.length !== 1) { + throw null; + } + const call = onRenderCalls[0]; + if (call.length !== 7) { + throw null; + } + const interaction = Array.from(call[6])[0]; + if (interaction.name !== 'render' || interaction.timestamp !== 123) { + throw null; + } + } catch (error) { + throw 'End to end integration is broken'; + } + }); +} diff --git a/packages/react-scheduler/npm/umd/react-scheduler-tracking-subscriptions.js b/packages/react-scheduler/npm/umd/react-scheduler-tracking-subscriptions.js new file mode 100644 index 0000000000000..21f529827d841 --- /dev/null +++ b/packages/react-scheduler/npm/umd/react-scheduler-tracking-subscriptions.js @@ -0,0 +1,39 @@ +/** + * @license React + * + * 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. + */ + +'use strict'; + +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + ? (module.exports = factory(require('react'))) + : typeof define === 'function' && define.amd // eslint-disable-line no-undef + ? define(['react'], factory) // eslint-disable-line no-undef + : (global.ReactSchedulerTrackingSubscriptions = factory(global)); +})(this, function(global) { + function unstable_subscribe() { + // eslint-disable-next-line max-len + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.unstable_subscribe.apply( + this, + arguments + ); + } + + function unstable_unsubscribe() { + // eslint-disable-next-line max-len + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.unstable_unsubscribe.apply( + this, + arguments + ); + } + + return Object.freeze({ + unstable_subscribe: unstable_subscribe, + unstable_unsubscribe: unstable_unsubscribe, + }); +}); diff --git a/packages/react-scheduler/npm/umd/react-scheduler-tracking.js b/packages/react-scheduler/npm/umd/react-scheduler-tracking.js new file mode 100644 index 0000000000000..69f7f4a9b9571 --- /dev/null +++ b/packages/react-scheduler/npm/umd/react-scheduler-tracking.js @@ -0,0 +1,77 @@ +/** + * @license React + * + * 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. + */ + +'use strict'; + +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + ? (module.exports = factory(require('react'))) + : typeof define === 'function' && define.amd // eslint-disable-line no-undef + ? define(['react'], factory) // eslint-disable-line no-undef + : (global.ReactSchedulerTracking = factory(global)); +})(this, function(global) { + function __getInteractionsRef() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.__getInteractionsRef.apply( + this, + arguments + ); + } + + function __getSubscriberRef() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.__getSubscriberRef.apply( + this, + arguments + ); + } + + function unstable_clear() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_clear.apply( + this, + arguments + ); + } + + function unstable_getCurrent() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_getCurrent.apply( + this, + arguments + ); + } + + function unstable_getThreadID() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_getThreadID.apply( + this, + arguments + ); + } + + function unstable_track() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_track.apply( + this, + arguments + ); + } + + function unstable_wrap() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_wrap.apply( + this, + arguments + ); + } + + return Object.freeze({ + __getInteractionsRef: __getInteractionsRef, + __getSubscriberRef: __getSubscriberRef, + unstable_clear: unstable_clear, + unstable_getCurrent: unstable_getCurrent, + unstable_getThreadID: unstable_getThreadID, + unstable_track: unstable_track, + unstable_wrap: unstable_wrap, + }); +}); diff --git a/packages/react-scheduler/npm/umd/react-scheduler.js b/packages/react-scheduler/npm/umd/react-scheduler.js new file mode 100644 index 0000000000000..f02ccba6bfbd3 --- /dev/null +++ b/packages/react-scheduler/npm/umd/react-scheduler.js @@ -0,0 +1,45 @@ +/** + * @license React + * + * 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. + */ + +'use strict'; + +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + ? (module.exports = factory(require('react'))) + : typeof define === 'function' && define.amd // eslint-disable-line no-undef + ? define(['react'], factory) // eslint-disable-line no-undef + : (global.ReactScheduler = factory(global)); +})(this, function(global) { + function unstable_now() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_now.apply( + this, + arguments + ); + } + + function unstable_scheduleWork() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_scheduleWork.apply( + this, + arguments + ); + } + + function unstable_cancelScheduledWork() { + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.unstable_cancelScheduledWork.apply( + this, + arguments + ); + } + + return Object.freeze({ + unstable_now: unstable_now, + unstable_scheduleWork: unstable_scheduleWork, + unstable_cancelScheduledWork: unstable_cancelScheduledWork, + }); +}); diff --git a/packages/react/src/ReactSharedInternals.js b/packages/react/src/ReactSharedInternals.js index 80dd92464cf90..77190c6dd0c9f 100644 --- a/packages/react/src/ReactSharedInternals.js +++ b/packages/react/src/ReactSharedInternals.js @@ -7,22 +7,22 @@ import assign from 'object-assign'; import { - unstable_cancelScheduledWork as cancelScheduledWork, - unstable_now as now, - unstable_scheduleWork as scheduleWork, + unstable_cancelScheduledWork, + unstable_now, + unstable_scheduleWork, } from 'react-scheduler'; import { __getInteractionsRef, __getSubscriberRef, - unstable_clear as clear, - unstable_getCurrent as getCurrent, - unstable_getThreadID as getThreadID, - unstable_track as track, - unstable_wrap as wrap, + unstable_clear, + unstable_getCurrent, + unstable_getThreadID, + unstable_track, + unstable_wrap, } from 'react-scheduler/tracking'; import { - unstable_subscribe as subscribe, - unstable_unsubscribe as unsubscribe, + unstable_subscribe, + unstable_unsubscribe, } from 'react-scheduler/tracking-subscriptions'; import ReactCurrentOwner from './ReactCurrentOwner'; import ReactDebugCurrentFrame from './ReactDebugCurrentFrame'; @@ -41,22 +41,22 @@ if (__UMD__) { // CJS bundles use the shared NPM package. Object.assign(ReactSharedInternals, { Scheduler: { - cancelScheduledWork, - now, - scheduleWork, + unstable_cancelScheduledWork, + unstable_now, + unstable_scheduleWork, }, SchedulerTracking: { __getInteractionsRef, __getSubscriberRef, - clear, - getCurrent, - getThreadID, - track, - wrap, + unstable_clear, + unstable_getCurrent, + unstable_getThreadID, + unstable_track, + unstable_wrap, }, SchedulerTrackingSubscriptions: { - subscribe, - unsubscribe, + unstable_subscribe, + unstable_unsubscribe, }, }); } diff --git a/packages/shared/ReactScheduler.js b/packages/shared/ReactScheduler.js deleted file mode 100644 index 1e279f550bffa..0000000000000 --- a/packages/shared/ReactScheduler.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * 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'; -import { - unstable_now as now, - unstable_scheduleWork as scheduleWork, - unstable_cancelScheduledWork as cancelScheduledWork, -} from 'react-scheduler'; - -export {now, scheduleWork, cancelScheduledWork}; diff --git a/packages/shared/forks/ReactScheduler.umd.js b/packages/shared/forks/ReactScheduler.umd.js index cb074a848240b..81adf456e03e3 100644 --- a/packages/shared/forks/ReactScheduler.umd.js +++ b/packages/shared/forks/ReactScheduler.umd.js @@ -9,23 +9,12 @@ import React from 'react'; -export function unstable_now() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.now.apply( - this, - arguments, - ); -} +const ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; -export function unstable_scheduleWork() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.scheduleWork.apply( - this, - arguments, - ); -} +const { + unstable_cancelScheduledWork, + unstable_now, + unstable_scheduleWork, +} = ReactInternals.Scheduler; -export function unstable_cancelScheduledWork() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler.cancelScheduledWork.apply( - this, - arguments, - ); -} +export {unstable_cancelScheduledWork, unstable_now, unstable_scheduleWork}; diff --git a/packages/shared/forks/ReactScheduler.www.js b/packages/shared/forks/ReactScheduler.www.js index d18736eb838c3..0df242dfb1e9b 100644 --- a/packages/shared/forks/ReactScheduler.www.js +++ b/packages/shared/forks/ReactScheduler.www.js @@ -6,10 +6,10 @@ */ 'use strict'; -const {now, scheduleWork, cancelScheduledWork} = require('customSchedule'); +const { + unstable_now, + unstable_scheduleWork, + unstable_cancelScheduledWork, +} = require('customSchedule'); -export { - now as unstable_now, - scheduleWork as unstable_scheduleWork, - cancelScheduledWork as unstable_cancelScheduledWork, -}; +export {unstable_now, unstable_scheduleWork, unstable_cancelScheduledWork}; diff --git a/packages/shared/forks/ReactSchedulerTracking.umd.js b/packages/shared/forks/ReactSchedulerTracking.umd.js index 358bf3e55b28e..2d4b84ad536f6 100644 --- a/packages/shared/forks/ReactSchedulerTracking.umd.js +++ b/packages/shared/forks/ReactSchedulerTracking.umd.js @@ -9,51 +9,24 @@ import React from 'react'; -export function __getInteractionsRef() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.__getInteractionsRef.apply( - this, - arguments, - ); -} - -export function __getSubscriberRef() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.__getSubscriberRef.apply( - this, - arguments, - ); -} - -export function unstable_clear() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.clear.apply( - this, - arguments, - ); -} - -export function unstable_getCurrent() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.getCurrent.apply( - this, - arguments, - ); -} - -export function unstable_getThreadID() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.getThreadID.apply( - this, - arguments, - ); -} - -export function unstable_track() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.track.apply( - this, - arguments, - ); -} - -export function unstable_wrap() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.wrap.apply( - this, - arguments, - ); -} +const ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +const { + __getInteractionsRef, + __getSubscriberRef, + unstable_clear, + unstable_getCurrent, + unstable_getThreadID, + unstable_track, + unstable_wrap, +} = ReactInternals.SchedulerTracking; + +export { + __getInteractionsRef, + __getSubscriberRef, + unstable_clear, + unstable_getCurrent, + unstable_getThreadID, + unstable_track, + unstable_wrap, +}; diff --git a/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js b/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js index dc6e40bfe6c7f..1cbf6ccee8943 100644 --- a/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js +++ b/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js @@ -9,16 +9,11 @@ import React from 'react'; -export function unstable_subscribe() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.subscribe.apply( - this, - arguments, - ); -} +const ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; -export function unstable_unsubscribe() { - return React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.unsubscribe.apply( - this, - arguments, - ); -} +const { + unstable_subscribe, + unstable_unsubscribe, +} = ReactInternals.SchedulerTrackingSubscriptions; + +export {unstable_subscribe, unstable_unsubscribe}; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 167c5ff17bcec..504dc9ece0712 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -383,14 +383,7 @@ const bundles = [ /******* React Scheduler (experimental) *******/ { label: 'react-scheduler', - bundleTypes: [ - UMD_DEV, - UMD_PROD, - NODE_DEV, - NODE_PROD, - FB_WWW_DEV, - FB_WWW_PROD, - ], + bundleTypes: [NODE_DEV, NODE_PROD, FB_WWW_DEV, FB_WWW_PROD], moduleType: ISOMORPHIC, entry: 'react-scheduler', global: 'ReactScheduler', @@ -400,8 +393,6 @@ const bundles = [ { label: 'react-scheduler-tracking', bundleTypes: [ - UMD_DEV, - UMD_PROD, FB_WWW_DEV, FB_WWW_PROD, FB_WWW_PROFILING, @@ -418,8 +409,6 @@ const bundles = [ { label: 'react-scheduler-tracking-subscriptions', bundleTypes: [ - UMD_DEV, - UMD_PROD, FB_WWW_DEV, FB_WWW_PROD, FB_WWW_PROFILING, @@ -430,7 +419,7 @@ const bundles = [ moduleType: ISOMORPHIC, entry: 'react-scheduler/tracking-subscriptions', global: 'ReactSchedulerTrackingSubscriptions', - externals: ['react-scheduler-tracking'], + externals: ['react-scheduler', 'react-scheduler/tracking'], }, ]; diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js index 4152ab037f8ee..f82e79dbb2327 100644 --- a/scripts/rollup/forks.js +++ b/scripts/rollup/forks.js @@ -123,8 +123,7 @@ const forks = Object.freeze({ case UMD_DEV: case UMD_PROD: if (dependencies.indexOf('react') === -1) { - // We can only apply the optimizations to bundle that depend on React - // because we read assign() from an object exposed on React internals. + // For CJS bundles, use the shared NPM package. return null; } // Optimization: for UMDs, use the API that is already a part of the React @@ -140,8 +139,7 @@ const forks = Object.freeze({ case UMD_DEV: case UMD_PROD: if (dependencies.indexOf('react') === -1) { - // We can only apply the optimizations to bundle that depend on React - // because we read assign() from an object exposed on React internals. + // For CJS bundles, use the shared NPM package. return null; } // Optimization: for UMDs, use the API that is already a part of the React @@ -161,8 +159,7 @@ const forks = Object.freeze({ case UMD_DEV: case UMD_PROD: if (dependencies.indexOf('react') === -1) { - // We can only apply the optimizations to bundle that depend on React - // because we read assign() from an object exposed on React internals. + // For CJS bundles, use the shared NPM package. return null; } // Optimization: for UMDs, use the API that is already a part of the React diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js index ab5103d159483..439838423a1df 100644 --- a/scripts/rollup/modules.js +++ b/scripts/rollup/modules.js @@ -23,8 +23,9 @@ const importSideEffects = Object.freeze({ const knownGlobals = Object.freeze({ react: 'React', 'react-dom': 'ReactDOM', - 'react-scheduler-tracking': 'ReactSchedulerTracking', - 'react-scheduler-tracking-subscriptions': + 'react-scheduler': 'ReactScheduler', + 'react-scheduler/tracking': 'ReactSchedulerTracking', + 'react-scheduler/tracking-subscriptions': 'ReactSchedulerTrackingSubscriptions', }); From c5b4db2f37f0e3495e50299a1e1efe5b7dbf0124 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Sat, 1 Sep 2018 08:03:24 -0700 Subject: [PATCH 11/12] Cleaned up inline comment about scheduling fork --- scripts/rollup/forks.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js index f82e79dbb2327..28dbd64528afd 100644 --- a/scripts/rollup/forks.js +++ b/scripts/rollup/forks.js @@ -123,13 +123,15 @@ const forks = Object.freeze({ case UMD_DEV: case UMD_PROD: if (dependencies.indexOf('react') === -1) { - // For CJS bundles, use the shared NPM package. + // It's only safe to use this fork for modules that depend on React, + // because they read the re-exported API from the SECRET_INTERNALS object. return null; } // Optimization: for UMDs, use the API that is already a part of the React // package instead of requiring it to be loaded via a separate - diff --git a/fixtures/tracking/script.js b/fixtures/tracking/script.js index 8536ed4929ff7..b146a56ebc961 100644 --- a/fixtures/tracking/script.js +++ b/fixtures/tracking/script.js @@ -93,11 +93,9 @@ function checkSchedulerTrackingSubscriptionsAPI() { document.getElementById('checkSchedulerTrackingSubscriptionsAPI'), () => { if ( - typeof ReactSchedulerTrackingSubscriptions === 'undefined' || - typeof ReactSchedulerTrackingSubscriptions.unstable_subscribe !== - 'function' || - typeof ReactSchedulerTrackingSubscriptions.unstable_unsubscribe !== - 'function' + typeof ReactSchedulerTracking === 'undefined' || + typeof ReactSchedulerTracking.unstable_subscribe !== 'function' || + typeof ReactSchedulerTracking.unstable_unsubscribe !== 'function' ) { throw 'API is not defined'; } @@ -119,9 +117,9 @@ function checkSchedulerTrackingSubscriptionsAPI() { }; try { - ReactSchedulerTrackingSubscriptions.unstable_subscribe(subscriber); + ReactSchedulerTracking.unstable_subscribe(subscriber); ReactSchedulerTracking.unstable_track('foo', 123, () => {}); - ReactSchedulerTrackingSubscriptions.unstable_unsubscribe(subscriber); + ReactSchedulerTracking.unstable_unsubscribe(subscriber); if (onInteractionTrackedCalls.length !== 1) { throw null; } @@ -137,18 +135,15 @@ function checkSchedulerTrackingSubscriptionsAPI() { throw 'API does not forward methods'; } - const ForwardedSchedulerTrackingSubscriptions = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED - .SchedulerTrackingSubscriptions; const ForwardedSchedulerTracking = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED .SchedulerTracking; try { - ForwardedSchedulerTrackingSubscriptions.unstable_subscribe(subscriber); + ForwardedSchedulerTracking.unstable_subscribe(subscriber); ReactSchedulerTracking.unstable_track('foo', 123, () => {}); ForwardedSchedulerTracking.unstable_track('bar', 456, () => {}); - ReactSchedulerTrackingSubscriptions.unstable_unsubscribe(subscriber); + ReactSchedulerTracking.unstable_unsubscribe(subscriber); if (onInteractionTrackedCalls.length !== 3) { throw null; } diff --git a/packages/react-scheduler/npm/tracking-subscriptions.js b/packages/react-scheduler/npm/tracking-subscriptions.js deleted file mode 100644 index f32e47d0429e4..0000000000000 --- a/packages/react-scheduler/npm/tracking-subscriptions.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -if (process.env.NODE_ENV === 'production') { - module.exports = require('./cjs/react-scheduler-tracking-subscriptions.production.min.js'); -} else { - module.exports = require('./cjs/react-scheduler-tracking-subscriptions.development.js'); -} diff --git a/packages/react-scheduler/npm/umd/react-scheduler-tracking-subscriptions.js b/packages/react-scheduler/npm/umd/react-scheduler-tracking-subscriptions.js deleted file mode 100644 index 21f529827d841..0000000000000 --- a/packages/react-scheduler/npm/umd/react-scheduler-tracking-subscriptions.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @license React - * - * 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. - */ - -'use strict'; - -(function(global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' - ? (module.exports = factory(require('react'))) - : typeof define === 'function' && define.amd // eslint-disable-line no-undef - ? define(['react'], factory) // eslint-disable-line no-undef - : (global.ReactSchedulerTrackingSubscriptions = factory(global)); -})(this, function(global) { - function unstable_subscribe() { - // eslint-disable-next-line max-len - return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.unstable_subscribe.apply( - this, - arguments - ); - } - - function unstable_unsubscribe() { - // eslint-disable-next-line max-len - return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTrackingSubscriptions.unstable_unsubscribe.apply( - this, - arguments - ); - } - - return Object.freeze({ - unstable_subscribe: unstable_subscribe, - unstable_unsubscribe: unstable_unsubscribe, - }); -}); diff --git a/packages/react-scheduler/npm/umd/react-scheduler-tracking.js b/packages/react-scheduler/npm/umd/react-scheduler-tracking.js index 69f7f4a9b9571..d237e3bd820b2 100644 --- a/packages/react-scheduler/npm/umd/react-scheduler-tracking.js +++ b/packages/react-scheduler/npm/umd/react-scheduler-tracking.js @@ -51,6 +51,14 @@ ); } + function unstable_subscribe() { + // eslint-disable-next-line max-len + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_subscribe.apply( + this, + arguments + ); + } + function unstable_track() { return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_track.apply( this, @@ -58,6 +66,14 @@ ); } + function unstable_unsubscribe() { + // eslint-disable-next-line max-len + return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_unsubscribe.apply( + this, + arguments + ); + } + function unstable_wrap() { return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.SchedulerTracking.unstable_wrap.apply( this, @@ -71,7 +87,9 @@ unstable_clear: unstable_clear, unstable_getCurrent: unstable_getCurrent, unstable_getThreadID: unstable_getThreadID, + unstable_subscribe: unstable_subscribe, unstable_track: unstable_track, + unstable_unsubscribe: unstable_unsubscribe, unstable_wrap: unstable_wrap, }); }); diff --git a/packages/react-scheduler/package.json b/packages/react-scheduler/package.json index ac1a170ebed2e..3daf0c475e5ed 100644 --- a/packages/react-scheduler/package.json +++ b/packages/react-scheduler/package.json @@ -21,7 +21,6 @@ "README.md", "index.js", "tracking.js", - "tracking-subscriptions.js", "cjs/", "umd/" ] diff --git a/packages/react-scheduler/src/TrackingSubscriptions.js b/packages/react-scheduler/src/TrackingSubscriptions.js index 539213af2fdcc..4c45af957ad1d 100644 --- a/packages/react-scheduler/src/TrackingSubscriptions.js +++ b/packages/react-scheduler/src/TrackingSubscriptions.js @@ -7,25 +7,42 @@ * @flow */ -import type {Interaction, Subscriber} from './Tracking'; +import type {Interaction, Subscriber, SubscriberRef} from './Tracking'; import {enableSchedulerTracking} from 'shared/ReactFeatureFlags'; import {__getSubscriberRef} from 'react-scheduler/tracking'; +let subscriberRef: SubscriberRef = (null: any); let subscribers: Set = (null: any); if (enableSchedulerTracking) { + subscriberRef = __getSubscriberRef(); subscribers = new Set(); } export function unstable_subscribe(subscriber: Subscriber): void { if (enableSchedulerTracking) { subscribers.add(subscriber); + + if (subscribers.size === 1) { + subscriberRef.current = { + onInteractionScheduledWorkCompleted, + onInteractionTracked, + onWorkCanceled, + onWorkScheduled, + onWorkStarted, + onWorkStopped, + }; + } } } export function unstable_unsubscribe(subscriber: Subscriber): void { if (enableSchedulerTracking) { subscribers.delete(subscriber); + + if (subscribers.size === 0) { + subscriberRef.current = null; + } } } @@ -154,15 +171,3 @@ function onWorkCanceled( throw caughtError; } } - -if (enableSchedulerTracking) { - const subscriberRef = __getSubscriberRef(); - subscriberRef.current = { - onInteractionScheduledWorkCompleted, - onInteractionTracked, - onWorkCanceled, - onWorkScheduled, - onWorkStarted, - onWorkStopped, - }; -} diff --git a/packages/react-scheduler/src/__tests__/Tracking-test.internal.js b/packages/react-scheduler/src/__tests__/Tracking-test.internal.js index f64fce3ecda85..9b0e0d7108330 100644 --- a/packages/react-scheduler/src/__tests__/Tracking-test.internal.js +++ b/packages/react-scheduler/src/__tests__/Tracking-test.internal.js @@ -8,7 +8,7 @@ */ 'use strict'; -describe('SchedulerTracking', () => { +describe('Tracking', () => { let SchedulerTracking; let ReactFeatureFlags; diff --git a/packages/react-scheduler/src/__tests__/TrackingSubscriptions-test.internal.js b/packages/react-scheduler/src/__tests__/TrackingSubscriptions-test.internal.js index db7b124f65721..b346acc31d7e7 100644 --- a/packages/react-scheduler/src/__tests__/TrackingSubscriptions-test.internal.js +++ b/packages/react-scheduler/src/__tests__/TrackingSubscriptions-test.internal.js @@ -8,9 +8,8 @@ */ 'use strict'; -describe('SchedulerTrackingSubscriptions', () => { +describe('TrackingSubscriptions', () => { let SchedulerTracking; - let SchedulerTrackingSubscriptions; let ReactFeatureFlags; let currentTime; @@ -34,7 +33,7 @@ describe('SchedulerTrackingSubscriptions', () => { const secondEvent = {id: 1, name: 'second', timestamp: 0}; const threadID = 123; - function loadModules({enableSchedulerTracking}) { + function loadModules({enableSchedulerTracking, autoSubscribe = true}) { jest.resetModules(); jest.useFakeTimers(); @@ -44,7 +43,6 @@ describe('SchedulerTrackingSubscriptions', () => { ReactFeatureFlags.enableSchedulerTracking = enableSchedulerTracking; SchedulerTracking = require('react-scheduler/tracking'); - SchedulerTrackingSubscriptions = require('react-scheduler/tracking-subscriptions'); throwInOnInteractionScheduledWorkCompleted = false; throwInOnInteractionTracked = false; @@ -102,13 +100,29 @@ describe('SchedulerTrackingSubscriptions', () => { onWorkStopped: jest.fn(), }; - SchedulerTrackingSubscriptions.unstable_subscribe(firstSubscriber); - SchedulerTrackingSubscriptions.unstable_subscribe(secondSubscriber); + if (autoSubscribe) { + SchedulerTracking.unstable_subscribe(firstSubscriber); + SchedulerTracking.unstable_subscribe(secondSubscriber); + } } describe('enabled', () => { beforeEach(() => loadModules({enableSchedulerTracking: true})); + it('should lazily subscribe to tracking and unsubscribe again if there are no external subscribers', () => { + loadModules({enableSchedulerTracking: true, autoSubscribe: false}); + + expect(SchedulerTracking.__getSubscriberRef().current).toBe(null); + SchedulerTracking.unstable_subscribe(firstSubscriber); + expect(SchedulerTracking.__getSubscriberRef().current).toBeDefined(); + SchedulerTracking.unstable_subscribe(secondSubscriber); + expect(SchedulerTracking.__getSubscriberRef().current).toBeDefined(); + SchedulerTracking.unstable_unsubscribe(secondSubscriber); + expect(SchedulerTracking.__getSubscriberRef().current).toBeDefined(); + SchedulerTracking.unstable_unsubscribe(firstSubscriber); + expect(SchedulerTracking.__getSubscriberRef().current).toBe(null); + }); + describe('error handling', () => { it('should cover onInteractionTracked/onWorkStarted within', done => { SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => { @@ -598,7 +612,7 @@ describe('SchedulerTrackingSubscriptions', () => { }); it('should unsubscribe', () => { - SchedulerTrackingSubscriptions.unstable_unsubscribe(firstSubscriber); + SchedulerTracking.unstable_unsubscribe(firstSubscriber); SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {}); expect(onInteractionTracked).not.toHaveBeenCalled(); diff --git a/packages/react-scheduler/tracking-subscriptions.js b/packages/react-scheduler/tracking-subscriptions.js deleted file mode 100644 index ce17901194ea0..0000000000000 --- a/packages/react-scheduler/tracking-subscriptions.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * 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/TrackingSubscriptions'; diff --git a/packages/react-scheduler/tracking.js b/packages/react-scheduler/tracking.js index 19ce07381109f..314a84cbf6970 100644 --- a/packages/react-scheduler/tracking.js +++ b/packages/react-scheduler/tracking.js @@ -10,3 +10,4 @@ 'use strict'; export * from './src/Tracking'; +export * from './src/TrackingSubscriptions'; diff --git a/packages/react/src/ReactSharedInternals.js b/packages/react/src/ReactSharedInternals.js index 77190c6dd0c9f..a31f2fe5601b7 100644 --- a/packages/react/src/ReactSharedInternals.js +++ b/packages/react/src/ReactSharedInternals.js @@ -17,13 +17,11 @@ import { unstable_clear, unstable_getCurrent, unstable_getThreadID, + unstable_subscribe, unstable_track, + unstable_unsubscribe, unstable_wrap, } from 'react-scheduler/tracking'; -import { - unstable_subscribe, - unstable_unsubscribe, -} from 'react-scheduler/tracking-subscriptions'; import ReactCurrentOwner from './ReactCurrentOwner'; import ReactDebugCurrentFrame from './ReactDebugCurrentFrame'; @@ -51,12 +49,10 @@ if (__UMD__) { unstable_clear, unstable_getCurrent, unstable_getThreadID, - unstable_track, - unstable_wrap, - }, - SchedulerTrackingSubscriptions: { unstable_subscribe, + unstable_track, unstable_unsubscribe, + unstable_wrap, }, }); } diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 46d68dafda38f..749c6f48209e9 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -16,7 +16,6 @@ let ReactNoop; let ReactTestRenderer; let advanceTimeBy; let SchedulerTracking; -let SchedulerTrackingSubscriptions; let mockNow; let AdvanceTime; @@ -44,7 +43,6 @@ function loadModules({ React = require('react'); SchedulerTracking = require('react-scheduler/tracking'); - SchedulerTrackingSubscriptions = require('react-scheduler/tracking-subscriptions'); if (useNoopRenderer) { ReactNoop = require('react-noop-renderer'); @@ -1208,7 +1206,7 @@ describe('Profiler', () => { }); // Verify interaction subscriber methods are called as expected. - SchedulerTrackingSubscriptions.unstable_subscribe({ + SchedulerTracking.unstable_subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, @@ -1747,7 +1745,7 @@ describe('Profiler', () => { expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1); // Work might be started multiple times before being completed. - // This is okay; it's part of the react-scheduler/tracking-subscriptions contract. + // This is okay; it's part of the react-scheduler/tracking contract. expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(3); expect( getWorkForReactThreads(onWorkStarted)[1][0], @@ -2074,7 +2072,7 @@ describe('Profiler', () => { }); // Re-register since we've reloaded modules - SchedulerTrackingSubscriptions.unstable_subscribe({ + SchedulerTracking.unstable_subscribe({ onInteractionScheduledWorkCompleted, onInteractionTracked, onWorkCanceled, diff --git a/packages/shared/forks/ReactSchedulerTracking.umd.js b/packages/shared/forks/ReactSchedulerTracking.umd.js index 2d4b84ad536f6..5b66ea93e8df9 100644 --- a/packages/shared/forks/ReactSchedulerTracking.umd.js +++ b/packages/shared/forks/ReactSchedulerTracking.umd.js @@ -17,7 +17,9 @@ const { unstable_clear, unstable_getCurrent, unstable_getThreadID, + unstable_subscribe, unstable_track, + unstable_unsubscribe, unstable_wrap, } = ReactInternals.SchedulerTracking; @@ -27,6 +29,8 @@ export { unstable_clear, unstable_getCurrent, unstable_getThreadID, + unstable_subscribe, unstable_track, + unstable_unsubscribe, unstable_wrap, }; diff --git a/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js b/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js deleted file mode 100644 index 1cbf6ccee8943..0000000000000 --- a/packages/shared/forks/ReactSchedulerTrackingSubscriptions.umd.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * 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 - */ - -import React from 'react'; - -const ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -const { - unstable_subscribe, - unstable_unsubscribe, -} = ReactInternals.SchedulerTrackingSubscriptions; - -export {unstable_subscribe, unstable_unsubscribe}; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 504dc9ece0712..c35bf046f2e2b 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -405,22 +405,6 @@ const bundles = [ global: 'ReactSchedulerTracking', externals: [], }, - - { - label: 'react-scheduler-tracking-subscriptions', - bundleTypes: [ - FB_WWW_DEV, - FB_WWW_PROD, - FB_WWW_PROFILING, - NODE_DEV, - NODE_PROD, - NODE_PROFILING, - ], - moduleType: ISOMORPHIC, - entry: 'react-scheduler/tracking-subscriptions', - global: 'ReactSchedulerTrackingSubscriptions', - externals: ['react-scheduler', 'react-scheduler/tracking'], - }, ]; // Based on deep-freeze by substack (public domain) diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js index 28dbd64528afd..5ebd3cb4b1c63 100644 --- a/scripts/rollup/forks.js +++ b/scripts/rollup/forks.js @@ -154,28 +154,6 @@ const forks = Object.freeze({ } }, - 'react-scheduler/tracking-subscriptions': ( - bundleType, - entry, - dependencies - ) => { - switch (bundleType) { - case UMD_DEV: - case UMD_PROD: - if (dependencies.indexOf('react') === -1) { - // It's only safe to use this fork for modules that depend on React, - // because they read the re-exported API from the SECRET_INTERNALS object. - return null; - } - // Optimization: for UMDs, use the API that is already a part of the React - // package instead of requiring it to be loaded via a separate