Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bec2ddaf15 | ||
|
|
789e714bd7 | ||
|
|
4269fafb0a | ||
|
|
4380f9ba17 | ||
|
|
72fad84e76 | ||
|
|
39f93f7987 | ||
|
|
c3fad5acf8 | ||
|
|
dd91205617 | ||
|
|
42d12317a7 | ||
|
|
21ceb19ea0 | ||
|
|
489614c4fc | ||
|
|
351c9015c8 | ||
|
|
a210b5b440 | ||
|
|
2f54a0467b | ||
|
|
1d8a75fef0 | ||
|
|
d92114b98e | ||
|
|
0c9c591bfb | ||
|
|
9f819a5ea9 | ||
|
|
9c961c0a27 | ||
|
|
8bc0bcabe7 | ||
|
|
b488a5d9c5 | ||
|
|
4bcee56210 | ||
|
|
9a6c5ba72d | ||
|
|
72217d0819 | ||
|
|
cc66a1aa23 | ||
|
|
8b93a60c5e | ||
|
|
7a5eecc073 |
20
CHANGELOG.md
20
CHANGELOG.md
@@ -7,6 +7,24 @@
|
||||
|
||||
</details>
|
||||
|
||||
## 16.5.1 (September 13, 2018)
|
||||
|
||||
### React
|
||||
|
||||
* Improve the warning when `React.forwardRef` receives an unexpected number of arguments. ([@andresroberto](https://github.com/andresroberto) in [#13636](https://github.com/facebook/react/issues/13636))
|
||||
|
||||
### React DOM
|
||||
|
||||
* Fix a regression in unstable exports used by React Native Web. ([@aweary](https://github.com/aweary) in [#13598](https://github.com/facebook/react/issues/13598))
|
||||
* Fix a crash when component defines a method called `isReactComponent`. ([@gaearon](https://github.com/gaearon) in [#13608](https://github.com/facebook/react/issues/13608))
|
||||
* Fix a crash in development mode in IE9 when printing a warning. ([@link-alex](https://github.com/link-alex) in [#13620](https://github.com/facebook/react/issues/13620))
|
||||
* Provide a better error message when running `react-dom/profiling` with `schedule/tracking`. ([@bvaughn](https://github.com/bvaughn) in [#13605](https://github.com/facebook/react/issues/13605))
|
||||
* If a `ForwardRef` component defines a `displayName`, use it in warnings. ([@probablyup](https://github.com/probablyup) in [#13615](https://github.com/facebook/react/issues/13615))
|
||||
|
||||
### Schedule (Experimental)
|
||||
|
||||
* Add a separate profiling entry point at `schedule/tracking-profiling`. ([@bvaughn](https://github.com/bvaughn) in [#13605](https://github.com/facebook/react/issues/13605))
|
||||
|
||||
## 16.5.0 (September 5, 2018)
|
||||
|
||||
### React
|
||||
@@ -29,7 +47,7 @@
|
||||
* Fix incorrect data in `compositionend` event when typing Korean on IE11 ([@crux153](https://github.com/crux153) in [#12563](https://github.com/facebook/react/issues/12563))
|
||||
* Fix a crash when using dynamic `children` in the `<option>` tag ([@Slowyn](https://github.com/Slowyn) in [#13261](https://github.com/facebook/react/issues/13261), [@gaearon](https://github.com/gaearon) in [#13465](https://github.com/facebook/react/pull/13465))
|
||||
* Fix the `checked` attribute not getting initially set on the `input` ([@dilidili](https://github.com/dilidili) in [#13114](https://github.com/facebook/react/issues/13114))
|
||||
* Fix hydration of `dangerousSetInnerHTML` when `__html` is not a string ([@gaearon](https://github.com/gaearon) in [#13353](https://github.com/facebook/react/issues/13353))
|
||||
* Fix hydration of `dangerouslySetInnerHTML` when `__html` is not a string ([@gaearon](https://github.com/gaearon) in [#13353](https://github.com/facebook/react/issues/13353))
|
||||
* Fix a warning about missing controlled `onChange` to fire on falsy values too ([@nicolevy](https://github.com/nicolevy) in [#12628](https://github.com/facebook/react/issues/12628))
|
||||
* Fix `submit` and `reset` buttons getting an empty label ([@ellsclytn](https://github.com/ellsclytn) in [#12780](https://github.com/facebook/react/issues/12780))
|
||||
* Fix the `onSelect` event not being triggered after drag and drop ([@gaearon](https://github.com/gaearon) in [#13422](https://github.com/facebook/react/issues/13422))
|
||||
|
||||
@@ -42,51 +42,51 @@
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>browserify (dev)</h2>
|
||||
<iframe src="/fixtures/packaging/browserify/dev/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/browserify/dev/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>browserify (prod)</h2>
|
||||
<iframe src="/fixtures/packaging/browserify/prod/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/browserify/prod/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>brunch (dev)</h2>
|
||||
<iframe src="/fixtures/packaging/brunch/dev/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/brunch/dev/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>brunch (prod)</h2>
|
||||
<iframe src="/fixtures/packaging/brunch/prod/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/brunch/prod/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>rjs (dev)</h2>
|
||||
<iframe src="/fixtures/packaging/rjs/dev/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/rjs/dev/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>rjs (prod)</h2>
|
||||
<iframe src="/fixtures/packaging/rjs/prod/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/rjs/prod/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>systemjs-builder (dev)</h2>
|
||||
<iframe src="/fixtures/packaging/systemjs-builder/dev/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/systemjs-builder/dev/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>systemjs-builder (prod)</h2>
|
||||
<iframe src="/fixtures/packaging/systemjs-builder/prod/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/systemjs-builder/prod/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>webpack (dev)</h2>
|
||||
<iframe src="/fixtures/packaging/webpack/dev/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/webpack/dev/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>webpack (prod)</h2>
|
||||
<iframe src="/fixtures/packaging/webpack/prod/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/webpack/prod/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>webpack-alias (dev)</h2>
|
||||
<iframe src="/fixtures/packaging/webpack-alias/dev/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/webpack-alias/dev/"></iframe>
|
||||
</div>
|
||||
<div class="frame">
|
||||
<h2>webpack-alias (prod)</h2>
|
||||
<iframe src="/fixtures/packaging/webpack-alias/prod/index.html"></iframe>
|
||||
<iframe src="/fixtures/packaging/webpack-alias/prod/"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,7 @@
|
||||
<html style="width: 100%; height: 100%;">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test tracking UMD</title>
|
||||
<title>Test tracing UMD</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
@@ -36,9 +36,9 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test tracking UMD</h1>
|
||||
<h1>Test tracing UMD</h1>
|
||||
<p>
|
||||
This fixture tests that the new tracking API is accessible via UMD build using the UMD shim.
|
||||
This fixture tests that the new tracing API is accessible via UMD build using the UMD shim.
|
||||
It does not exhaustively test API functionality, only that the forwarded methods can be called.
|
||||
</p>
|
||||
<p>
|
||||
@@ -52,19 +52,19 @@
|
||||
<li id="checkSchedulerAPI" data-value="...">
|
||||
<strong>Test scheduler API</strong>
|
||||
</li>
|
||||
<li id="checkSchedulerTrackingAPI" data-value="...">
|
||||
<strong>Test tracking API</strong>
|
||||
<li id="checkSchedulerTracingAPI" data-value="...">
|
||||
<strong>Test tracing API</strong>
|
||||
</li>
|
||||
<li id="checkSchedulerTrackingSubscriptionsAPI" data-value="...">
|
||||
<strong>Test tracking subscriptions API</strong>
|
||||
<li id="checkSchedulerTracingSubscriptionsAPI" data-value="...">
|
||||
<strong>Test tracing subscriptions API</strong>
|
||||
</li>
|
||||
<li id="checkEndToEndIntegration" data-value="...">
|
||||
<strong>Test end-to-end integration</strong>
|
||||
</li>
|
||||
</ol>
|
||||
<!-- Load the tracking API before react to test that it's lazily evaluated -->
|
||||
<!-- Load the tracing API before react to test that it's lazily evaluated -->
|
||||
<script src="../../build/node_modules/schedule/umd/schedule.development.js"></script>
|
||||
<script src="../../build/node_modules/schedule/umd/schedule-tracking.development.js"></script>
|
||||
<script src="../../build/node_modules/schedule/umd/schedule-tracing.development.js"></script>
|
||||
<script src="../../build/node_modules/react/umd/react.development.js"></script>
|
||||
<script src="../../build/node_modules/react-dom/umd/react-dom.development.js"></script>
|
||||
<script src="./script.js"></script>
|
||||
@@ -14,10 +14,10 @@ function runAllTests() {
|
||||
checkSchedulerAPI();
|
||||
} finally {
|
||||
try {
|
||||
checkSchedulerTrackingAPI();
|
||||
checkSchedulerTracingAPI();
|
||||
} finally {
|
||||
try {
|
||||
checkSchedulerTrackingSubscriptionsAPI();
|
||||
checkSchedulerTracingSubscriptionsAPI();
|
||||
} finally {
|
||||
checkEndToEndIntegration();
|
||||
}
|
||||
@@ -44,23 +44,23 @@ function checkSchedulerAPI() {
|
||||
});
|
||||
}
|
||||
|
||||
function checkSchedulerTrackingAPI() {
|
||||
runTest(document.getElementById('checkSchedulerTrackingAPI'), () => {
|
||||
function checkSchedulerTracingAPI() {
|
||||
runTest(document.getElementById('checkSchedulerTracingAPI'), () => {
|
||||
if (
|
||||
typeof ScheduleTracking === 'undefined' ||
|
||||
typeof ScheduleTracking.unstable_clear !== 'function' ||
|
||||
typeof ScheduleTracking.unstable_getCurrent !== 'function' ||
|
||||
typeof ScheduleTracking.unstable_getThreadID !== 'function' ||
|
||||
typeof ScheduleTracking.unstable_track !== 'function' ||
|
||||
typeof ScheduleTracking.unstable_wrap !== 'function'
|
||||
typeof ScheduleTracing === 'undefined' ||
|
||||
typeof ScheduleTracing.unstable_clear !== 'function' ||
|
||||
typeof ScheduleTracing.unstable_getCurrent !== 'function' ||
|
||||
typeof ScheduleTracing.unstable_getThreadID !== 'function' ||
|
||||
typeof ScheduleTracing.unstable_trace !== 'function' ||
|
||||
typeof ScheduleTracing.unstable_wrap !== 'function'
|
||||
) {
|
||||
throw 'API is not defined';
|
||||
}
|
||||
|
||||
try {
|
||||
let interactionsSet;
|
||||
ScheduleTracking.unstable_track('test', 123, () => {
|
||||
interactionsSet = ScheduleTracking.unstable_getCurrent();
|
||||
ScheduleTracing.unstable_trace('test', 123, () => {
|
||||
interactionsSet = ScheduleTracing.unstable_getCurrent();
|
||||
});
|
||||
if (interactionsSet.size !== 1) {
|
||||
throw null;
|
||||
@@ -73,32 +73,32 @@ function checkSchedulerTrackingAPI() {
|
||||
throw 'API does not work';
|
||||
}
|
||||
|
||||
const ForwardedSchedulerTracking =
|
||||
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking;
|
||||
const ForwardedSchedulerTracing =
|
||||
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing;
|
||||
|
||||
if (
|
||||
ScheduleTracking.unstable_getThreadID() ===
|
||||
ForwardedSchedulerTracking.unstable_getThreadID()
|
||||
ScheduleTracing.unstable_getThreadID() ===
|
||||
ForwardedSchedulerTracing.unstable_getThreadID()
|
||||
) {
|
||||
throw 'API forwarding is broken';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkSchedulerTrackingSubscriptionsAPI() {
|
||||
function checkSchedulerTracingSubscriptionsAPI() {
|
||||
runTest(
|
||||
document.getElementById('checkSchedulerTrackingSubscriptionsAPI'),
|
||||
document.getElementById('checkSchedulerTracingSubscriptionsAPI'),
|
||||
() => {
|
||||
if (
|
||||
typeof ScheduleTracking === 'undefined' ||
|
||||
typeof ScheduleTracking.unstable_subscribe !== 'function' ||
|
||||
typeof ScheduleTracking.unstable_unsubscribe !== 'function'
|
||||
typeof ScheduleTracing === 'undefined' ||
|
||||
typeof ScheduleTracing.unstable_subscribe !== 'function' ||
|
||||
typeof ScheduleTracing.unstable_unsubscribe !== 'function'
|
||||
) {
|
||||
throw 'API is not defined';
|
||||
}
|
||||
|
||||
const onInteractionScheduledWorkCompletedCalls = [];
|
||||
const onInteractionTrackedCalls = [];
|
||||
const onInteractionTracedCalls = [];
|
||||
const onWorkCanceledCalls = [];
|
||||
const onWorkScheduledCalls = [];
|
||||
const onWorkStartedCalls = [];
|
||||
@@ -106,7 +106,7 @@ function checkSchedulerTrackingSubscriptionsAPI() {
|
||||
const subscriber = {
|
||||
onInteractionScheduledWorkCompleted: (...args) =>
|
||||
onInteractionScheduledWorkCompletedCalls.push(args),
|
||||
onInteractionTracked: (...args) => onInteractionTrackedCalls.push(args),
|
||||
onInteractionTraced: (...args) => onInteractionTracedCalls.push(args),
|
||||
onWorkCanceled: (...args) => onWorkCanceledCalls.push(args),
|
||||
onWorkScheduled: (...args) => onWorkScheduledCalls.push(args),
|
||||
onWorkStarted: (...args) => onWorkStartedCalls.push(args),
|
||||
@@ -114,38 +114,38 @@ function checkSchedulerTrackingSubscriptionsAPI() {
|
||||
};
|
||||
|
||||
try {
|
||||
ScheduleTracking.unstable_subscribe(subscriber);
|
||||
ScheduleTracking.unstable_track('foo', 123, () => {});
|
||||
ScheduleTracking.unstable_unsubscribe(subscriber);
|
||||
if (onInteractionTrackedCalls.length !== 1) {
|
||||
ScheduleTracing.unstable_subscribe(subscriber);
|
||||
ScheduleTracing.unstable_trace('foo', 123, () => {});
|
||||
ScheduleTracing.unstable_unsubscribe(subscriber);
|
||||
if (onInteractionTracedCalls.length !== 1) {
|
||||
throw null;
|
||||
}
|
||||
const interaction = onInteractionTrackedCalls[0][0];
|
||||
const interaction = onInteractionTracedCalls[0][0];
|
||||
if (interaction.name !== 'foo' || interaction.timestamp !== 123) {
|
||||
throw null;
|
||||
}
|
||||
ScheduleTracking.unstable_track('bar', 456, () => {});
|
||||
if (onInteractionTrackedCalls.length !== 1) {
|
||||
ScheduleTracing.unstable_trace('bar', 456, () => {});
|
||||
if (onInteractionTracedCalls.length !== 1) {
|
||||
throw null;
|
||||
}
|
||||
} catch (error) {
|
||||
throw 'API does not forward methods';
|
||||
}
|
||||
|
||||
const ForwardedSchedulerTracking =
|
||||
const ForwardedSchedulerTracing =
|
||||
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
||||
.ScheduleTracking;
|
||||
.ScheduleTracing;
|
||||
|
||||
try {
|
||||
ForwardedSchedulerTracking.unstable_subscribe(subscriber);
|
||||
ScheduleTracking.unstable_track('foo', 123, () => {});
|
||||
ForwardedSchedulerTracking.unstable_track('bar', 456, () => {});
|
||||
ScheduleTracking.unstable_unsubscribe(subscriber);
|
||||
if (onInteractionTrackedCalls.length !== 3) {
|
||||
ForwardedSchedulerTracing.unstable_subscribe(subscriber);
|
||||
ScheduleTracing.unstable_trace('foo', 123, () => {});
|
||||
ForwardedSchedulerTracing.unstable_trace('bar', 456, () => {});
|
||||
ScheduleTracing.unstable_unsubscribe(subscriber);
|
||||
if (onInteractionTracedCalls.length !== 3) {
|
||||
throw null;
|
||||
}
|
||||
const interactionFoo = onInteractionTrackedCalls[1][0];
|
||||
const interactionBar = onInteractionTrackedCalls[2][0];
|
||||
const interactionFoo = onInteractionTracedCalls[1][0];
|
||||
const interactionBar = onInteractionTracedCalls[2][0];
|
||||
if (
|
||||
interactionFoo.name !== 'foo' ||
|
||||
interactionFoo.timestamp !== 123 ||
|
||||
@@ -154,8 +154,8 @@ function checkSchedulerTrackingSubscriptionsAPI() {
|
||||
) {
|
||||
throw null;
|
||||
}
|
||||
ForwardedSchedulerTracking.unstable_track('baz', 789, () => {});
|
||||
if (onInteractionTrackedCalls.length !== 3) {
|
||||
ForwardedSchedulerTracing.unstable_trace('baz', 789, () => {});
|
||||
if (onInteractionTracedCalls.length !== 3) {
|
||||
throw null;
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -172,7 +172,7 @@ function checkEndToEndIntegration() {
|
||||
const onRender = (...args) => onRenderCalls.push(args);
|
||||
const container = document.createElement('div');
|
||||
|
||||
ScheduleTracking.unstable_track('render', 123, () => {
|
||||
ScheduleTracing.unstable_trace('render', 123, () => {
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
React.unstable_Profiler,
|
||||
@@ -1,9 +1,6 @@
|
||||
import React, {Placeholder, PureComponent} from 'react';
|
||||
import {unstable_scheduleWork} from 'schedule';
|
||||
import {
|
||||
unstable_track as track,
|
||||
unstable_wrap as wrap,
|
||||
} from 'schedule/tracking';
|
||||
import {unstable_trace as trace, unstable_wrap as wrap} from 'schedule/tracing';
|
||||
import {createResource} from 'simple-cache-provider';
|
||||
import {cache} from '../cache';
|
||||
import Spinner from './Spinner';
|
||||
@@ -32,15 +29,15 @@ export default class App extends PureComponent {
|
||||
}
|
||||
|
||||
handleUserClick = id => {
|
||||
track(`View ${id}`, performance.now(), () => {
|
||||
track(`View ${id} (high-pri)`, performance.now(), () =>
|
||||
trace(`View ${id}`, performance.now(), () => {
|
||||
trace(`View ${id} (high-pri)`, performance.now(), () =>
|
||||
this.setState({
|
||||
currentId: id,
|
||||
})
|
||||
);
|
||||
unstable_scheduleWork(
|
||||
wrap(() =>
|
||||
track(`View ${id} (low-pri)`, performance.now(), () =>
|
||||
trace(`View ${id} (low-pri)`, performance.now(), () =>
|
||||
this.setState({
|
||||
showDetail: true,
|
||||
})
|
||||
@@ -51,7 +48,7 @@ export default class App extends PureComponent {
|
||||
};
|
||||
|
||||
handleBackClick = () =>
|
||||
track('View list', performance.now(), () =>
|
||||
trace('View list', performance.now(), () =>
|
||||
this.setState({
|
||||
currentId: null,
|
||||
showDetail: false,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, {Fragment, PureComponent} from 'react';
|
||||
import {unstable_createRoot, render} from 'react-dom';
|
||||
import {unstable_track as track} from 'schedule/tracking';
|
||||
import {unstable_trace as trace} from 'schedule/tracing';
|
||||
import {cache} from './cache';
|
||||
import {
|
||||
setFakeRequestTime,
|
||||
@@ -65,7 +65,7 @@ class Debugger extends PureComponent {
|
||||
}
|
||||
|
||||
handleReset = () => {
|
||||
track('Clear cache', () => {
|
||||
trace('Clear cache', () => {
|
||||
cache.invalidate();
|
||||
this.setState(state => ({
|
||||
requests: {},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"version": "16.5.0",
|
||||
"version": "16.5.2",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "create-subscription",
|
||||
"description": "utility for subscribing to external data sources inside React components",
|
||||
"version": "16.5.0",
|
||||
"version": "16.5.2",
|
||||
"repository": "facebook/react",
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-art",
|
||||
"description": "React ART is a JavaScript library for drawing vector graphics using React. It provides declarative and reactive bindings to the ART library. Using the same declarative API you can render the output to either Canvas, SVG or VML (IE8).",
|
||||
"version": "16.5.0",
|
||||
"version": "16.5.2",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
"keywords": [
|
||||
@@ -23,7 +23,7 @@
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"schedule": "^0.3.0"
|
||||
"schedule": "^0.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-dom",
|
||||
"version": "16.5.0",
|
||||
"version": "16.5.2",
|
||||
"description": "React package for working with the DOM.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -16,7 +16,7 @@
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"schedule": "^0.3.0"
|
||||
"schedule": "^0.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0"
|
||||
|
||||
@@ -455,9 +455,11 @@ describe('ReactDOM', () => {
|
||||
try {
|
||||
delete global.requestAnimationFrame;
|
||||
jest.resetModules();
|
||||
expect(() => require('react-dom')).toWarnDev(
|
||||
spyOnDevAndProd(console, 'error');
|
||||
require('react-dom');
|
||||
expect(console.error.calls.count()).toEqual(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toMatch(
|
||||
"This browser doesn't support requestAnimationFrame.",
|
||||
{withoutStack: true},
|
||||
);
|
||||
} finally {
|
||||
global.requestAnimationFrame = previousRAF;
|
||||
|
||||
@@ -426,6 +426,46 @@ describe('ReactDOMTextarea', () => {
|
||||
ReactDOM.render(<textarea value={undefined} />, container);
|
||||
});
|
||||
|
||||
it('does not set textContent if value is unchanged', () => {
|
||||
const container = document.createElement('div');
|
||||
let node;
|
||||
let instance;
|
||||
// Setting defaultValue on a textarea is equivalent to setting textContent,
|
||||
// and is the method we currently use, so we can observe if defaultValue is
|
||||
// is set to determine if textContent is being recreated.
|
||||
// https://html.spec.whatwg.org/#the-textarea-element
|
||||
let defaultValue;
|
||||
const set = jest.fn(value => {
|
||||
defaultValue = value;
|
||||
});
|
||||
const get = jest.fn(value => {
|
||||
return defaultValue;
|
||||
});
|
||||
class App extends React.Component {
|
||||
state = {count: 0, text: 'foo'};
|
||||
componentDidMount() {
|
||||
instance = this;
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>{this.state.count}</span>
|
||||
<textarea
|
||||
ref={n => (node = n)}
|
||||
value="foo"
|
||||
onChange={emptyFunction}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
ReactDOM.render(<App />, container);
|
||||
defaultValue = node.defaultValue;
|
||||
Object.defineProperty(node, 'defaultValue', {get, set});
|
||||
instance.setState({count: 1});
|
||||
expect(set.mock.calls.length).toBe(0);
|
||||
});
|
||||
|
||||
describe('When given a Symbol value', () => {
|
||||
it('treats initial Symbol value as an empty string', () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
@@ -302,7 +302,7 @@ describe('ReactMount', () => {
|
||||
ReactDOM.render(<Foo>a</Foo>, container2);
|
||||
// The update did not flush yet.
|
||||
expect(container1.textContent).toEqual('1');
|
||||
// The initial mount flushed, but not the update scheduled in cDU.
|
||||
// The initial mount flushed, but not the update scheduled in cDM.
|
||||
expect(container2.textContent).toEqual('a');
|
||||
});
|
||||
// All updates have flushed.
|
||||
|
||||
@@ -152,7 +152,7 @@ export function getModernOffsetsFromPoints(
|
||||
*/
|
||||
export function setOffsets(node, offsets) {
|
||||
const doc = node.ownerDocument || document;
|
||||
const win = doc ? doc.defaultView : window;
|
||||
const win = (doc && doc.defaultView) || window;
|
||||
const selection = win.getSelection();
|
||||
const length = node.textContent.length;
|
||||
let start = Math.min(offsets.start, length);
|
||||
|
||||
@@ -128,6 +128,7 @@ export function initWrapperState(element: Element, props: Object) {
|
||||
export function updateWrapper(element: Element, props: Object) {
|
||||
const node = ((element: any): TextAreaWithWrapperState);
|
||||
const value = getToStringValue(props.value);
|
||||
const defaultValue = getToStringValue(props.defaultValue);
|
||||
if (value != null) {
|
||||
// Cast `value` to a string to ensure the value is set correctly. While
|
||||
// browsers typically do this as necessary, jsdom doesn't.
|
||||
@@ -136,12 +137,12 @@ export function updateWrapper(element: Element, props: Object) {
|
||||
if (newValue !== node.value) {
|
||||
node.value = newValue;
|
||||
}
|
||||
if (props.defaultValue == null) {
|
||||
if (props.defaultValue == null && node.defaultValue !== newValue) {
|
||||
node.defaultValue = newValue;
|
||||
}
|
||||
}
|
||||
if (props.defaultValue != null) {
|
||||
node.defaultValue = toString(getToStringValue(props.defaultValue));
|
||||
if (defaultValue != null) {
|
||||
node.defaultValue = toString(defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-is",
|
||||
"version": "16.5.0",
|
||||
"version": "16.5.2",
|
||||
"description": "Brand checking of React Elements.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"dependencies": {
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"schedule": "^0.3.0"
|
||||
"schedule": "^0.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-reconciler",
|
||||
"description": "React package for creating custom renderers.",
|
||||
"version": "0.13.0",
|
||||
"version": "0.15.0",
|
||||
"keywords": [
|
||||
"react"
|
||||
],
|
||||
@@ -28,7 +28,7 @@
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"schedule": "^0.3.0"
|
||||
"schedule": "^0.5.0"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
|
||||
@@ -20,7 +20,7 @@ import type {ExpirationTime} from './ReactFiberExpirationTime';
|
||||
import type {CapturedValue, CapturedError} from './ReactCapturedValue';
|
||||
|
||||
import {
|
||||
enableSchedulerTracking,
|
||||
enableSchedulerTracing,
|
||||
enableProfilerTimer,
|
||||
enableSuspense,
|
||||
} from 'shared/ReactFeatureFlags';
|
||||
@@ -329,7 +329,7 @@ function commitLifeCycles(
|
||||
if (enableProfilerTimer) {
|
||||
const onRender = finishedWork.memoizedProps.onRender;
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
onRender(
|
||||
finishedWork.memoizedProps.id,
|
||||
current === null ? 'mount' : 'update',
|
||||
|
||||
20
packages/react-reconciler/src/ReactFiberRoot.js
vendored
20
packages/react-reconciler/src/ReactFiberRoot.js
vendored
@@ -10,13 +10,13 @@
|
||||
import type {Fiber} from './ReactFiber';
|
||||
import type {ExpirationTime} from './ReactFiberExpirationTime';
|
||||
import type {TimeoutHandle, NoTimeout} from './ReactFiberHostConfig';
|
||||
import type {Interaction} from 'schedule/src/Tracking';
|
||||
import type {Interaction} from 'schedule/src/Tracing';
|
||||
|
||||
import {noTimeout} from './ReactFiberHostConfig';
|
||||
import {createHostRootFiber} from './ReactFiber';
|
||||
import {NoWork} from './ReactFiberExpirationTime';
|
||||
import {enableSchedulerTracking} from 'shared/ReactFeatureFlags';
|
||||
import {unstable_getThreadID} from 'schedule/tracking';
|
||||
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
|
||||
import {unstable_getThreadID} from 'schedule/tracing';
|
||||
|
||||
/* eslint-disable no-use-before-define */
|
||||
// TODO: This should be lifted into the renderer.
|
||||
@@ -80,10 +80,10 @@ type BaseFiberRootProperties = {|
|
||||
nextScheduledRoot: FiberRoot | null,
|
||||
|};
|
||||
|
||||
// The following attributes are only used by interaction tracking builds.
|
||||
// The following attributes are only used by interaction tracing 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 enableSchedulerTracking flag is enabled.
|
||||
// Note that these attributes are only defined when the enableSchedulerTracing flag is enabled.
|
||||
type ProfilingOnlyFiberRootProperties = {|
|
||||
interactionThreadID: number,
|
||||
memoizedInteractions: Set<Interaction>,
|
||||
@@ -92,9 +92,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 enableSchedulerTracking is true).
|
||||
// Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing 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 enableSchedulerTracking is disabled.)
|
||||
// (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.)
|
||||
export type FiberRoot = {
|
||||
...BaseFiberRootProperties,
|
||||
...ProfilingOnlyFiberRootProperties,
|
||||
@@ -111,7 +111,7 @@ export function createFiberRoot(
|
||||
const uninitializedFiber = createHostRootFiber(isAsync);
|
||||
|
||||
let root;
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
root = ({
|
||||
current: uninitializedFiber,
|
||||
containerInfo: containerInfo,
|
||||
@@ -170,8 +170,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 tracing fields are used.
|
||||
// Unfortunately that requires an :any cast for non-interaction tracing capable builds.
|
||||
// $FlowFixMe Remove this :any cast and replace it with something better.
|
||||
return ((root: any): FiberRoot);
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
import type {Fiber} from './ReactFiber';
|
||||
import type {Batch, FiberRoot} from './ReactFiberRoot';
|
||||
import type {ExpirationTime} from './ReactFiberExpirationTime';
|
||||
import type {Interaction} from 'schedule/src/Tracking';
|
||||
import type {Interaction} from 'schedule/src/Tracing';
|
||||
|
||||
import {__interactionsRef, __subscriberRef} from 'schedule/tracking';
|
||||
import {__interactionsRef, __subscriberRef} from 'schedule/tracing';
|
||||
import {
|
||||
invokeGuardedCallback,
|
||||
hasCaughtError,
|
||||
@@ -44,7 +44,7 @@ import {
|
||||
HostPortal,
|
||||
} from 'shared/ReactWorkTags';
|
||||
import {
|
||||
enableSchedulerTracking,
|
||||
enableSchedulerTracing,
|
||||
enableProfilerTimer,
|
||||
enableUserTimingAPI,
|
||||
replayFailedUnitOfWorkWithInvokeGuardedCallback,
|
||||
@@ -153,7 +153,7 @@ import {
|
||||
import {Dispatcher} from './ReactFiberDispatcher';
|
||||
|
||||
export type Deadline = {
|
||||
timeRemaining: () => number,
|
||||
timeRemaining(): number,
|
||||
didTimeout: boolean,
|
||||
};
|
||||
|
||||
@@ -168,13 +168,13 @@ let didWarnSetStateChildContext;
|
||||
let warnAboutUpdateOnUnmounted;
|
||||
let warnAboutInvalidUpdates;
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
// Provide explicit error message when production+profiling bundle of e.g. react-dom
|
||||
// is used with production (non-profiling) bundle of schedule/tracking
|
||||
// is used with production (non-profiling) bundle of schedule/tracing
|
||||
invariant(
|
||||
__interactionsRef != null && __interactionsRef.current != null,
|
||||
'It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) ' +
|
||||
'without also replacing the `schedule/tracking` module with `schedule/tracking-profiling`. ' +
|
||||
'without also replacing the `schedule/tracing` module with `schedule/tracing-profiling`. ' +
|
||||
'Your bundler might have a setting for aliasing both modules. ' +
|
||||
'Learn more at http://fb.me/react-profiling',
|
||||
);
|
||||
@@ -566,10 +566,10 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
|
||||
markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit);
|
||||
|
||||
let prevInteractions: Set<Interaction> = (null: any);
|
||||
let committedInteractions: Array<Interaction> = enableSchedulerTracking
|
||||
let committedInteractions: Array<Interaction> = enableSchedulerTracing
|
||||
? []
|
||||
: (null: any);
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
// Restore any pending interactions at this point,
|
||||
// So that cascading work triggered during the render phase will be accounted for.
|
||||
prevInteractions = __interactionsRef.current;
|
||||
@@ -767,7 +767,7 @@ function commitRoot(root: FiberRoot, finishedWork: Fiber): void {
|
||||
}
|
||||
onCommit(root, earliestRemainingTimeAfterCommit);
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
__interactionsRef.current = prevInteractions;
|
||||
|
||||
let subscriber;
|
||||
@@ -1175,8 +1175,8 @@ function renderRoot(
|
||||
const expirationTime = root.nextExpirationTimeToWorkOn;
|
||||
|
||||
let prevInteractions: Set<Interaction> = (null: any);
|
||||
if (enableSchedulerTracking) {
|
||||
// We're about to start new tracked work.
|
||||
if (enableSchedulerTracing) {
|
||||
// We're about to start new traced work.
|
||||
// Restore pending interactions so cascading work triggered during the render phase will be accounted for.
|
||||
prevInteractions = __interactionsRef.current;
|
||||
__interactionsRef.current = root.memoizedInteractions;
|
||||
@@ -1200,7 +1200,7 @@ function renderRoot(
|
||||
);
|
||||
root.pendingCommitExpirationTime = NoWork;
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
// 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.
|
||||
@@ -1231,7 +1231,7 @@ function renderRoot(
|
||||
try {
|
||||
subscriber.onWorkStarted(interactions, threadID);
|
||||
} catch (error) {
|
||||
// Work thrown by an interaction tracking subscriber should be rethrown,
|
||||
// Work thrown by an interaction tracing 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) {
|
||||
@@ -1305,8 +1305,8 @@ function renderRoot(
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
// Tracked work is done for now; restore the previous interactions.
|
||||
if (enableSchedulerTracing) {
|
||||
// Traced work is done for now; restore the previous interactions.
|
||||
__interactionsRef.current = prevInteractions;
|
||||
}
|
||||
|
||||
@@ -1614,7 +1614,7 @@ function retrySuspendedRoot(
|
||||
scheduleWorkToRoot(fiber, retryTime);
|
||||
const rootExpirationTime = root.expirationTime;
|
||||
if (rootExpirationTime !== NoWork) {
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
// Restore previous interactions so that new work is associated with them.
|
||||
let prevInteractions = __interactionsRef.current;
|
||||
__interactionsRef.current = root.memoizedInteractions;
|
||||
@@ -1685,7 +1685,7 @@ function storeInteractionsForExpirationTime(
|
||||
expirationTime: ExpirationTime,
|
||||
updateInteractionCounts: boolean,
|
||||
): void {
|
||||
if (!enableSchedulerTracking) {
|
||||
if (!enableSchedulerTracing) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1744,7 +1744,7 @@ function scheduleWork(fiber: Fiber, expirationTime: ExpirationTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
storeInteractionsForExpirationTime(root, expirationTime, true);
|
||||
}
|
||||
|
||||
@@ -1935,7 +1935,7 @@ function onTimeout(root, finishedWork, suspendedExpirationTime) {
|
||||
recomputeCurrentRendererTime();
|
||||
currentSchedulerTime = currentRendererTime;
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
// Don't update pending interaction counts for suspense timeouts,
|
||||
// Because we know we still need to do more work in this case.
|
||||
suspenseDidTimeout = true;
|
||||
@@ -2506,7 +2506,7 @@ function flushControlled(fn: () => mixed): void {
|
||||
} finally {
|
||||
isBatchingUpdates = previousIsBatchingUpdates;
|
||||
if (!isBatchingUpdates && !isRendering) {
|
||||
performWork(Sync, null);
|
||||
performSyncWork();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
describe('ReactTracking', () => {
|
||||
it('should error if profiling renderer and non-profiling schedule/tracking bundles are combined', () => {
|
||||
describe('ReactTracing', () => {
|
||||
it('should error if profiling renderer and non-profiling schedule/tracing bundles are combined', () => {
|
||||
jest.resetModules();
|
||||
|
||||
const ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableSchedulerTracking = false;
|
||||
ReactFeatureFlags.enableSchedulerTracing = false;
|
||||
|
||||
require('schedule/tracking');
|
||||
require('schedule/tracing');
|
||||
|
||||
ReactFeatureFlags.enableSchedulerTracking = true;
|
||||
ReactFeatureFlags.enableSchedulerTracing = true;
|
||||
|
||||
expect(() => require('react-dom')).toThrow(
|
||||
'Learn more at http://fb.me/react-profiling',
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-test-renderer",
|
||||
"version": "16.5.0",
|
||||
"version": "16.5.2",
|
||||
"description": "React package for snapshot testing.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -17,8 +17,8 @@
|
||||
"dependencies": {
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react-is": "^16.5.0",
|
||||
"schedule": "^0.3.0"
|
||||
"react-is": "^16.5.2",
|
||||
"schedule": "^0.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"keywords": [
|
||||
"react"
|
||||
],
|
||||
"version": "16.5.0",
|
||||
"version": "16.5.2",
|
||||
"homepage": "https://reactjs.org/",
|
||||
"bugs": "https://github.com/facebook/react/issues",
|
||||
"license": "MIT",
|
||||
@@ -24,7 +24,7 @@
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"schedule": "^0.3.0"
|
||||
"schedule": "^0.5.0"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
|
||||
@@ -18,10 +18,10 @@ import {
|
||||
unstable_getCurrent,
|
||||
unstable_getThreadID,
|
||||
unstable_subscribe,
|
||||
unstable_track,
|
||||
unstable_trace,
|
||||
unstable_unsubscribe,
|
||||
unstable_wrap,
|
||||
} from 'schedule/tracking';
|
||||
} from 'schedule/tracing';
|
||||
import ReactCurrentOwner from './ReactCurrentOwner';
|
||||
import ReactDebugCurrentFrame from './ReactDebugCurrentFrame';
|
||||
|
||||
@@ -43,14 +43,14 @@ if (__UMD__) {
|
||||
unstable_now,
|
||||
unstable_scheduleWork,
|
||||
},
|
||||
ScheduleTracking: {
|
||||
ScheduleTracing: {
|
||||
__interactionsRef,
|
||||
__subscriberRef,
|
||||
unstable_clear,
|
||||
unstable_getCurrent,
|
||||
unstable_getThreadID,
|
||||
unstable_subscribe,
|
||||
unstable_track,
|
||||
unstable_trace,
|
||||
unstable_unsubscribe,
|
||||
unstable_wrap,
|
||||
},
|
||||
|
||||
@@ -15,14 +15,14 @@ let ReactFeatureFlags;
|
||||
let ReactNoop;
|
||||
let ReactTestRenderer;
|
||||
let advanceTimeBy;
|
||||
let SchedulerTracking;
|
||||
let SchedulerTracing;
|
||||
let mockNow;
|
||||
let AdvanceTime;
|
||||
|
||||
function loadModules({
|
||||
enableProfilerTimer = true,
|
||||
enableSuspense = false,
|
||||
enableSchedulerTracking = true,
|
||||
enableSchedulerTracing = true,
|
||||
replayFailedUnitOfWorkWithInvokeGuardedCallback = false,
|
||||
useNoopRenderer = false,
|
||||
} = {}) {
|
||||
@@ -37,12 +37,12 @@ function loadModules({
|
||||
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
ReactFeatureFlags.enableProfilerTimer = enableProfilerTimer;
|
||||
ReactFeatureFlags.enableGetDerivedStateFromCatch = true;
|
||||
ReactFeatureFlags.enableSchedulerTracking = enableSchedulerTracking;
|
||||
ReactFeatureFlags.enableSchedulerTracing = enableSchedulerTracing;
|
||||
ReactFeatureFlags.enableSuspense = enableSuspense;
|
||||
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = replayFailedUnitOfWorkWithInvokeGuardedCallback;
|
||||
|
||||
React = require('react');
|
||||
SchedulerTracking = require('schedule/tracking');
|
||||
SchedulerTracing = require('schedule/tracing');
|
||||
|
||||
if (useNoopRenderer) {
|
||||
ReactNoop = require('react-noop-renderer');
|
||||
@@ -82,17 +82,17 @@ const mockDevToolsForTest = () => {
|
||||
|
||||
describe('Profiler', () => {
|
||||
describe('works in profiling and non-profiling bundles', () => {
|
||||
[true, false].forEach(enableSchedulerTracking => {
|
||||
[true, false].forEach(enableSchedulerTracing => {
|
||||
[true, false].forEach(enableProfilerTimer => {
|
||||
describe(`enableSchedulerTracking:${
|
||||
enableSchedulerTracking ? 'enabled' : 'disabled'
|
||||
describe(`enableSchedulerTracing:${
|
||||
enableSchedulerTracing ? 'enabled' : 'disabled'
|
||||
} enableProfilerTimer:${
|
||||
enableProfilerTimer ? 'enabled' : 'disabled'
|
||||
}`, () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
loadModules({enableSchedulerTracking, enableProfilerTimer});
|
||||
loadModules({enableSchedulerTracing, enableProfilerTimer});
|
||||
});
|
||||
|
||||
// This will throw in production too,
|
||||
@@ -165,12 +165,12 @@ describe('Profiler', () => {
|
||||
});
|
||||
});
|
||||
|
||||
[true, false].forEach(enableSchedulerTracking => {
|
||||
[true, false].forEach(enableSchedulerTracing => {
|
||||
describe('onRender callback', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
loadModules({enableSchedulerTracking});
|
||||
loadModules({enableSchedulerTracing});
|
||||
});
|
||||
|
||||
it('should handle errors thrown', () => {
|
||||
@@ -265,16 +265,14 @@ describe('Profiler', () => {
|
||||
|
||||
let [call] = callback.mock.calls;
|
||||
|
||||
expect(call).toHaveLength(enableSchedulerTracking ? 7 : 6);
|
||||
expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6);
|
||||
expect(call[0]).toBe('test');
|
||||
expect(call[1]).toBe('mount');
|
||||
expect(call[2]).toBe(10); // actual time
|
||||
expect(call[3]).toBe(10); // base time
|
||||
expect(call[4]).toBe(5); // start time
|
||||
expect(call[5]).toBe(15); // commit time
|
||||
expect(call[6]).toEqual(
|
||||
enableSchedulerTracking ? new Set() : undefined,
|
||||
); // interaction events
|
||||
expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events
|
||||
|
||||
callback.mockReset();
|
||||
|
||||
@@ -290,16 +288,14 @@ describe('Profiler', () => {
|
||||
|
||||
[call] = callback.mock.calls;
|
||||
|
||||
expect(call).toHaveLength(enableSchedulerTracking ? 7 : 6);
|
||||
expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6);
|
||||
expect(call[0]).toBe('test');
|
||||
expect(call[1]).toBe('update');
|
||||
expect(call[2]).toBe(10); // actual time
|
||||
expect(call[3]).toBe(10); // base time
|
||||
expect(call[4]).toBe(35); // start time
|
||||
expect(call[5]).toBe(45); // commit time
|
||||
expect(call[6]).toEqual(
|
||||
enableSchedulerTracking ? new Set() : undefined,
|
||||
); // interaction events
|
||||
expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events
|
||||
|
||||
callback.mockReset();
|
||||
|
||||
@@ -315,16 +311,14 @@ describe('Profiler', () => {
|
||||
|
||||
[call] = callback.mock.calls;
|
||||
|
||||
expect(call).toHaveLength(enableSchedulerTracking ? 7 : 6);
|
||||
expect(call).toHaveLength(enableSchedulerTracing ? 7 : 6);
|
||||
expect(call[0]).toBe('test');
|
||||
expect(call[1]).toBe('update');
|
||||
expect(call[2]).toBe(4); // actual time
|
||||
expect(call[3]).toBe(4); // base time
|
||||
expect(call[4]).toBe(65); // start time
|
||||
expect(call[5]).toBe(69); // commit time
|
||||
expect(call[6]).toEqual(
|
||||
enableSchedulerTracking ? new Set() : undefined,
|
||||
); // interaction events
|
||||
expect(call[6]).toEqual(enableSchedulerTracing ? new Set() : undefined); // interaction events
|
||||
});
|
||||
|
||||
it('includes render times of nested Profilers in their parent times', () => {
|
||||
@@ -362,7 +356,7 @@ describe('Profiler', () => {
|
||||
expect(parentCall[5]).toBe(35); // commit time
|
||||
});
|
||||
|
||||
it('tracks sibling Profilers separately', () => {
|
||||
it('traces sibling Profilers separately', () => {
|
||||
const callback = jest.fn();
|
||||
|
||||
advanceTimeBy(5); // 0 -> 5
|
||||
@@ -1220,9 +1214,9 @@ describe('Profiler', () => {
|
||||
expect(ReactNoop.getRoot('two').current.actualDuration).toBe(14);
|
||||
});
|
||||
|
||||
describe('interaction tracking', () => {
|
||||
describe('interaction tracing', () => {
|
||||
let onInteractionScheduledWorkCompleted;
|
||||
let onInteractionTracked;
|
||||
let onInteractionTraced;
|
||||
let onWorkCanceled;
|
||||
let onWorkScheduled;
|
||||
let onWorkStarted;
|
||||
@@ -1239,7 +1233,7 @@ describe('Profiler', () => {
|
||||
jest.resetModules();
|
||||
|
||||
loadModules({
|
||||
enableSchedulerTracking: true,
|
||||
enableSchedulerTracing: true,
|
||||
});
|
||||
|
||||
throwInOnInteractionScheduledWorkCompleted = false;
|
||||
@@ -1252,7 +1246,7 @@ describe('Profiler', () => {
|
||||
throw Error('Expected error onInteractionScheduledWorkCompleted');
|
||||
}
|
||||
});
|
||||
onInteractionTracked = jest.fn();
|
||||
onInteractionTraced = jest.fn();
|
||||
onWorkCanceled = jest.fn();
|
||||
onWorkScheduled = jest.fn(() => {
|
||||
if (throwInOnWorkScheduled) {
|
||||
@@ -1271,9 +1265,9 @@ describe('Profiler', () => {
|
||||
});
|
||||
|
||||
// Verify interaction subscriber methods are called as expected.
|
||||
SchedulerTracking.unstable_subscribe({
|
||||
SchedulerTracing.unstable_subscribe({
|
||||
onInteractionScheduledWorkCompleted,
|
||||
onInteractionTracked,
|
||||
onInteractionTraced,
|
||||
onWorkCanceled,
|
||||
onWorkScheduled,
|
||||
onWorkStarted,
|
||||
@@ -1293,7 +1287,7 @@ describe('Profiler', () => {
|
||||
// Errors that happen inside of a subscriber should throw,
|
||||
throwInOnWorkScheduled = true;
|
||||
expect(() => {
|
||||
SchedulerTracking.unstable_track('event', mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace('event', mockNow(), () => {
|
||||
renderer = ReactTestRenderer.create(<Component>fail</Component>, {
|
||||
unstable_isAsync: true,
|
||||
});
|
||||
@@ -1319,7 +1313,7 @@ describe('Profiler', () => {
|
||||
}
|
||||
|
||||
let renderer;
|
||||
SchedulerTracking.unstable_track('event', mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace('event', mockNow(), () => {
|
||||
renderer = ReactTestRenderer.create(<Component>text</Component>, {
|
||||
unstable_isAsync: true,
|
||||
});
|
||||
@@ -1348,7 +1342,7 @@ describe('Profiler', () => {
|
||||
}
|
||||
|
||||
let renderer;
|
||||
SchedulerTracking.unstable_track('event', mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace('event', mockNow(), () => {
|
||||
renderer = ReactTestRenderer.create(<Component>text</Component>, {
|
||||
unstable_isAsync: true,
|
||||
});
|
||||
@@ -1390,8 +1384,8 @@ describe('Profiler', () => {
|
||||
};
|
||||
|
||||
let renderer;
|
||||
SchedulerTracking.unstable_track(eventOne.name, mockNow(), () => {
|
||||
SchedulerTracking.unstable_track(eventTwo.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(eventOne.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(eventTwo.name, mockNow(), () => {
|
||||
renderer = ReactTestRenderer.create(<Component>text</Component>, {
|
||||
unstable_isAsync: true,
|
||||
});
|
||||
@@ -1410,7 +1404,7 @@ describe('Profiler', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should associate tracked events with their subsequent commits', () => {
|
||||
it('should associate traced events with their subsequent commits', () => {
|
||||
let instance = null;
|
||||
|
||||
const Yield = ({duration = 10, value}) => {
|
||||
@@ -1445,7 +1439,7 @@ describe('Profiler', () => {
|
||||
|
||||
const onRender = jest.fn();
|
||||
let renderer;
|
||||
SchedulerTracking.unstable_track(
|
||||
SchedulerTracing.unstable_trace(
|
||||
interactionCreation.name,
|
||||
mockNow(),
|
||||
() => {
|
||||
@@ -1460,13 +1454,13 @@ describe('Profiler', () => {
|
||||
},
|
||||
);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interactionCreation,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
// The schedule/tracking package will notify of work started for the default thread,
|
||||
// The schedule/tracing 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);
|
||||
@@ -1486,11 +1480,11 @@ describe('Profiler', () => {
|
||||
let call = onRender.mock.calls[0];
|
||||
expect(call[0]).toEqual('test-profiler');
|
||||
expect(call[5]).toEqual(mockNow());
|
||||
if (ReactFeatureFlags.enableSchedulerTracking) {
|
||||
if (ReactFeatureFlags.enableSchedulerTracing) {
|
||||
expect(call[6]).toMatchInteractions([interactionCreation]);
|
||||
}
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -1518,13 +1512,13 @@ describe('Profiler', () => {
|
||||
name: 'initial event',
|
||||
timestamp: mockNow(),
|
||||
};
|
||||
SchedulerTracking.unstable_track(interactionOne.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(interactionOne.name, mockNow(), () => {
|
||||
instance.setState({count: 1});
|
||||
|
||||
// Update state again to verify our tracked interaction isn't registered twice
|
||||
// Update state again to verify our traced interaction isn't registered twice
|
||||
instance.setState({count: 2});
|
||||
|
||||
// The schedule/tracking package will notify of work started for the default thread,
|
||||
// The schedule/tracing 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);
|
||||
@@ -1541,8 +1535,8 @@ describe('Profiler', () => {
|
||||
expect(renderer).toFlushThrough(['first']);
|
||||
expect(onRender).not.toHaveBeenCalled();
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interactionOne,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
@@ -1558,7 +1552,7 @@ describe('Profiler', () => {
|
||||
call = onRender.mock.calls[0];
|
||||
expect(call[0]).toEqual('test-profiler');
|
||||
expect(call[5]).toEqual(mockNow());
|
||||
if (ReactFeatureFlags.enableSchedulerTracking) {
|
||||
if (ReactFeatureFlags.enableSchedulerTracing) {
|
||||
expect(call[6]).toMatchInteractions([interactionOne]);
|
||||
}
|
||||
|
||||
@@ -1591,11 +1585,11 @@ describe('Profiler', () => {
|
||||
call = onRender.mock.calls[0];
|
||||
expect(call[0]).toEqual('test-profiler');
|
||||
expect(call[5]).toEqual(mockNow());
|
||||
if (ReactFeatureFlags.enableSchedulerTracking) {
|
||||
if (ReactFeatureFlags.enableSchedulerTracing) {
|
||||
expect(call[6]).toMatchInteractions([]);
|
||||
}
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -1607,13 +1601,13 @@ describe('Profiler', () => {
|
||||
|
||||
advanceTimeBy(3);
|
||||
|
||||
// Verify that root updates are also associated with tracked events.
|
||||
// Verify that root updates are also associated with traced events.
|
||||
const interactionTwo = {
|
||||
id: 2,
|
||||
name: 'root update event',
|
||||
timestamp: mockNow(),
|
||||
};
|
||||
SchedulerTracking.unstable_track(interactionTwo.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(interactionTwo.name, mockNow(), () => {
|
||||
renderer.update(
|
||||
<React.unstable_Profiler id="test-profiler" onRender={onRender}>
|
||||
<Example />
|
||||
@@ -1621,13 +1615,13 @@ describe('Profiler', () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interactionTwo,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2);
|
||||
|
||||
// The schedule/tracking package will notify of work started for the default thread,
|
||||
// The schedule/tracing 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);
|
||||
@@ -1647,11 +1641,11 @@ describe('Profiler', () => {
|
||||
call = onRender.mock.calls[0];
|
||||
expect(call[0]).toEqual('test-profiler');
|
||||
expect(call[5]).toEqual(mockNow());
|
||||
if (ReactFeatureFlags.enableSchedulerTracking) {
|
||||
if (ReactFeatureFlags.enableSchedulerTracing) {
|
||||
expect(call[6]).toMatchInteractions([interactionTwo]);
|
||||
}
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(3);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -1701,7 +1695,7 @@ describe('Profiler', () => {
|
||||
// Initial mount.
|
||||
renderer.unstable_flushAll(['FirstComponent', 'SecondComponent']);
|
||||
|
||||
expect(onInteractionTracked).not.toHaveBeenCalled();
|
||||
expect(onInteractionTraced).not.toHaveBeenCalled();
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
onRender.mockClear();
|
||||
@@ -1714,121 +1708,115 @@ describe('Profiler', () => {
|
||||
timestamp: mockNow(),
|
||||
};
|
||||
|
||||
SchedulerTracking.unstable_track(
|
||||
interactionLowPri.name,
|
||||
mockNow(),
|
||||
() => {
|
||||
// Render a partially update, but don't finish.
|
||||
first.setState({count: 1});
|
||||
SchedulerTracing.unstable_trace(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(onWorkScheduled).toHaveBeenCalled();
|
||||
expect(onWorkScheduled.mock.calls[0][0]).toMatchInteractions([
|
||||
interactionLowPri,
|
||||
]);
|
||||
|
||||
expect(renderer).toFlushThrough(['FirstComponent']);
|
||||
expect(onRender).not.toHaveBeenCalled();
|
||||
expect(renderer).toFlushThrough(['FirstComponent']);
|
||||
expect(onRender).not.toHaveBeenCalled();
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
interactionLowPri,
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).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(),
|
||||
};
|
||||
|
||||
// Interrupt with higher priority work.
|
||||
// This simulates a total of 37ms of actual render time.
|
||||
renderer.unstable_flushSync(() => {
|
||||
SchedulerTracing.unstable_trace(
|
||||
interactionHighPri.name,
|
||||
mockNow(),
|
||||
() => {
|
||||
second.setState({count: 1});
|
||||
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).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(onWorkStarted)[0][0],
|
||||
).toMatchInteractions([interactionLowPri]);
|
||||
expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0);
|
||||
});
|
||||
expect(ReactTestRenderer).toClearYields(['SecondComponent']);
|
||||
|
||||
advanceTimeBy(100);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
).toHaveBeenLastNotifiedOfInteraction(interactionHighPri);
|
||||
|
||||
const interactionHighPri = {
|
||||
id: 1,
|
||||
name: 'highPri',
|
||||
timestamp: mockNow(),
|
||||
};
|
||||
// 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.enableSchedulerTracing
|
||||
? [interactionLowPri, interactionHighPri]
|
||||
: [],
|
||||
);
|
||||
|
||||
// Interrupt with higher priority work.
|
||||
// This simulates a total of 37ms of actual render time.
|
||||
renderer.unstable_flushSync(() => {
|
||||
SchedulerTracking.unstable_track(
|
||||
interactionHighPri.name,
|
||||
mockNow(),
|
||||
() => {
|
||||
second.setState({count: 1});
|
||||
onRender.mockClear();
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
onInteractionTracked,
|
||||
).toHaveBeenLastNotifiedOfInteraction(interactionHighPri);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
).not.toHaveBeenCalled();
|
||||
advanceTimeBy(100);
|
||||
|
||||
expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(1);
|
||||
expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(0);
|
||||
},
|
||||
);
|
||||
});
|
||||
expect(ReactTestRenderer).toClearYields(['SecondComponent']);
|
||||
// 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.enableSchedulerTracing ? [interactionLowPri] : [],
|
||||
);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
).toHaveBeenLastNotifiedOfInteraction(interactionHighPri);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
|
||||
// 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.enableSchedulerTracking
|
||||
? [interactionLowPri, interactionHighPri]
|
||||
: [],
|
||||
);
|
||||
// Work might be started multiple times before being completed.
|
||||
// This is okay; it's part of the schedule/tracing 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],
|
||||
);
|
||||
});
|
||||
|
||||
onRender.mockClear();
|
||||
|
||||
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.enableSchedulerTracking
|
||||
? [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 schedule/tracking 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(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -1837,7 +1825,7 @@ describe('Profiler', () => {
|
||||
expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should track work spawned by a commit phase lifecycle and setState callback', () => {
|
||||
it('should trace work spawned by a commit phase lifecycle and setState callback', () => {
|
||||
let instance;
|
||||
class Example extends React.Component {
|
||||
state = {
|
||||
@@ -1870,7 +1858,7 @@ describe('Profiler', () => {
|
||||
const onRender = jest.fn();
|
||||
let firstCommitTime = mockNow();
|
||||
let renderer;
|
||||
SchedulerTracking.unstable_track(interactionOne.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(interactionOne.name, mockNow(), () => {
|
||||
renderer = ReactTestRenderer.create(
|
||||
<React.unstable_Profiler id="test" onRender={onRender}>
|
||||
<Example />
|
||||
@@ -1879,8 +1867,8 @@ describe('Profiler', () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interactionOne,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
@@ -1889,7 +1877,7 @@ describe('Profiler', () => {
|
||||
|
||||
renderer.unstable_flushAll(['Example:0', 'Example:1']);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -1914,13 +1902,13 @@ describe('Profiler', () => {
|
||||
expect(call[0]).toEqual('test');
|
||||
expect(call[5]).toEqual(firstCommitTime);
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interactionOne] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interactionOne] : [],
|
||||
);
|
||||
call = onRender.mock.calls[1];
|
||||
expect(call[0]).toEqual('test');
|
||||
expect(call[5]).toEqual(mockNow());
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interactionOne] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interactionOne] : [],
|
||||
);
|
||||
|
||||
onRender.mockClear();
|
||||
@@ -1931,13 +1919,13 @@ describe('Profiler', () => {
|
||||
timestamp: mockNow(),
|
||||
};
|
||||
|
||||
// Cause an tracked, async update
|
||||
SchedulerTracking.unstable_track(interactionTwo.name, mockNow(), () => {
|
||||
// Cause an traced, async update
|
||||
SchedulerTracing.unstable_trace(interactionTwo.name, mockNow(), () => {
|
||||
instance.setState({count: 2});
|
||||
});
|
||||
expect(onRender).not.toHaveBeenCalled();
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interactionTwo,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
@@ -1946,12 +1934,12 @@ describe('Profiler', () => {
|
||||
|
||||
advanceTimeBy(5);
|
||||
|
||||
// Flush async work (outside of tracked scope)
|
||||
// Flush async work (outside of traced scope)
|
||||
// This will cause an intentional cascading update from did-update
|
||||
firstCommitTime = mockNow();
|
||||
renderer.unstable_flushAll(['Example:2', 'Example:3']);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -1977,13 +1965,13 @@ describe('Profiler', () => {
|
||||
expect(call[0]).toEqual('test');
|
||||
expect(call[5]).toEqual(firstCommitTime);
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interactionTwo] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interactionTwo] : [],
|
||||
);
|
||||
call = onRender.mock.calls[1];
|
||||
expect(call[0]).toEqual('test');
|
||||
expect(call[5]).toEqual(mockNow());
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interactionTwo] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interactionTwo] : [],
|
||||
);
|
||||
|
||||
onRender.mockClear();
|
||||
@@ -1998,25 +1986,25 @@ describe('Profiler', () => {
|
||||
function callback() {
|
||||
instance.setState({count: 6});
|
||||
}
|
||||
SchedulerTracking.unstable_track(interactionThree.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(interactionThree.name, mockNow(), () => {
|
||||
instance.setState({count: 5}, callback);
|
||||
});
|
||||
expect(onRender).not.toHaveBeenCalled();
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interactionThree,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(2);
|
||||
expect(getWorkForReactThreads(onWorkStarted)).toHaveLength(4);
|
||||
expect(getWorkForReactThreads(onWorkStopped)).toHaveLength(4);
|
||||
|
||||
// Flush async work (outside of tracked scope)
|
||||
// Flush async work (outside of traced scope)
|
||||
// This will cause an intentional cascading update from the setState callback
|
||||
firstCommitTime = mockNow();
|
||||
renderer.unstable_flushAll(['Example:5', 'Example:6']);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(3);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(3);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -2042,17 +2030,17 @@ describe('Profiler', () => {
|
||||
expect(call[0]).toEqual('test');
|
||||
expect(call[5]).toEqual(firstCommitTime);
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interactionThree] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interactionThree] : [],
|
||||
);
|
||||
call = onRender.mock.calls[1];
|
||||
expect(call[0]).toEqual('test');
|
||||
expect(call[5]).toEqual(mockNow());
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interactionThree] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interactionThree] : [],
|
||||
);
|
||||
});
|
||||
|
||||
it('should track interactions associated with a parent component state update', () => {
|
||||
it('should trace interactions associated with a parent component state update', () => {
|
||||
const onRender = jest.fn();
|
||||
let parentInstance = null;
|
||||
|
||||
@@ -2091,12 +2079,12 @@ describe('Profiler', () => {
|
||||
timestamp: mockNow(),
|
||||
};
|
||||
|
||||
SchedulerTracking.unstable_track(interaction.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(interaction.name, mockNow(), () => {
|
||||
parentInstance.setState({count: 1});
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interaction,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
@@ -2109,10 +2097,10 @@ describe('Profiler', () => {
|
||||
let call = onRender.mock.calls[0];
|
||||
expect(call[0]).toEqual('test-profiler');
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interaction] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interaction] : [],
|
||||
);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -2127,19 +2115,19 @@ describe('Profiler', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('tracks both the temporary placeholder and the finished render for an interaction', async () => {
|
||||
it('traces both the temporary placeholder and the finished render for an interaction', async () => {
|
||||
jest.resetModules();
|
||||
|
||||
loadModules({
|
||||
useNoopRenderer: true,
|
||||
enableSuspense: true,
|
||||
enableSchedulerTracking: true,
|
||||
enableSchedulerTracing: true,
|
||||
});
|
||||
|
||||
// Re-register since we've reloaded modules
|
||||
SchedulerTracking.unstable_subscribe({
|
||||
SchedulerTracing.unstable_subscribe({
|
||||
onInteractionScheduledWorkCompleted,
|
||||
onInteractionTracked,
|
||||
onInteractionTraced,
|
||||
onWorkCanceled,
|
||||
onWorkScheduled,
|
||||
onWorkStarted,
|
||||
@@ -2204,7 +2192,7 @@ describe('Profiler', () => {
|
||||
};
|
||||
|
||||
const onRender = jest.fn();
|
||||
SchedulerTracking.unstable_track(interaction.name, mockNow(), () => {
|
||||
SchedulerTracing.unstable_trace(interaction.name, mockNow(), () => {
|
||||
ReactNoop.render(
|
||||
<React.unstable_Profiler id="test-profiler" onRender={onRender}>
|
||||
<React.Placeholder fallback={<Text text="Loading..." />}>
|
||||
@@ -2215,8 +2203,8 @@ describe('Profiler', () => {
|
||||
);
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
interaction,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
@@ -2249,10 +2237,10 @@ describe('Profiler', () => {
|
||||
let call = onRender.mock.calls[0];
|
||||
expect(call[0]).toEqual('test-profiler');
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interaction] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interaction] : [],
|
||||
);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
// Once the promise resolves, we render the suspended view
|
||||
@@ -2264,10 +2252,10 @@ describe('Profiler', () => {
|
||||
call = onRender.mock.calls[1];
|
||||
expect(call[0]).toEqual('test-profiler');
|
||||
expect(call[6]).toMatchInteractions(
|
||||
ReactFeatureFlags.enableSchedulerTracking ? [interaction] : [],
|
||||
ReactFeatureFlags.enableSchedulerTracing ? [interaction] : [],
|
||||
);
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
let React;
|
||||
let ReactFeatureFlags;
|
||||
let ReactTestRenderer;
|
||||
let SchedulerTracking;
|
||||
let SchedulerTracing;
|
||||
let AdvanceTime;
|
||||
let advanceTimeBy;
|
||||
let hook;
|
||||
@@ -38,8 +38,8 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableProfilerTimer = true;
|
||||
ReactFeatureFlags.enableSchedulerTracking = true;
|
||||
SchedulerTracking = require('schedule/tracking');
|
||||
ReactFeatureFlags.enableSchedulerTracing = true;
|
||||
SchedulerTracing = require('schedule/tracing');
|
||||
React = require('react');
|
||||
ReactTestRenderer = require('react-test-renderer');
|
||||
|
||||
@@ -168,7 +168,7 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
).toBe(7);
|
||||
});
|
||||
|
||||
it('should store tracked interactions on the HostNode so DevTools can access them', () => {
|
||||
it('should store traced interactions on the HostNode so DevTools can access them', () => {
|
||||
// Render without an interaction
|
||||
const rendered = ReactTestRenderer.create(<div />);
|
||||
|
||||
@@ -180,7 +180,7 @@ describe('ReactProfiler DevTools integration', () => {
|
||||
const eventTime = mockNow();
|
||||
|
||||
// Render with an interaction
|
||||
SchedulerTracking.unstable_track('some event', eventTime, () => {
|
||||
SchedulerTracing.unstable_trace('some event', eventTime, () => {
|
||||
rendered.update(<div />);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:disabled should render children 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:disabled enableProfilerTimer:disabled should render children 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
outside span
|
||||
@@ -14,11 +14,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTr
|
||||
</div>
|
||||
`;
|
||||
|
||||
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 enableSchedulerTracing: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) 2`] = `<div />`;
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:disabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 2`] = `<div />`;
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:disabled should support nested Profilers 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:disabled enableProfilerTimer:disabled should support nested Profilers 1`] = `
|
||||
Array [
|
||||
<div>
|
||||
outer functional component
|
||||
@@ -32,7 +32,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:enabled should render children 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:disabled enableProfilerTimer:enabled should render children 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
outside span
|
||||
@@ -46,11 +46,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTr
|
||||
</div>
|
||||
`;
|
||||
|
||||
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 enableSchedulerTracing: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) 2`] = `<div />`;
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:disabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 2`] = `<div />`;
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:disabled enableProfilerTimer:enabled should support nested Profilers 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:disabled enableProfilerTimer:enabled should support nested Profilers 1`] = `
|
||||
Array [
|
||||
<div>
|
||||
outer functional component
|
||||
@@ -64,7 +64,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:disabled should render children 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:enabled enableProfilerTimer:disabled should render children 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
outside span
|
||||
@@ -78,11 +78,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTr
|
||||
</div>
|
||||
`;
|
||||
|
||||
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 enableSchedulerTracing: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) 2`] = `<div />`;
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:enabled enableProfilerTimer:disabled should support an empty Profiler (with no children) 2`] = `<div />`;
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:disabled should support nested Profilers 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:enabled enableProfilerTimer:disabled should support nested Profilers 1`] = `
|
||||
Array [
|
||||
<div>
|
||||
outer functional component
|
||||
@@ -96,7 +96,7 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:enabled should render children 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:enabled enableProfilerTimer:enabled should render children 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
outside span
|
||||
@@ -110,11 +110,11 @@ exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTr
|
||||
</div>
|
||||
`;
|
||||
|
||||
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 enableSchedulerTracing: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) 2`] = `<div />`;
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:enabled enableProfilerTimer:enabled should support an empty Profiler (with no children) 2`] = `<div />`;
|
||||
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracking:enabled enableProfilerTimer:enabled should support nested Profilers 1`] = `
|
||||
exports[`Profiler works in profiling and non-profiling bundles enableSchedulerTracing:enabled enableProfilerTimer:enabled should support nested Profilers 1`] = `
|
||||
Array [
|
||||
<div>
|
||||
outer functional component
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
*
|
||||
* 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';
|
||||
|
||||
7
packages/schedule/npm/tracing-profiling.js
Normal file
7
packages/schedule/npm/tracing-profiling.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./cjs/schedule-tracing.profiling.min.js');
|
||||
} else {
|
||||
module.exports = require('./cjs/schedule-tracing.development.js');
|
||||
}
|
||||
7
packages/schedule/npm/tracing.js
Normal file
7
packages/schedule/npm/tracing.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./cjs/schedule-tracing.production.min.js');
|
||||
} else {
|
||||
module.exports = require('./cjs/schedule-tracing.development.js');
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./cjs/schedule-tracking.profiling.min.js');
|
||||
} else {
|
||||
module.exports = require('./cjs/schedule-tracking.development.js');
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./cjs/schedule-tracking.production.min.js');
|
||||
} else {
|
||||
module.exports = require('./cjs/schedule-tracking.development.js');
|
||||
}
|
||||
@@ -14,24 +14,24 @@
|
||||
? (module.exports = factory(require('react')))
|
||||
: typeof define === 'function' && define.amd // eslint-disable-line no-undef
|
||||
? define(['react'], factory) // eslint-disable-line no-undef
|
||||
: (global.ScheduleTracking = factory(global));
|
||||
: (global.ScheduleTracing = factory(global));
|
||||
})(this, function(global) {
|
||||
function unstable_clear() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_clear.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_clear.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_getCurrent() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_getCurrent.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_getCurrent.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_getThreadID() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_getThreadID.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_getThreadID.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
@@ -39,14 +39,14 @@
|
||||
|
||||
function unstable_subscribe() {
|
||||
// eslint-disable-next-line max-len
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_subscribe.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_subscribe.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_track() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_track.apply(
|
||||
function unstable_trace() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_trace.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
@@ -54,14 +54,14 @@
|
||||
|
||||
function unstable_unsubscribe() {
|
||||
// eslint-disable-next-line max-len
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_unsubscribe.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_unsubscribe.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_wrap() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_wrap.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_wrap.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
@@ -72,7 +72,7 @@
|
||||
unstable_getCurrent: unstable_getCurrent,
|
||||
unstable_getThreadID: unstable_getThreadID,
|
||||
unstable_subscribe: unstable_subscribe,
|
||||
unstable_track: unstable_track,
|
||||
unstable_trace: unstable_trace,
|
||||
unstable_unsubscribe: unstable_unsubscribe,
|
||||
unstable_wrap: unstable_wrap,
|
||||
});
|
||||
@@ -14,24 +14,24 @@
|
||||
? (module.exports = factory(require('react')))
|
||||
: typeof define === 'function' && define.amd // eslint-disable-line no-undef
|
||||
? define(['react'], factory) // eslint-disable-line no-undef
|
||||
: (global.ScheduleTracking = factory(global));
|
||||
: (global.ScheduleTracing = factory(global));
|
||||
})(this, function(global) {
|
||||
function unstable_clear() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_clear.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_clear.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_getCurrent() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_getCurrent.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_getCurrent.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_getThreadID() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_getThreadID.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_getThreadID.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
@@ -39,14 +39,14 @@
|
||||
|
||||
function unstable_subscribe() {
|
||||
// eslint-disable-next-line max-len
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_subscribe.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_subscribe.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_track() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_track.apply(
|
||||
function unstable_trace() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_trace.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
@@ -54,14 +54,14 @@
|
||||
|
||||
function unstable_unsubscribe() {
|
||||
// eslint-disable-next-line max-len
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_unsubscribe.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_unsubscribe.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_wrap() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracking.unstable_wrap.apply(
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_wrap.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
@@ -72,7 +72,7 @@
|
||||
unstable_getCurrent: unstable_getCurrent,
|
||||
unstable_getThreadID: unstable_getThreadID,
|
||||
unstable_subscribe: unstable_subscribe,
|
||||
unstable_track: unstable_track,
|
||||
unstable_trace: unstable_trace,
|
||||
unstable_unsubscribe: unstable_unsubscribe,
|
||||
unstable_wrap: unstable_wrap,
|
||||
});
|
||||
79
packages/schedule/npm/umd/schedule-tracing.profiling.min.js
vendored
Normal file
79
packages/schedule/npm/umd/schedule-tracing.profiling.min.js
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @license React
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.ScheduleTracing = factory(global));
|
||||
})(this, function(global) {
|
||||
function unstable_clear() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_clear.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_getCurrent() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_getCurrent.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_getThreadID() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_getThreadID.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_subscribe() {
|
||||
// eslint-disable-next-line max-len
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_subscribe.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_trace() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_trace.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.ScheduleTracing.unstable_unsubscribe.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_wrap() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ScheduleTracing.unstable_wrap.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
unstable_clear: unstable_clear,
|
||||
unstable_getCurrent: unstable_getCurrent,
|
||||
unstable_getThreadID: unstable_getThreadID,
|
||||
unstable_subscribe: unstable_subscribe,
|
||||
unstable_trace: unstable_trace,
|
||||
unstable_unsubscribe: unstable_unsubscribe,
|
||||
unstable_wrap: unstable_wrap,
|
||||
});
|
||||
});
|
||||
45
packages/schedule/npm/umd/schedule.profiling.min.js
vendored
Normal file
45
packages/schedule/npm/umd/schedule.profiling.min.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @license React
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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.Schedule = factory(global));
|
||||
})(this, function(global) {
|
||||
function unstable_now() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Schedule.unstable_now.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_scheduleWork() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Schedule.unstable_scheduleWork.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
function unstable_cancelScheduledWork() {
|
||||
return global.React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Schedule.unstable_cancelScheduledWork.apply(
|
||||
this,
|
||||
arguments
|
||||
);
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
unstable_now: unstable_now,
|
||||
unstable_scheduleWork: unstable_scheduleWork,
|
||||
unstable_cancelScheduledWork: unstable_cancelScheduledWork,
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "schedule",
|
||||
"version": "0.3.0",
|
||||
"version": "0.5.0",
|
||||
"description": "Cooperative scheduler for the browser environment.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -19,8 +19,8 @@
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"index.js",
|
||||
"tracking.js",
|
||||
"tracking-profiling.js",
|
||||
"tracing.js",
|
||||
"tracing-profiling.js",
|
||||
"cjs/",
|
||||
"umd/"
|
||||
]
|
||||
|
||||
@@ -4,313 +4,380 @@
|
||||
* 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';
|
||||
/* eslint-disable no-var */
|
||||
|
||||
/**
|
||||
* A scheduling library to allow scheduling work with more granular priority and
|
||||
* control than requestAnimationFrame and requestIdleCallback.
|
||||
* Current TODO items:
|
||||
* X- Pull out the scheduleWork polyfill built into React
|
||||
* X- Initial test coverage
|
||||
* X- Support for multiple callbacks
|
||||
* - Support for two priorities; serial and deferred
|
||||
* - Better test coverage
|
||||
* - Better docblock
|
||||
* - Polish documentation, API
|
||||
*/
|
||||
// TODO: Currently there's only a single priority level, Deferred. Will add
|
||||
// additional priorities.
|
||||
var DEFERRED_TIMEOUT = 5000;
|
||||
|
||||
// This is a built-in polyfill for requestIdleCallback. It works by scheduling
|
||||
// a requestAnimationFrame, storing the time for the start of the frame, then
|
||||
// scheduling a postMessage which gets scheduled after paint. Within the
|
||||
// postMessage handler do as much work as possible until time + frame rate.
|
||||
// By separating the idle call into a separate event tick we ensure that
|
||||
// Callbacks are stored as a circular, doubly linked list.
|
||||
var firstCallbackNode = null;
|
||||
|
||||
var isPerformingWork = false;
|
||||
|
||||
var isHostCallbackScheduled = false;
|
||||
|
||||
var hasNativePerformanceNow =
|
||||
typeof performance === 'object' && typeof performance.now === 'function';
|
||||
|
||||
var timeRemaining;
|
||||
if (hasNativePerformanceNow) {
|
||||
timeRemaining = function() {
|
||||
// We assume that if we have a performance timer that the rAF callback
|
||||
// gets a performance timer value. Not sure if this is always true.
|
||||
var remaining = getFrameDeadline() - performance.now();
|
||||
return remaining > 0 ? remaining : 0;
|
||||
};
|
||||
} else {
|
||||
timeRemaining = function() {
|
||||
// Fallback to Date.now()
|
||||
var remaining = getFrameDeadline() - Date.now();
|
||||
return remaining > 0 ? remaining : 0;
|
||||
};
|
||||
}
|
||||
|
||||
var deadlineObject = {
|
||||
timeRemaining,
|
||||
didTimeout: false,
|
||||
};
|
||||
|
||||
function ensureHostCallbackIsScheduled() {
|
||||
if (isPerformingWork) {
|
||||
// Don't schedule work yet; wait until the next time we yield.
|
||||
return;
|
||||
}
|
||||
// Schedule the host callback using the earliest timeout in the list.
|
||||
var timesOutAt = firstCallbackNode.timesOutAt;
|
||||
if (!isHostCallbackScheduled) {
|
||||
isHostCallbackScheduled = true;
|
||||
} else {
|
||||
// Cancel the existing host callback.
|
||||
cancelCallback();
|
||||
}
|
||||
requestCallback(flushWork, timesOutAt);
|
||||
}
|
||||
|
||||
function flushFirstCallback(node) {
|
||||
var flushedNode = firstCallbackNode;
|
||||
|
||||
// Remove the node from the list before calling the callback. That way the
|
||||
// list is in a consistent state even if the callback throws.
|
||||
var next = firstCallbackNode.next;
|
||||
if (firstCallbackNode === next) {
|
||||
// This is the last callback in the list.
|
||||
firstCallbackNode = null;
|
||||
next = null;
|
||||
} else {
|
||||
var previous = firstCallbackNode.previous;
|
||||
firstCallbackNode = previous.next = next;
|
||||
next.previous = previous;
|
||||
}
|
||||
|
||||
flushedNode.next = flushedNode.previous = null;
|
||||
|
||||
// Now it's safe to call the callback.
|
||||
var callback = flushedNode.callback;
|
||||
callback(deadlineObject);
|
||||
}
|
||||
|
||||
function flushWork(didTimeout) {
|
||||
isPerformingWork = true;
|
||||
deadlineObject.didTimeout = didTimeout;
|
||||
try {
|
||||
if (didTimeout) {
|
||||
// Flush all the timed out callbacks without yielding.
|
||||
while (firstCallbackNode !== null) {
|
||||
// Read the current time. Flush all the callbacks that expire at or
|
||||
// earlier than that time. Then read the current time again and repeat.
|
||||
// This optimizes for as few performance.now calls as possible.
|
||||
var currentTime = getCurrentTime();
|
||||
if (firstCallbackNode.timesOutAt <= currentTime) {
|
||||
do {
|
||||
flushFirstCallback();
|
||||
} while (
|
||||
firstCallbackNode !== null &&
|
||||
firstCallbackNode.timesOutAt <= currentTime
|
||||
);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Keep flushing callbacks until we run out of time in the frame.
|
||||
if (firstCallbackNode !== null) {
|
||||
do {
|
||||
flushFirstCallback();
|
||||
} while (
|
||||
firstCallbackNode !== null &&
|
||||
getFrameDeadline() - getCurrentTime() > 0
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isPerformingWork = false;
|
||||
if (firstCallbackNode !== null) {
|
||||
// There's still work remaining. Request another callback.
|
||||
ensureHostCallbackIsScheduled(firstCallbackNode);
|
||||
} else {
|
||||
isHostCallbackScheduled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function unstable_scheduleWork(callback, options) {
|
||||
var currentTime = getCurrentTime();
|
||||
|
||||
var timesOutAt;
|
||||
if (
|
||||
options !== undefined &&
|
||||
options !== null &&
|
||||
options.timeout !== null &&
|
||||
options.timeout !== undefined
|
||||
) {
|
||||
// Check for an explicit timeout
|
||||
timesOutAt = currentTime + options.timeout;
|
||||
} else {
|
||||
// Compute an absolute timeout using the default constant.
|
||||
timesOutAt = currentTime + DEFERRED_TIMEOUT;
|
||||
}
|
||||
|
||||
var newNode = {
|
||||
callback,
|
||||
timesOutAt,
|
||||
next: null,
|
||||
previous: null,
|
||||
};
|
||||
|
||||
// Insert the new callback into the list, sorted by its timeout.
|
||||
if (firstCallbackNode === null) {
|
||||
// This is the first callback in the list.
|
||||
firstCallbackNode = newNode.next = newNode.previous = newNode;
|
||||
ensureHostCallbackIsScheduled(firstCallbackNode);
|
||||
} else {
|
||||
var next = null;
|
||||
var node = firstCallbackNode;
|
||||
do {
|
||||
if (node.timesOutAt > timesOutAt) {
|
||||
// The new callback times out before this one.
|
||||
next = node;
|
||||
break;
|
||||
}
|
||||
node = node.next;
|
||||
} while (node !== firstCallbackNode);
|
||||
|
||||
if (next === null) {
|
||||
// No callback with a later timeout was found, which means the new
|
||||
// callback has the latest timeout in the list.
|
||||
next = firstCallbackNode;
|
||||
} else if (next === firstCallbackNode) {
|
||||
// The new callback has the earliest timeout in the entire list.
|
||||
firstCallbackNode = newNode;
|
||||
ensureHostCallbackIsScheduled(firstCallbackNode);
|
||||
}
|
||||
|
||||
var previous = next.previous;
|
||||
previous.next = next.previous = newNode;
|
||||
newNode.next = next;
|
||||
newNode.previous = previous;
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
function unstable_cancelScheduledWork(callbackNode) {
|
||||
var next = callbackNode.next;
|
||||
if (next === null) {
|
||||
// Already cancelled.
|
||||
return;
|
||||
}
|
||||
|
||||
if (next === callbackNode) {
|
||||
// This is the only scheduled callback. Clear the list.
|
||||
firstCallbackNode = null;
|
||||
} else {
|
||||
// Remove the callback from its position in the list.
|
||||
if (callbackNode === firstCallbackNode) {
|
||||
firstCallbackNode = next;
|
||||
}
|
||||
var previous = callbackNode.previous;
|
||||
previous.next = next;
|
||||
next.previous = previous;
|
||||
}
|
||||
|
||||
callbackNode.next = callbackNode.previous = null;
|
||||
}
|
||||
|
||||
// The remaining code is essentially a polyfill for requestIdleCallback. It
|
||||
// works by scheduling a requestAnimationFrame, storing the time for the start
|
||||
// of the frame, then scheduling a postMessage which gets scheduled after paint.
|
||||
// Within the postMessage handler do as much work as possible until time + frame
|
||||
// rate. By separating the idle call into a separate event tick we ensure that
|
||||
// layout, paint and other browser work is counted against the available time.
|
||||
// The frame rate is dynamically adjusted.
|
||||
|
||||
import type {Deadline} from 'react-reconciler/src/ReactFiberScheduler';
|
||||
type FrameCallbackType = Deadline => void;
|
||||
type CallbackConfigType = {|
|
||||
scheduledCallback: FrameCallbackType,
|
||||
timeoutTime: number,
|
||||
next: CallbackConfigType | null, // creating a linked list
|
||||
prev: CallbackConfigType | null, // creating a linked list
|
||||
|};
|
||||
|
||||
export type CallbackIdType = CallbackConfigType;
|
||||
|
||||
import {canUseDOM} from 'shared/ExecutionEnvironment';
|
||||
|
||||
// We capture a local reference to any global, in case it gets polyfilled after
|
||||
// this module is initially evaluated.
|
||||
// We want to be using a consistent implementation.
|
||||
const localDate = Date;
|
||||
// this module is initially evaluated. We want to be using a
|
||||
// consistent implementation.
|
||||
var localDate = Date;
|
||||
|
||||
// This initialization code may run even on server environments
|
||||
// if a component just imports ReactDOM (e.g. for findDOMNode).
|
||||
// Some environments might not have setTimeout or clearTimeout.
|
||||
// However, we always expect them to be defined on the client.
|
||||
// https://github.com/facebook/react/pull/13088
|
||||
const localSetTimeout =
|
||||
typeof setTimeout === 'function' ? setTimeout : (undefined: any);
|
||||
const localClearTimeout =
|
||||
typeof clearTimeout === 'function' ? clearTimeout : (undefined: any);
|
||||
// This initialization code may run even on server environments if a component
|
||||
// just imports ReactDOM (e.g. for findDOMNode). Some environments might not
|
||||
// have setTimeout or clearTimeout. However, we always expect them to be defined
|
||||
// on the client. https://github.com/facebook/react/pull/13088
|
||||
var localSetTimeout = typeof setTimeout === 'function' ? setTimeout : undefined;
|
||||
var localClearTimeout =
|
||||
typeof clearTimeout === 'function' ? clearTimeout : undefined;
|
||||
|
||||
// We don't expect either of these to necessarily be defined,
|
||||
// but we will error later if they are missing on the client.
|
||||
const localRequestAnimationFrame =
|
||||
// We don't expect either of these to necessarily be defined, but we will error
|
||||
// later if they are missing on the client.
|
||||
var localRequestAnimationFrame =
|
||||
typeof requestAnimationFrame === 'function'
|
||||
? requestAnimationFrame
|
||||
: (undefined: any);
|
||||
const localCancelAnimationFrame =
|
||||
typeof cancelAnimationFrame === 'function'
|
||||
? cancelAnimationFrame
|
||||
: (undefined: any);
|
||||
: undefined;
|
||||
var localCancelAnimationFrame =
|
||||
typeof cancelAnimationFrame === 'function' ? cancelAnimationFrame : undefined;
|
||||
|
||||
const hasNativePerformanceNow =
|
||||
typeof performance === 'object' && typeof performance.now === 'function';
|
||||
var getCurrentTime;
|
||||
|
||||
// requestAnimationFrame does not run when the tab is in the background. If
|
||||
// we're backgrounded we prefer for that work to happen so that the page
|
||||
// continues to load in the background. So we also schedule a 'setTimeout' as
|
||||
// a fallback.
|
||||
// TODO: Need a better heuristic for backgrounded work.
|
||||
var ANIMATION_FRAME_TIMEOUT = 100;
|
||||
var rAFID;
|
||||
var rAFTimeoutID;
|
||||
var requestAnimationFrameWithTimeout = function(callback) {
|
||||
// schedule rAF and also a setTimeout
|
||||
rAFID = localRequestAnimationFrame(function(timestamp) {
|
||||
// cancel the setTimeout
|
||||
localClearTimeout(rAFTimeoutID);
|
||||
callback(timestamp);
|
||||
});
|
||||
rAFTimeoutID = localSetTimeout(function() {
|
||||
// cancel the requestAnimationFrame
|
||||
localCancelAnimationFrame(rAFID);
|
||||
callback(getCurrentTime());
|
||||
}, ANIMATION_FRAME_TIMEOUT);
|
||||
};
|
||||
|
||||
let now;
|
||||
if (hasNativePerformanceNow) {
|
||||
const Performance = performance;
|
||||
now = function() {
|
||||
var Performance = performance;
|
||||
getCurrentTime = function() {
|
||||
return Performance.now();
|
||||
};
|
||||
} else {
|
||||
now = function() {
|
||||
getCurrentTime = function() {
|
||||
return localDate.now();
|
||||
};
|
||||
}
|
||||
|
||||
let scheduleWork: (
|
||||
callback: FrameCallbackType,
|
||||
options?: {timeout: number},
|
||||
) => CallbackIdType;
|
||||
let cancelScheduledWork: (callbackId: CallbackIdType) => void;
|
||||
var requestCallback;
|
||||
var cancelCallback;
|
||||
var getFrameDeadline;
|
||||
|
||||
if (!canUseDOM) {
|
||||
const timeoutIds = new Map();
|
||||
|
||||
scheduleWork = function(
|
||||
callback: FrameCallbackType,
|
||||
options?: {timeout: number},
|
||||
): CallbackIdType {
|
||||
// keeping return type consistent
|
||||
const callbackConfig = {
|
||||
scheduledCallback: callback,
|
||||
timeoutTime: 0,
|
||||
next: null,
|
||||
prev: null,
|
||||
};
|
||||
const timeoutId = localSetTimeout(() => {
|
||||
callback({
|
||||
timeRemaining() {
|
||||
return Infinity;
|
||||
},
|
||||
didTimeout: false,
|
||||
});
|
||||
});
|
||||
timeoutIds.set(callback, timeoutId);
|
||||
return callbackConfig;
|
||||
if (typeof window === 'undefined') {
|
||||
// If this accidentally gets imported in a non-browser environment, fallback
|
||||
// to a naive implementation.
|
||||
var timeoutID = -1;
|
||||
requestCallback = function(callback, absoluteTimeout) {
|
||||
timeoutID = setTimeout(callback, 0, true);
|
||||
};
|
||||
cancelScheduledWork = function(callbackId: CallbackIdType) {
|
||||
const callback = callbackId.scheduledCallback;
|
||||
const timeoutId = timeoutIds.get(callback);
|
||||
timeoutIds.delete(callbackId);
|
||||
localClearTimeout(timeoutId);
|
||||
cancelCallback = function() {
|
||||
clearTimeout(timeoutID);
|
||||
};
|
||||
getFrameDeadline = function() {
|
||||
return 0;
|
||||
};
|
||||
} else if (window._schedMock) {
|
||||
// Dynamic injection, only for testing purposes.
|
||||
var impl = window._schedMock;
|
||||
requestCallback = impl[0];
|
||||
cancelCallback = impl[1];
|
||||
getFrameDeadline = impl[2];
|
||||
} else {
|
||||
if (__DEV__) {
|
||||
if (typeof console !== 'undefined') {
|
||||
if (typeof localRequestAnimationFrame !== 'function') {
|
||||
console.error(
|
||||
"This browser doesn't support requestAnimationFrame. " +
|
||||
'Make sure that you load a ' +
|
||||
'polyfill in older browsers. https://fb.me/react-polyfills',
|
||||
);
|
||||
}
|
||||
if (typeof localCancelAnimationFrame !== 'function') {
|
||||
console.error(
|
||||
"This browser doesn't support cancelAnimationFrame. " +
|
||||
'Make sure that you load a ' +
|
||||
'polyfill in older browsers. https://fb.me/react-polyfills',
|
||||
);
|
||||
}
|
||||
if (typeof console !== 'undefined') {
|
||||
if (typeof localRequestAnimationFrame !== 'function') {
|
||||
console.error(
|
||||
"This browser doesn't support requestAnimationFrame. " +
|
||||
'Make sure that you load a ' +
|
||||
'polyfill in older browsers. https://fb.me/react-polyfills',
|
||||
);
|
||||
}
|
||||
if (typeof localCancelAnimationFrame !== 'function') {
|
||||
console.error(
|
||||
"This browser doesn't support cancelAnimationFrame. " +
|
||||
'Make sure that you load a ' +
|
||||
'polyfill in older browsers. https://fb.me/react-polyfills',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let headOfPendingCallbacksLinkedList: CallbackConfigType | null = null;
|
||||
let tailOfPendingCallbacksLinkedList: CallbackConfigType | null = null;
|
||||
var scheduledCallback = null;
|
||||
var isIdleScheduled = false;
|
||||
var timeoutTime = -1;
|
||||
|
||||
// We track what the next soonest timeoutTime is, to be able to quickly tell
|
||||
// if none of the scheduled callbacks have timed out.
|
||||
let nextSoonestTimeoutTime = -1;
|
||||
var isAnimationFrameScheduled = false;
|
||||
|
||||
let isIdleScheduled = false;
|
||||
let isAnimationFrameScheduled = false;
|
||||
var isPerformingIdleWork = false;
|
||||
|
||||
// requestAnimationFrame does not run when the tab is in the background.
|
||||
// if we're backgrounded we prefer for that work to happen so that the page
|
||||
// continues to load in the background.
|
||||
// so we also schedule a 'setTimeout' as a fallback.
|
||||
const animationFrameTimeout = 100;
|
||||
let rafID;
|
||||
let timeoutID;
|
||||
const scheduleAnimationFrameWithFallbackSupport = function(callback) {
|
||||
// schedule rAF and also a setTimeout
|
||||
rafID = localRequestAnimationFrame(function(timestamp) {
|
||||
// cancel the setTimeout
|
||||
localClearTimeout(timeoutID);
|
||||
callback(timestamp);
|
||||
});
|
||||
timeoutID = localSetTimeout(function() {
|
||||
// cancel the requestAnimationFrame
|
||||
localCancelAnimationFrame(rafID);
|
||||
callback(now());
|
||||
}, animationFrameTimeout);
|
||||
};
|
||||
|
||||
let frameDeadline = 0;
|
||||
var frameDeadline = 0;
|
||||
// We start out assuming that we run at 30fps but then the heuristic tracking
|
||||
// will adjust this value to a faster fps if we get more frequent animation
|
||||
// frames.
|
||||
let previousFrameTime = 33;
|
||||
let activeFrameTime = 33;
|
||||
var previousFrameTime = 33;
|
||||
var activeFrameTime = 33;
|
||||
|
||||
const frameDeadlineObject: Deadline = {
|
||||
didTimeout: false,
|
||||
timeRemaining() {
|
||||
const remaining = frameDeadline - now();
|
||||
return remaining > 0 ? remaining : 0;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the case where a callback errors:
|
||||
* - don't catch the error, because this changes debugging behavior
|
||||
* - do start a new postMessage callback, to call any remaining callbacks,
|
||||
* - but only if there is an error, so there is not extra overhead.
|
||||
*/
|
||||
const callUnsafely = function(
|
||||
callbackConfig: CallbackConfigType,
|
||||
arg: Deadline,
|
||||
) {
|
||||
const callback = callbackConfig.scheduledCallback;
|
||||
let finishedCalling = false;
|
||||
try {
|
||||
callback(arg);
|
||||
finishedCalling = true;
|
||||
} finally {
|
||||
// always remove it from linked list
|
||||
cancelScheduledWork(callbackConfig);
|
||||
|
||||
if (!finishedCalling) {
|
||||
// an error must have been thrown
|
||||
isIdleScheduled = true;
|
||||
window.postMessage(messageKey, '*');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks for timed out callbacks, runs them, and then checks again to see if
|
||||
* any more have timed out.
|
||||
* Keeps doing this until there are none which have currently timed out.
|
||||
*/
|
||||
const callTimedOutCallbacks = function() {
|
||||
if (headOfPendingCallbacksLinkedList === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentTime = now();
|
||||
// TODO: this would be more efficient if deferred callbacks are stored in
|
||||
// min heap.
|
||||
// Or in a linked list with links for both timeoutTime order and insertion
|
||||
// order.
|
||||
// For now an easy compromise is the current approach:
|
||||
// Keep a pointer to the soonest timeoutTime, and check that first.
|
||||
// If it has not expired, we can skip traversing the whole list.
|
||||
// If it has expired, then we step through all the callbacks.
|
||||
if (nextSoonestTimeoutTime === -1 || nextSoonestTimeoutTime > currentTime) {
|
||||
// We know that none of them have timed out yet.
|
||||
return;
|
||||
}
|
||||
// NOTE: we intentionally wait to update the nextSoonestTimeoutTime until
|
||||
// after successfully calling any timed out callbacks.
|
||||
// If a timed out callback throws an error, we could get stuck in a state
|
||||
// where the nextSoonestTimeoutTime was set wrong.
|
||||
let updatedNextSoonestTimeoutTime = -1; // we will update nextSoonestTimeoutTime below
|
||||
const timedOutCallbacks = [];
|
||||
|
||||
// iterate once to find timed out callbacks and find nextSoonestTimeoutTime
|
||||
let currentCallbackConfig = headOfPendingCallbacksLinkedList;
|
||||
while (currentCallbackConfig !== null) {
|
||||
const timeoutTime = currentCallbackConfig.timeoutTime;
|
||||
if (timeoutTime !== -1 && timeoutTime <= currentTime) {
|
||||
// it has timed out!
|
||||
timedOutCallbacks.push(currentCallbackConfig);
|
||||
} else {
|
||||
if (
|
||||
timeoutTime !== -1 &&
|
||||
(updatedNextSoonestTimeoutTime === -1 ||
|
||||
timeoutTime < updatedNextSoonestTimeoutTime)
|
||||
) {
|
||||
updatedNextSoonestTimeoutTime = timeoutTime;
|
||||
}
|
||||
}
|
||||
currentCallbackConfig = currentCallbackConfig.next;
|
||||
}
|
||||
|
||||
if (timedOutCallbacks.length > 0) {
|
||||
frameDeadlineObject.didTimeout = true;
|
||||
for (let i = 0, len = timedOutCallbacks.length; i < len; i++) {
|
||||
callUnsafely(timedOutCallbacks[i], frameDeadlineObject);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: we intentionally wait to update the nextSoonestTimeoutTime until
|
||||
// after successfully calling any timed out callbacks.
|
||||
nextSoonestTimeoutTime = updatedNextSoonestTimeoutTime;
|
||||
getFrameDeadline = function() {
|
||||
return frameDeadline;
|
||||
};
|
||||
|
||||
// We use the postMessage trick to defer idle work until after the repaint.
|
||||
const messageKey =
|
||||
var messageKey =
|
||||
'__reactIdleCallback$' +
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.slice(2);
|
||||
const idleTick = function(event) {
|
||||
var idleTick = function(event) {
|
||||
if (event.source !== window || event.data !== messageKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
isIdleScheduled = false;
|
||||
|
||||
if (headOfPendingCallbacksLinkedList === null) {
|
||||
return;
|
||||
var currentTime = getCurrentTime();
|
||||
|
||||
var didTimeout = false;
|
||||
if (frameDeadline - currentTime <= 0) {
|
||||
// There's no time left in this idle period. Check if the callback has
|
||||
// a timeout and whether it's been exceeded.
|
||||
if (timeoutTime !== -1 && timeoutTime <= currentTime) {
|
||||
// Exceeded the timeout. Invoke the callback even though there's no
|
||||
// time left.
|
||||
didTimeout = true;
|
||||
} else {
|
||||
// No timeout.
|
||||
if (!isAnimationFrameScheduled) {
|
||||
// Schedule another animation callback so we retry later.
|
||||
isAnimationFrameScheduled = true;
|
||||
requestAnimationFrameWithTimeout(animationTick);
|
||||
}
|
||||
// Exit without invoking the callback.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// First call anything which has timed out, until we have caught up.
|
||||
callTimedOutCallbacks();
|
||||
|
||||
let currentTime = now();
|
||||
// Next, as long as we have idle time, try calling more callbacks.
|
||||
while (
|
||||
frameDeadline - currentTime > 0 &&
|
||||
headOfPendingCallbacksLinkedList !== null
|
||||
) {
|
||||
const latestCallbackConfig = headOfPendingCallbacksLinkedList;
|
||||
frameDeadlineObject.didTimeout = false;
|
||||
// callUnsafely will remove it from the head of the linked list
|
||||
callUnsafely(latestCallbackConfig, frameDeadlineObject);
|
||||
currentTime = now();
|
||||
}
|
||||
if (headOfPendingCallbacksLinkedList !== null) {
|
||||
if (!isAnimationFrameScheduled) {
|
||||
// Schedule another animation callback so we retry later.
|
||||
isAnimationFrameScheduled = true;
|
||||
scheduleAnimationFrameWithFallbackSupport(animationTick);
|
||||
timeoutTime = -1;
|
||||
var callback = scheduledCallback;
|
||||
scheduledCallback = null;
|
||||
if (callback !== null) {
|
||||
isPerformingIdleWork = true;
|
||||
try {
|
||||
callback(didTimeout);
|
||||
} finally {
|
||||
isPerformingIdleWork = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -318,9 +385,9 @@ if (!canUseDOM) {
|
||||
// something better for old IE.
|
||||
window.addEventListener('message', idleTick, false);
|
||||
|
||||
const animationTick = function(rafTime) {
|
||||
var animationTick = function(rafTime) {
|
||||
isAnimationFrameScheduled = false;
|
||||
let nextFrameTime = rafTime - frameDeadline + activeFrameTime;
|
||||
var nextFrameTime = rafTime - frameDeadline + activeFrameTime;
|
||||
if (
|
||||
nextFrameTime < activeFrameTime &&
|
||||
previousFrameTime < activeFrameTime
|
||||
@@ -349,124 +416,32 @@ if (!canUseDOM) {
|
||||
}
|
||||
};
|
||||
|
||||
scheduleWork = function(
|
||||
callback: FrameCallbackType,
|
||||
options?: {timeout: number},
|
||||
): CallbackIdType /* CallbackConfigType */ {
|
||||
let timeoutTime = -1;
|
||||
if (options != null && typeof options.timeout === 'number') {
|
||||
timeoutTime = now() + options.timeout;
|
||||
}
|
||||
if (
|
||||
nextSoonestTimeoutTime === -1 ||
|
||||
(timeoutTime !== -1 && timeoutTime < nextSoonestTimeoutTime)
|
||||
) {
|
||||
nextSoonestTimeoutTime = timeoutTime;
|
||||
}
|
||||
|
||||
const scheduledCallbackConfig: CallbackConfigType = {
|
||||
scheduledCallback: callback,
|
||||
timeoutTime,
|
||||
prev: null,
|
||||
next: null,
|
||||
};
|
||||
if (headOfPendingCallbacksLinkedList === null) {
|
||||
// Make this callback the head and tail of our list
|
||||
headOfPendingCallbacksLinkedList = scheduledCallbackConfig;
|
||||
tailOfPendingCallbacksLinkedList = scheduledCallbackConfig;
|
||||
} else {
|
||||
// Add latest callback as the new tail of the list
|
||||
scheduledCallbackConfig.prev = tailOfPendingCallbacksLinkedList;
|
||||
// renaming for clarity
|
||||
const oldTailOfPendingCallbacksLinkedList = tailOfPendingCallbacksLinkedList;
|
||||
if (oldTailOfPendingCallbacksLinkedList !== null) {
|
||||
oldTailOfPendingCallbacksLinkedList.next = scheduledCallbackConfig;
|
||||
}
|
||||
tailOfPendingCallbacksLinkedList = scheduledCallbackConfig;
|
||||
}
|
||||
|
||||
if (!isAnimationFrameScheduled) {
|
||||
requestCallback = function(callback, absoluteTimeout) {
|
||||
scheduledCallback = callback;
|
||||
timeoutTime = absoluteTimeout;
|
||||
if (isPerformingIdleWork) {
|
||||
// If we're already performing idle work, an error must have been thrown.
|
||||
// Don't wait for the next frame. Continue working ASAP, in a new event.
|
||||
window.postMessage(messageKey, '*');
|
||||
} else if (!isAnimationFrameScheduled) {
|
||||
// If rAF didn't already schedule one, we need to schedule a frame.
|
||||
// TODO: If this rAF doesn't materialize because the browser throttles, we
|
||||
// might want to still have setTimeout trigger scheduleWork as a backup to ensure
|
||||
// might want to still have setTimeout trigger rIC as a backup to ensure
|
||||
// that we keep performing work.
|
||||
isAnimationFrameScheduled = true;
|
||||
scheduleAnimationFrameWithFallbackSupport(animationTick);
|
||||
requestAnimationFrameWithTimeout(animationTick);
|
||||
}
|
||||
return scheduledCallbackConfig;
|
||||
};
|
||||
|
||||
cancelScheduledWork = function(
|
||||
callbackConfig: CallbackIdType /* CallbackConfigType */,
|
||||
) {
|
||||
if (
|
||||
callbackConfig.prev === null &&
|
||||
headOfPendingCallbacksLinkedList !== callbackConfig
|
||||
) {
|
||||
// this callbackConfig has already been cancelled.
|
||||
// cancelScheduledWork should be idempotent, a no-op after first call.
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* There are four possible cases:
|
||||
* - Head/nodeToRemove/Tail -> null
|
||||
* In this case we set Head and Tail to null.
|
||||
* - Head -> ... middle nodes... -> Tail/nodeToRemove
|
||||
* In this case we point the middle.next to null and put middle as the new
|
||||
* Tail.
|
||||
* - Head/nodeToRemove -> ...middle nodes... -> Tail
|
||||
* In this case we point the middle.prev at null and move the Head to
|
||||
* middle.
|
||||
* - Head -> ... ?some nodes ... -> nodeToRemove -> ... ?some nodes ... -> Tail
|
||||
* In this case we point the Head.next to the Tail and the Tail.prev to
|
||||
* the Head.
|
||||
*/
|
||||
const next = callbackConfig.next;
|
||||
const prev = callbackConfig.prev;
|
||||
callbackConfig.next = null;
|
||||
callbackConfig.prev = null;
|
||||
if (next !== null) {
|
||||
// we have a next
|
||||
|
||||
if (prev !== null) {
|
||||
// we have a prev
|
||||
|
||||
// callbackConfig is somewhere in the middle of a list of 3 or more nodes.
|
||||
prev.next = next;
|
||||
next.prev = prev;
|
||||
return;
|
||||
} else {
|
||||
// there is a next but not a previous one;
|
||||
// callbackConfig is the head of a list of 2 or more other nodes.
|
||||
next.prev = null;
|
||||
headOfPendingCallbacksLinkedList = next;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// there is no next callback config; this must the tail of the list
|
||||
|
||||
if (prev !== null) {
|
||||
// we have a prev
|
||||
|
||||
// callbackConfig is the tail of a list of 2 or more other nodes.
|
||||
prev.next = null;
|
||||
tailOfPendingCallbacksLinkedList = prev;
|
||||
return;
|
||||
} else {
|
||||
// there is no previous callback config;
|
||||
// callbackConfig is the only thing in the linked list,
|
||||
// so both head and tail point to it.
|
||||
headOfPendingCallbacksLinkedList = null;
|
||||
tailOfPendingCallbacksLinkedList = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
cancelCallback = function() {
|
||||
scheduledCallback = null;
|
||||
isIdleScheduled = false;
|
||||
timeoutTime = -1;
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
now as unstable_now,
|
||||
scheduleWork as unstable_scheduleWork,
|
||||
cancelScheduledWork as unstable_cancelScheduledWork,
|
||||
unstable_scheduleWork,
|
||||
unstable_cancelScheduledWork,
|
||||
getCurrentTime as unstable_now,
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import {enableSchedulerTracking} from 'shared/ReactFeatureFlags';
|
||||
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
|
||||
|
||||
export type Interaction = {|
|
||||
__count: number,
|
||||
@@ -17,8 +17,8 @@ export type Interaction = {|
|
||||
|};
|
||||
|
||||
export type Subscriber = {
|
||||
// A new interaction has been created via the track() method.
|
||||
onInteractionTracked: (interaction: Interaction) => void,
|
||||
// A new interaction has been created via the trace() method.
|
||||
onInteractionTraced: (interaction: Interaction) => void,
|
||||
|
||||
// All scheduled async work for an interaction has finished.
|
||||
onInteractionScheduledWorkCompleted: (interaction: Interaction) => void,
|
||||
@@ -61,16 +61,16 @@ const DEFAULT_THREAD_ID = 0;
|
||||
let interactionIDCounter: number = 0;
|
||||
let threadIDCounter: number = 0;
|
||||
|
||||
// Set of currently tracked interactions.
|
||||
// Set of currently traced interactions.
|
||||
// Interactions "stack"–
|
||||
// Meaning that newly tracked interactions are appended to the previously active set.
|
||||
// Meaning that newly traced interactions are appended to the previously active set.
|
||||
// When an interaction goes out of scope, the previous set (if any) is restored.
|
||||
let interactionsRef: InteractionsRef = (null: any);
|
||||
|
||||
// Listener(s) to notify when interactions begin and end.
|
||||
let subscriberRef: SubscriberRef = (null: any);
|
||||
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
interactionsRef = {
|
||||
current: new Set(),
|
||||
};
|
||||
@@ -82,7 +82,7 @@ if (enableSchedulerTracking) {
|
||||
export {interactionsRef as __interactionsRef, subscriberRef as __subscriberRef};
|
||||
|
||||
export function unstable_clear(callback: Function): any {
|
||||
if (!enableSchedulerTracking) {
|
||||
if (!enableSchedulerTracing) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ export function unstable_clear(callback: Function): any {
|
||||
}
|
||||
|
||||
export function unstable_getCurrent(): Set<Interaction> | null {
|
||||
if (!enableSchedulerTracking) {
|
||||
if (!enableSchedulerTracing) {
|
||||
return null;
|
||||
} else {
|
||||
return interactionsRef.current;
|
||||
@@ -108,13 +108,13 @@ export function unstable_getThreadID(): number {
|
||||
return ++threadIDCounter;
|
||||
}
|
||||
|
||||
export function unstable_track(
|
||||
export function unstable_trace(
|
||||
name: string,
|
||||
timestamp: number,
|
||||
callback: Function,
|
||||
threadID: number = DEFAULT_THREAD_ID,
|
||||
): any {
|
||||
if (!enableSchedulerTracking) {
|
||||
if (!enableSchedulerTracing) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ export function unstable_track(
|
||||
|
||||
const prevInteractions = interactionsRef.current;
|
||||
|
||||
// Tracked interactions should stack/accumulate.
|
||||
// Traced interactions should stack/accumulate.
|
||||
// To do that, clone the current interactions.
|
||||
// The previous set will be restored upon completion.
|
||||
const interactions = new Set(prevInteractions);
|
||||
@@ -139,7 +139,7 @@ export function unstable_track(
|
||||
|
||||
try {
|
||||
if (subscriber !== null) {
|
||||
subscriber.onInteractionTracked(interaction);
|
||||
subscriber.onInteractionTraced(interaction);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
@@ -176,7 +176,7 @@ export function unstable_wrap(
|
||||
callback: Function,
|
||||
threadID: number = DEFAULT_THREAD_ID,
|
||||
): Function {
|
||||
if (!enableSchedulerTracking) {
|
||||
if (!enableSchedulerTracing) {
|
||||
return callback;
|
||||
}
|
||||
|
||||
@@ -7,24 +7,24 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {Interaction, Subscriber} from './Tracking';
|
||||
import type {Interaction, Subscriber} from './Tracing';
|
||||
|
||||
import {enableSchedulerTracking} from 'shared/ReactFeatureFlags';
|
||||
import {__subscriberRef} from 'schedule/tracking';
|
||||
import {enableSchedulerTracing} from 'shared/ReactFeatureFlags';
|
||||
import {__subscriberRef} from 'schedule/tracing';
|
||||
|
||||
let subscribers: Set<Subscriber> = (null: any);
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
subscribers = new Set();
|
||||
}
|
||||
|
||||
export function unstable_subscribe(subscriber: Subscriber): void {
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
subscribers.add(subscriber);
|
||||
|
||||
if (subscribers.size === 1) {
|
||||
__subscriberRef.current = {
|
||||
onInteractionScheduledWorkCompleted,
|
||||
onInteractionTracked,
|
||||
onInteractionTraced,
|
||||
onWorkCanceled,
|
||||
onWorkScheduled,
|
||||
onWorkStarted,
|
||||
@@ -35,7 +35,7 @@ export function unstable_subscribe(subscriber: Subscriber): void {
|
||||
}
|
||||
|
||||
export function unstable_unsubscribe(subscriber: Subscriber): void {
|
||||
if (enableSchedulerTracking) {
|
||||
if (enableSchedulerTracing) {
|
||||
subscribers.delete(subscriber);
|
||||
|
||||
if (subscribers.size === 0) {
|
||||
@@ -44,13 +44,13 @@ export function unstable_unsubscribe(subscriber: Subscriber): void {
|
||||
}
|
||||
}
|
||||
|
||||
function onInteractionTracked(interaction: Interaction): void {
|
||||
function onInteractionTraced(interaction: Interaction): void {
|
||||
let didCatchError = false;
|
||||
let caughtError = null;
|
||||
|
||||
subscribers.forEach(subscriber => {
|
||||
try {
|
||||
subscriber.onInteractionTracked(interaction);
|
||||
subscriber.onInteractionTraced(interaction);
|
||||
} catch (error) {
|
||||
if (!didCatchError) {
|
||||
didCatchError = true;
|
||||
174
packages/schedule/src/__tests__/Schedule-test.internal.js
Normal file
174
packages/schedule/src/__tests__/Schedule-test.internal.js
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @emails react-core
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
let scheduleWork;
|
||||
let cancelScheduledWork;
|
||||
let flushWork;
|
||||
let advanceTime;
|
||||
let doWork;
|
||||
let yieldedValues;
|
||||
let yieldValue;
|
||||
let clearYieldedValues;
|
||||
|
||||
describe('Schedule', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
jest.resetModules();
|
||||
|
||||
let _flushWork = null;
|
||||
let timeoutID = -1;
|
||||
let endOfFrame = -1;
|
||||
|
||||
let currentTime = 0;
|
||||
|
||||
flushWork = frameSize => {
|
||||
if (frameSize === null || frameSize === undefined) {
|
||||
frameSize = Infinity;
|
||||
}
|
||||
if (_flushWork === null) {
|
||||
throw new Error('No work is scheduled.');
|
||||
}
|
||||
timeoutID = -1;
|
||||
endOfFrame = currentTime + frameSize;
|
||||
try {
|
||||
_flushWork();
|
||||
} finally {
|
||||
endOfFrame = -1;
|
||||
}
|
||||
const yields = yieldedValues;
|
||||
yieldedValues = [];
|
||||
return yields;
|
||||
};
|
||||
|
||||
advanceTime = ms => {
|
||||
currentTime += ms;
|
||||
jest.advanceTimersByTime(ms);
|
||||
};
|
||||
|
||||
doWork = (label, timeCost) => {
|
||||
advanceTime(timeCost);
|
||||
yieldValue(label);
|
||||
};
|
||||
|
||||
yieldedValues = [];
|
||||
yieldValue = value => {
|
||||
yieldedValues.push(value);
|
||||
};
|
||||
|
||||
clearYieldedValues = () => {
|
||||
const yields = yieldedValues;
|
||||
yieldedValues = [];
|
||||
return yields;
|
||||
};
|
||||
|
||||
function requestCallback(fw, absoluteTimeout) {
|
||||
if (_flushWork !== null) {
|
||||
throw new Error('Work is already scheduled.');
|
||||
}
|
||||
_flushWork = fw;
|
||||
timeoutID = setTimeout(() => {
|
||||
_flushWork(true);
|
||||
}, absoluteTimeout - currentTime);
|
||||
}
|
||||
function cancelCallback() {
|
||||
if (_flushWork === null) {
|
||||
throw new Error('No work is scheduled.');
|
||||
}
|
||||
_flushWork = null;
|
||||
clearTimeout(timeoutID);
|
||||
}
|
||||
function getTimeRemaining() {
|
||||
return endOfFrame;
|
||||
}
|
||||
|
||||
// Override host implementation
|
||||
delete global.performance;
|
||||
global.Date.now = () => currentTime;
|
||||
window._schedMock = [requestCallback, cancelCallback, getTimeRemaining];
|
||||
|
||||
const Schedule = require('schedule');
|
||||
scheduleWork = Schedule.unstable_scheduleWork;
|
||||
cancelScheduledWork = Schedule.unstable_cancelScheduledWork;
|
||||
});
|
||||
|
||||
it('flushes work incrementally', () => {
|
||||
scheduleWork(() => doWork('A', 100));
|
||||
scheduleWork(() => doWork('B', 200));
|
||||
scheduleWork(() => doWork('C', 300));
|
||||
scheduleWork(() => doWork('D', 400));
|
||||
|
||||
expect(flushWork(300)).toEqual(['A', 'B']);
|
||||
expect(flushWork(300)).toEqual(['C']);
|
||||
expect(flushWork(400)).toEqual(['D']);
|
||||
});
|
||||
|
||||
it('cancels work', () => {
|
||||
scheduleWork(() => doWork('A', 100));
|
||||
const callbackHandleB = scheduleWork(() => doWork('B', 200));
|
||||
scheduleWork(() => doWork('C', 300));
|
||||
|
||||
cancelScheduledWork(callbackHandleB);
|
||||
|
||||
expect(flushWork()).toEqual([
|
||||
'A',
|
||||
// B should have been cancelled
|
||||
'C',
|
||||
]);
|
||||
});
|
||||
|
||||
it('prioritizes callbacks according to their timeouts', () => {
|
||||
scheduleWork(() => doWork('A', 10), {timeout: 5000});
|
||||
scheduleWork(() => doWork('B', 20), {timeout: 5000});
|
||||
scheduleWork(() => doWork('C', 30), {timeout: 1000});
|
||||
scheduleWork(() => doWork('D', 40), {timeout: 5000});
|
||||
|
||||
// C should be first because it has the earliest timeout
|
||||
expect(flushWork()).toEqual(['C', 'A', 'B', 'D']);
|
||||
});
|
||||
|
||||
it('times out work', () => {
|
||||
scheduleWork(() => doWork('A', 100), {timeout: 5000});
|
||||
scheduleWork(() => doWork('B', 200), {timeout: 5000});
|
||||
scheduleWork(() => doWork('C', 300), {timeout: 1000});
|
||||
scheduleWork(() => doWork('D', 400), {timeout: 5000});
|
||||
|
||||
// Advance time, but not by enough to flush any work
|
||||
advanceTime(999);
|
||||
expect(clearYieldedValues()).toEqual([]);
|
||||
|
||||
// Advance by just a bit more to flush C
|
||||
advanceTime(1);
|
||||
expect(clearYieldedValues()).toEqual(['C']);
|
||||
|
||||
// Flush the rest
|
||||
advanceTime(4000);
|
||||
expect(clearYieldedValues()).toEqual(['A', 'B', 'D']);
|
||||
});
|
||||
|
||||
it('has a default timeout of 5 seconds', () => {
|
||||
scheduleWork(() => doWork('A', 100));
|
||||
scheduleWork(() => doWork('B', 200));
|
||||
scheduleWork(() => doWork('C', 300), {timeout: 1000});
|
||||
scheduleWork(() => doWork('D', 400));
|
||||
|
||||
// Flush C
|
||||
advanceTime(1000);
|
||||
expect(clearYieldedValues()).toEqual(['C']);
|
||||
|
||||
// Advance time until right before the rest of the work expires
|
||||
advanceTime(3699);
|
||||
expect(clearYieldedValues()).toEqual([]);
|
||||
|
||||
// Now advance by just a bit more
|
||||
advanceTime(1);
|
||||
expect(clearYieldedValues()).toEqual(['A', 'B', 'D']);
|
||||
});
|
||||
});
|
||||
@@ -16,7 +16,7 @@ type FrameTimeoutConfigType = {
|
||||
timePastFrameDeadline: ?number,
|
||||
};
|
||||
|
||||
describe('Schedule', () => {
|
||||
describe('ScheduleDOM', () => {
|
||||
let rAFCallbacks = [];
|
||||
let postMessageCallback;
|
||||
let postMessageEvents = [];
|
||||
@@ -309,10 +309,10 @@ describe('Schedule', () => {
|
||||
const callbackC = jest.fn(() => callbackLog.push('C'));
|
||||
const callbackD = jest.fn(() => callbackLog.push('D'));
|
||||
|
||||
scheduleWork(callbackA); // won't time out
|
||||
scheduleWork(callbackA, {timeout: 100}); // won't time out
|
||||
scheduleWork(callbackB, {timeout: 100}); // times out later
|
||||
scheduleWork(callbackC, {timeout: 2}); // will time out fast
|
||||
scheduleWork(callbackD); // won't time out
|
||||
scheduleWork(callbackD, {timeout: 200}); // won't time out
|
||||
|
||||
advanceOneFrame({timeLeftInFrame: 15}); // runs rAF and postMessage callbacks
|
||||
|
||||
@@ -37,19 +37,27 @@ describe('Scheduling UMD bundle', () => {
|
||||
const api = require('../../index');
|
||||
const umdAPIDev = require('../../npm/umd/schedule.development');
|
||||
const umdAPIProd = require('../../npm/umd/schedule.production.min');
|
||||
const secretAPI = require('react/src/ReactSharedInternals').default;
|
||||
validateForwardedAPIs(api, [umdAPIDev, umdAPIProd, secretAPI.Schedule]);
|
||||
});
|
||||
|
||||
it('should define the same tracking API', () => {
|
||||
const api = require('../../tracking');
|
||||
const umdAPIDev = require('../../npm/umd/schedule-tracking.development');
|
||||
const umdAPIProd = require('../../npm/umd/schedule-tracking.production.min');
|
||||
const umdAPIProfiling = require('../../npm/umd/schedule.profiling.min');
|
||||
const secretAPI = require('react/src/ReactSharedInternals').default;
|
||||
validateForwardedAPIs(api, [
|
||||
umdAPIDev,
|
||||
umdAPIProd,
|
||||
secretAPI.ScheduleTracking,
|
||||
umdAPIProfiling,
|
||||
secretAPI.Schedule,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should define the same tracing API', () => {
|
||||
const api = require('../../tracing');
|
||||
const umdAPIDev = require('../../npm/umd/schedule-tracing.development');
|
||||
const umdAPIProd = require('../../npm/umd/schedule-tracing.production.min');
|
||||
const umdAPIProfiling = require('../../npm/umd/schedule-tracing.profiling.min');
|
||||
const secretAPI = require('react/src/ReactSharedInternals').default;
|
||||
validateForwardedAPIs(api, [
|
||||
umdAPIDev,
|
||||
umdAPIProd,
|
||||
umdAPIProfiling,
|
||||
secretAPI.ScheduleTracing,
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
375
packages/schedule/src/__tests__/Tracing-test.internal.js
Normal file
375
packages/schedule/src/__tests__/Tracing-test.internal.js
Normal file
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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('Tracing', () => {
|
||||
let SchedulerTracing;
|
||||
let ReactFeatureFlags;
|
||||
|
||||
let advanceTimeBy;
|
||||
let currentTime;
|
||||
|
||||
function loadModules({enableSchedulerTracing}) {
|
||||
jest.resetModules();
|
||||
jest.useFakeTimers();
|
||||
|
||||
currentTime = 0;
|
||||
Date.now = jest.fn().mockImplementation(() => currentTime);
|
||||
|
||||
advanceTimeBy = amount => {
|
||||
currentTime += amount;
|
||||
};
|
||||
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableSchedulerTracing = enableSchedulerTracing;
|
||||
|
||||
SchedulerTracing = require('schedule/tracing');
|
||||
}
|
||||
|
||||
describe('enableSchedulerTracing enabled', () => {
|
||||
beforeEach(() => loadModules({enableSchedulerTracing: true}));
|
||||
|
||||
it('should return the value of a traced function', () => {
|
||||
expect(
|
||||
SchedulerTracing.unstable_trace('arbitrary', currentTime, () => 123),
|
||||
).toBe(123);
|
||||
});
|
||||
|
||||
it('should return the value of a clear function', () => {
|
||||
expect(SchedulerTracing.unstable_clear(() => 123)).toBe(123);
|
||||
});
|
||||
|
||||
it('should return the value of a wrapped function', () => {
|
||||
let wrapped;
|
||||
SchedulerTracing.unstable_trace('arbitrary', currentTime, () => {
|
||||
wrapped = SchedulerTracing.unstable_wrap(() => 123);
|
||||
});
|
||||
expect(wrapped()).toBe(123);
|
||||
});
|
||||
|
||||
it('should pass arguments through to a wrapped function', done => {
|
||||
let wrapped;
|
||||
SchedulerTracing.unstable_trace('arbitrary', currentTime, () => {
|
||||
wrapped = SchedulerTracing.unstable_wrap((param1, param2) => {
|
||||
expect(param1).toBe('foo');
|
||||
expect(param2).toBe('bar');
|
||||
done();
|
||||
});
|
||||
});
|
||||
wrapped('foo', 'bar');
|
||||
});
|
||||
|
||||
it('should return an empty set when outside of a traced event', () => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toContainNoInteractions();
|
||||
});
|
||||
|
||||
it('should report the traced interaction from within the trace callback', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracing.unstable_trace('some event', currentTime, () => {
|
||||
const interactions = SchedulerTracing.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'some event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should report the traced interaction from within wrapped callbacks', done => {
|
||||
let wrappedIndirection;
|
||||
|
||||
function indirection() {
|
||||
const interactions = SchedulerTracing.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'some event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracing.unstable_trace('some event', currentTime, () => {
|
||||
wrappedIndirection = SchedulerTracing.unstable_wrap(indirection);
|
||||
});
|
||||
|
||||
advanceTimeBy(50);
|
||||
|
||||
wrappedIndirection();
|
||||
});
|
||||
|
||||
it('should clear the interaction stack for traced callbacks', () => {
|
||||
let innerTestReached = false;
|
||||
|
||||
SchedulerTracing.unstable_trace('outer event', currentTime, () => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
|
||||
SchedulerTracing.unstable_clear(() => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions(
|
||||
[],
|
||||
);
|
||||
|
||||
SchedulerTracing.unstable_trace('inner event', currentTime, () => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'inner event'},
|
||||
]);
|
||||
|
||||
innerTestReached = true;
|
||||
});
|
||||
});
|
||||
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
});
|
||||
|
||||
expect(innerTestReached).toBe(true);
|
||||
});
|
||||
|
||||
it('should clear the interaction stack for wrapped callbacks', () => {
|
||||
let innerTestReached = false;
|
||||
let wrappedIndirection;
|
||||
|
||||
const indirection = jest.fn(() => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
|
||||
SchedulerTracing.unstable_clear(() => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions(
|
||||
[],
|
||||
);
|
||||
|
||||
SchedulerTracing.unstable_trace('inner event', currentTime, () => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'inner event'},
|
||||
]);
|
||||
|
||||
innerTestReached = true;
|
||||
});
|
||||
});
|
||||
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
});
|
||||
|
||||
SchedulerTracing.unstable_trace('outer event', currentTime, () => {
|
||||
wrappedIndirection = SchedulerTracing.unstable_wrap(indirection);
|
||||
});
|
||||
|
||||
wrappedIndirection();
|
||||
|
||||
expect(innerTestReached).toBe(true);
|
||||
});
|
||||
|
||||
it('should support nested traced events', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
let innerIndirectionTraced = false;
|
||||
let outerIndirectionTraced = false;
|
||||
|
||||
function innerIndirection() {
|
||||
const interactions = SchedulerTracing.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
{name: 'inner event', timestamp: 150},
|
||||
]);
|
||||
|
||||
innerIndirectionTraced = true;
|
||||
}
|
||||
|
||||
function outerIndirection() {
|
||||
const interactions = SchedulerTracing.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
outerIndirectionTraced = true;
|
||||
}
|
||||
|
||||
SchedulerTracing.unstable_trace('outer event', currentTime, () => {
|
||||
// Verify the current traced event
|
||||
let interactions = SchedulerTracing.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
advanceTimeBy(50);
|
||||
|
||||
const wrapperOuterIndirection = SchedulerTracing.unstable_wrap(
|
||||
outerIndirection,
|
||||
);
|
||||
|
||||
let wrapperInnerIndirection;
|
||||
let innerEventTraced = false;
|
||||
|
||||
// Verify that a nested event is properly traced
|
||||
SchedulerTracing.unstable_trace('inner event', currentTime, () => {
|
||||
interactions = SchedulerTracing.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
{name: 'inner event', timestamp: 150},
|
||||
]);
|
||||
|
||||
// Verify that a wrapped outer callback is properly traced
|
||||
wrapperOuterIndirection();
|
||||
expect(outerIndirectionTraced).toBe(true);
|
||||
|
||||
wrapperInnerIndirection = SchedulerTracing.unstable_wrap(
|
||||
innerIndirection,
|
||||
);
|
||||
|
||||
innerEventTraced = true;
|
||||
});
|
||||
|
||||
expect(innerEventTraced).toBe(true);
|
||||
|
||||
// Verify that the original event is restored
|
||||
interactions = SchedulerTracing.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
// Verify that a wrapped nested callback is properly traced
|
||||
wrapperInnerIndirection();
|
||||
expect(innerIndirectionTraced).toBe(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should reset state appropriately when an error occurs in a trace callback', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracing.unstable_trace('outer event', currentTime, () => {
|
||||
expect(() => {
|
||||
SchedulerTracing.unstable_trace('inner event', currentTime, () => {
|
||||
throw Error('intentional');
|
||||
});
|
||||
}).toThrow();
|
||||
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reset state appropriately when an error occurs in a wrapped callback', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracing.unstable_trace('outer event', currentTime, () => {
|
||||
let wrappedCallback;
|
||||
|
||||
SchedulerTracing.unstable_trace('inner event', currentTime, () => {
|
||||
wrappedCallback = SchedulerTracing.unstable_wrap(() => {
|
||||
throw Error('intentional');
|
||||
});
|
||||
});
|
||||
|
||||
expect(wrappedCallback).toThrow();
|
||||
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('advanced integration', () => {
|
||||
it('should return a unique threadID per request', () => {
|
||||
expect(SchedulerTracing.unstable_getThreadID()).not.toBe(
|
||||
SchedulerTracing.unstable_getThreadID(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should expose the current set of interactions to be externally manipulated', () => {
|
||||
SchedulerTracing.unstable_trace('outer event', currentTime, () => {
|
||||
expect(SchedulerTracing.__interactionsRef.current).toBe(
|
||||
SchedulerTracing.unstable_getCurrent(),
|
||||
);
|
||||
|
||||
SchedulerTracing.__interactionsRef.current = new Set([
|
||||
{name: 'override event'},
|
||||
]);
|
||||
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'override event'},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should expose a subscriber ref to be externally manipulated', () => {
|
||||
SchedulerTracing.unstable_trace('outer event', currentTime, () => {
|
||||
expect(SchedulerTracing.__subscriberRef).toEqual({
|
||||
current: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('enableSchedulerTracing disabled', () => {
|
||||
beforeEach(() => loadModules({enableSchedulerTracing: false}));
|
||||
|
||||
it('should return the value of a traced function', () => {
|
||||
expect(
|
||||
SchedulerTracing.unstable_trace('arbitrary', currentTime, () => 123),
|
||||
).toBe(123);
|
||||
});
|
||||
|
||||
it('should return the value of a wrapped function', () => {
|
||||
let wrapped;
|
||||
SchedulerTracing.unstable_trace('arbitrary', currentTime, () => {
|
||||
wrapped = SchedulerTracing.unstable_wrap(() => 123);
|
||||
});
|
||||
expect(wrapped()).toBe(123);
|
||||
});
|
||||
|
||||
it('should return null for traced interactions', () => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toBe(null);
|
||||
});
|
||||
|
||||
it('should execute traced callbacks', done => {
|
||||
SchedulerTracing.unstable_trace('some event', currentTime, () => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toBe(null);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the value of a clear function', () => {
|
||||
expect(SchedulerTracing.unstable_clear(() => 123)).toBe(123);
|
||||
});
|
||||
|
||||
it('should execute wrapped callbacks', done => {
|
||||
const wrappedCallback = SchedulerTracing.unstable_wrap(() => {
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toBe(null);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
wrappedCallback();
|
||||
});
|
||||
|
||||
describe('advanced integration', () => {
|
||||
it('should not create unnecessary objects', () => {
|
||||
expect(SchedulerTracing.__interactionsRef).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,41 +8,41 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
describe('Tracking', () => {
|
||||
let SchedulerTracking;
|
||||
describe('Tracing', () => {
|
||||
let SchedulerTracing;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
|
||||
SchedulerTracking = require('schedule/tracking');
|
||||
SchedulerTracing = require('schedule/tracing');
|
||||
});
|
||||
|
||||
it('should return the value of a tracked function', () => {
|
||||
expect(SchedulerTracking.unstable_track('arbitrary', 0, () => 123)).toBe(
|
||||
it('should return the value of a traced function', () => {
|
||||
expect(SchedulerTracing.unstable_trace('arbitrary', 0, () => 123)).toBe(
|
||||
123,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return the value of a wrapped function', () => {
|
||||
let wrapped;
|
||||
SchedulerTracking.unstable_track('arbitrary', 0, () => {
|
||||
wrapped = SchedulerTracking.unstable_wrap(() => 123);
|
||||
SchedulerTracing.unstable_trace('arbitrary', 0, () => {
|
||||
wrapped = SchedulerTracing.unstable_wrap(() => 123);
|
||||
});
|
||||
expect(wrapped()).toBe(123);
|
||||
});
|
||||
|
||||
it('should execute tracked callbacks', done => {
|
||||
SchedulerTracking.unstable_track('some event', 0, () => {
|
||||
it('should execute traced callbacks', done => {
|
||||
SchedulerTracing.unstable_trace('some event', 0, () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the value of a clear function', () => {
|
||||
expect(SchedulerTracking.unstable_clear(() => 123)).toBe(123);
|
||||
expect(SchedulerTracing.unstable_clear(() => 123)).toBe(123);
|
||||
});
|
||||
|
||||
it('should execute wrapped callbacks', done => {
|
||||
const wrappedCallback = SchedulerTracking.unstable_wrap(() => {
|
||||
const wrappedCallback = SchedulerTracing.unstable_wrap(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -8,20 +8,20 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
describe('TrackingSubscriptions', () => {
|
||||
let SchedulerTracking;
|
||||
describe('TracingSubscriptions', () => {
|
||||
let SchedulerTracing;
|
||||
let ReactFeatureFlags;
|
||||
|
||||
let currentTime;
|
||||
|
||||
let onInteractionScheduledWorkCompleted;
|
||||
let onInteractionTracked;
|
||||
let onInteractionTraced;
|
||||
let onWorkCanceled;
|
||||
let onWorkScheduled;
|
||||
let onWorkStarted;
|
||||
let onWorkStopped;
|
||||
let throwInOnInteractionScheduledWorkCompleted;
|
||||
let throwInOnInteractionTracked;
|
||||
let throwInOnInteractionTraced;
|
||||
let throwInOnWorkCanceled;
|
||||
let throwInOnWorkScheduled;
|
||||
let throwInOnWorkStarted;
|
||||
@@ -33,19 +33,19 @@ describe('TrackingSubscriptions', () => {
|
||||
const secondEvent = {id: 1, name: 'second', timestamp: 0};
|
||||
const threadID = 123;
|
||||
|
||||
function loadModules({enableSchedulerTracking, autoSubscribe = true}) {
|
||||
function loadModules({enableSchedulerTracing, autoSubscribe = true}) {
|
||||
jest.resetModules();
|
||||
jest.useFakeTimers();
|
||||
|
||||
currentTime = 0;
|
||||
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableSchedulerTracking = enableSchedulerTracking;
|
||||
ReactFeatureFlags.enableSchedulerTracing = enableSchedulerTracing;
|
||||
|
||||
SchedulerTracking = require('schedule/tracking');
|
||||
SchedulerTracing = require('schedule/tracing');
|
||||
|
||||
throwInOnInteractionScheduledWorkCompleted = false;
|
||||
throwInOnInteractionTracked = false;
|
||||
throwInOnInteractionTraced = false;
|
||||
throwInOnWorkCanceled = false;
|
||||
throwInOnWorkScheduled = false;
|
||||
throwInOnWorkStarted = false;
|
||||
@@ -56,9 +56,9 @@ describe('TrackingSubscriptions', () => {
|
||||
throw Error('Expected error onInteractionScheduledWorkCompleted');
|
||||
}
|
||||
});
|
||||
onInteractionTracked = jest.fn(() => {
|
||||
if (throwInOnInteractionTracked) {
|
||||
throw Error('Expected error onInteractionTracked');
|
||||
onInteractionTraced = jest.fn(() => {
|
||||
if (throwInOnInteractionTraced) {
|
||||
throw Error('Expected error onInteractionTraced');
|
||||
}
|
||||
});
|
||||
onWorkCanceled = jest.fn(() => {
|
||||
@@ -84,7 +84,7 @@ describe('TrackingSubscriptions', () => {
|
||||
|
||||
firstSubscriber = {
|
||||
onInteractionScheduledWorkCompleted,
|
||||
onInteractionTracked,
|
||||
onInteractionTraced,
|
||||
onWorkCanceled,
|
||||
onWorkScheduled,
|
||||
onWorkStarted,
|
||||
@@ -93,7 +93,7 @@ describe('TrackingSubscriptions', () => {
|
||||
|
||||
secondSubscriber = {
|
||||
onInteractionScheduledWorkCompleted: jest.fn(),
|
||||
onInteractionTracked: jest.fn(),
|
||||
onInteractionTraced: jest.fn(),
|
||||
onWorkCanceled: jest.fn(),
|
||||
onWorkScheduled: jest.fn(),
|
||||
onWorkStarted: jest.fn(),
|
||||
@@ -101,49 +101,49 @@ describe('TrackingSubscriptions', () => {
|
||||
};
|
||||
|
||||
if (autoSubscribe) {
|
||||
SchedulerTracking.unstable_subscribe(firstSubscriber);
|
||||
SchedulerTracking.unstable_subscribe(secondSubscriber);
|
||||
SchedulerTracing.unstable_subscribe(firstSubscriber);
|
||||
SchedulerTracing.unstable_subscribe(secondSubscriber);
|
||||
}
|
||||
}
|
||||
|
||||
describe('enabled', () => {
|
||||
beforeEach(() => loadModules({enableSchedulerTracking: true}));
|
||||
beforeEach(() => loadModules({enableSchedulerTracing: true}));
|
||||
|
||||
it('should lazily subscribe to tracking and unsubscribe again if there are no external subscribers', () => {
|
||||
loadModules({enableSchedulerTracking: true, autoSubscribe: false});
|
||||
it('should lazily subscribe to tracing and unsubscribe again if there are no external subscribers', () => {
|
||||
loadModules({enableSchedulerTracing: true, autoSubscribe: false});
|
||||
|
||||
expect(SchedulerTracking.__subscriberRef.current).toBe(null);
|
||||
SchedulerTracking.unstable_subscribe(firstSubscriber);
|
||||
expect(SchedulerTracking.__subscriberRef.current).toBeDefined();
|
||||
SchedulerTracking.unstable_subscribe(secondSubscriber);
|
||||
expect(SchedulerTracking.__subscriberRef.current).toBeDefined();
|
||||
SchedulerTracking.unstable_unsubscribe(secondSubscriber);
|
||||
expect(SchedulerTracking.__subscriberRef.current).toBeDefined();
|
||||
SchedulerTracking.unstable_unsubscribe(firstSubscriber);
|
||||
expect(SchedulerTracking.__subscriberRef.current).toBe(null);
|
||||
expect(SchedulerTracing.__subscriberRef.current).toBe(null);
|
||||
SchedulerTracing.unstable_subscribe(firstSubscriber);
|
||||
expect(SchedulerTracing.__subscriberRef.current).toBeDefined();
|
||||
SchedulerTracing.unstable_subscribe(secondSubscriber);
|
||||
expect(SchedulerTracing.__subscriberRef.current).toBeDefined();
|
||||
SchedulerTracing.unstable_unsubscribe(secondSubscriber);
|
||||
expect(SchedulerTracing.__subscriberRef.current).toBeDefined();
|
||||
SchedulerTracing.unstable_unsubscribe(firstSubscriber);
|
||||
expect(SchedulerTracing.__subscriberRef.current).toBe(null);
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should cover onInteractionTracked/onWorkStarted within', done => {
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
it('should cover onInteractionTraced/onWorkStarted within', done => {
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
const mock = jest.fn();
|
||||
|
||||
// It should call the callback before re-throwing
|
||||
throwInOnInteractionTracked = true;
|
||||
throwInOnInteractionTraced = true;
|
||||
expect(() =>
|
||||
SchedulerTracking.unstable_track(
|
||||
SchedulerTracing.unstable_trace(
|
||||
secondEvent.name,
|
||||
currentTime,
|
||||
mock,
|
||||
threadID,
|
||||
),
|
||||
).toThrow('Expected error onInteractionTracked');
|
||||
throwInOnInteractionTracked = false;
|
||||
).toThrow('Expected error onInteractionTraced');
|
||||
throwInOnInteractionTraced = false;
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
|
||||
throwInOnWorkStarted = true;
|
||||
expect(() =>
|
||||
SchedulerTracking.unstable_track(
|
||||
SchedulerTracing.unstable_trace(
|
||||
secondEvent.name,
|
||||
currentTime,
|
||||
mock,
|
||||
@@ -153,32 +153,30 @@ describe('TrackingSubscriptions', () => {
|
||||
expect(mock).toHaveBeenCalledTimes(2);
|
||||
|
||||
// It should restore the previous/outer interactions
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
firstEvent,
|
||||
]);
|
||||
|
||||
// It should call other subscribers despite the earlier error
|
||||
expect(secondSubscriber.onInteractionTracked).toHaveBeenCalledTimes(
|
||||
3,
|
||||
);
|
||||
expect(secondSubscriber.onInteractionTraced).toHaveBeenCalledTimes(3);
|
||||
expect(secondSubscriber.onWorkStarted).toHaveBeenCalledTimes(3);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should cover onWorkStopped within track', done => {
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
it('should cover onWorkStopped within trace', done => {
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
let innerInteraction;
|
||||
const mock = jest.fn(() => {
|
||||
innerInteraction = Array.from(
|
||||
SchedulerTracking.unstable_getCurrent(),
|
||||
SchedulerTracing.unstable_getCurrent(),
|
||||
)[1];
|
||||
});
|
||||
|
||||
throwInOnWorkStopped = true;
|
||||
expect(() =>
|
||||
SchedulerTracking.unstable_track(
|
||||
SchedulerTracing.unstable_trace(
|
||||
secondEvent.name,
|
||||
currentTime,
|
||||
mock,
|
||||
@@ -187,7 +185,7 @@ describe('TrackingSubscriptions', () => {
|
||||
throwInOnWorkStopped = false;
|
||||
|
||||
// It should restore the previous/outer interactions
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
firstEvent,
|
||||
]);
|
||||
|
||||
@@ -201,13 +199,13 @@ describe('TrackingSubscriptions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should cover onInteractionScheduledWorkCompleted within track', done => {
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
it('should cover onInteractionScheduledWorkCompleted within trace', done => {
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
const mock = jest.fn();
|
||||
|
||||
throwInOnInteractionScheduledWorkCompleted = true;
|
||||
expect(() =>
|
||||
SchedulerTracking.unstable_track(
|
||||
SchedulerTracing.unstable_trace(
|
||||
secondEvent.name,
|
||||
currentTime,
|
||||
mock,
|
||||
@@ -216,7 +214,7 @@ describe('TrackingSubscriptions', () => {
|
||||
throwInOnInteractionScheduledWorkCompleted = false;
|
||||
|
||||
// It should restore the previous/outer interactions
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
firstEvent,
|
||||
]);
|
||||
|
||||
@@ -229,12 +227,12 @@ describe('TrackingSubscriptions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should cover the callback within track', done => {
|
||||
it('should cover the callback within trace', done => {
|
||||
expect(onWorkStarted).not.toHaveBeenCalled();
|
||||
expect(onWorkStopped).not.toHaveBeenCalled();
|
||||
|
||||
expect(() => {
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
throw Error('Expected error callback');
|
||||
});
|
||||
}).toThrow('Expected error callback');
|
||||
@@ -246,14 +244,14 @@ describe('TrackingSubscriptions', () => {
|
||||
});
|
||||
|
||||
it('should cover onWorkScheduled within wrap', done => {
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
const interaction = Array.from(
|
||||
SchedulerTracking.unstable_getCurrent(),
|
||||
SchedulerTracing.unstable_getCurrent(),
|
||||
)[0];
|
||||
const beforeCount = interaction.__count;
|
||||
|
||||
throwInOnWorkScheduled = true;
|
||||
expect(() => SchedulerTracking.unstable_wrap(() => {})).toThrow(
|
||||
expect(() => SchedulerTracing.unstable_wrap(() => {})).toThrow(
|
||||
'Expected error onWorkScheduled',
|
||||
);
|
||||
|
||||
@@ -270,9 +268,9 @@ describe('TrackingSubscriptions', () => {
|
||||
it('should cover onWorkStarted within wrap', () => {
|
||||
const mock = jest.fn();
|
||||
let interaction, wrapped;
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
interaction = Array.from(SchedulerTracking.unstable_getCurrent())[0];
|
||||
wrapped = SchedulerTracking.unstable_wrap(mock);
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
|
||||
wrapped = SchedulerTracing.unstable_wrap(mock);
|
||||
});
|
||||
expect(interaction.__count).toBe(1);
|
||||
|
||||
@@ -290,30 +288,26 @@ describe('TrackingSubscriptions', () => {
|
||||
});
|
||||
|
||||
it('should cover onWorkStopped within wrap', done => {
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
const outerInteraction = Array.from(
|
||||
SchedulerTracking.unstable_getCurrent(),
|
||||
SchedulerTracing.unstable_getCurrent(),
|
||||
)[0];
|
||||
expect(outerInteraction.__count).toBe(1);
|
||||
|
||||
let wrapped;
|
||||
let innerInteraction;
|
||||
|
||||
SchedulerTracking.unstable_track(
|
||||
secondEvent.name,
|
||||
currentTime,
|
||||
() => {
|
||||
innerInteraction = Array.from(
|
||||
SchedulerTracking.unstable_getCurrent(),
|
||||
)[1];
|
||||
expect(outerInteraction.__count).toBe(1);
|
||||
expect(innerInteraction.__count).toBe(1);
|
||||
SchedulerTracing.unstable_trace(secondEvent.name, currentTime, () => {
|
||||
innerInteraction = Array.from(
|
||||
SchedulerTracing.unstable_getCurrent(),
|
||||
)[1];
|
||||
expect(outerInteraction.__count).toBe(1);
|
||||
expect(innerInteraction.__count).toBe(1);
|
||||
|
||||
wrapped = SchedulerTracking.unstable_wrap(jest.fn());
|
||||
expect(outerInteraction.__count).toBe(2);
|
||||
expect(innerInteraction.__count).toBe(2);
|
||||
},
|
||||
);
|
||||
wrapped = SchedulerTracing.unstable_wrap(jest.fn());
|
||||
expect(outerInteraction.__count).toBe(2);
|
||||
expect(innerInteraction.__count).toBe(2);
|
||||
});
|
||||
|
||||
expect(outerInteraction.__count).toBe(2);
|
||||
expect(innerInteraction.__count).toBe(1);
|
||||
@@ -323,7 +317,7 @@ describe('TrackingSubscriptions', () => {
|
||||
throwInOnWorkStopped = false;
|
||||
|
||||
// It should restore the previous interactions
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
expect(SchedulerTracing.unstable_getCurrent()).toMatchInteractions([
|
||||
outerInteraction,
|
||||
]);
|
||||
|
||||
@@ -343,9 +337,9 @@ describe('TrackingSubscriptions', () => {
|
||||
|
||||
let wrapped;
|
||||
let interaction;
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
interaction = Array.from(SchedulerTracking.unstable_getCurrent())[0];
|
||||
wrapped = SchedulerTracking.unstable_wrap(() => {
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
|
||||
wrapped = SchedulerTracing.unstable_wrap(() => {
|
||||
throw Error('Expected error wrap');
|
||||
});
|
||||
});
|
||||
@@ -364,9 +358,9 @@ describe('TrackingSubscriptions', () => {
|
||||
|
||||
it('should cover onWorkCanceled within wrap', () => {
|
||||
let interaction, wrapped;
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
interaction = Array.from(SchedulerTracking.unstable_getCurrent())[0];
|
||||
wrapped = SchedulerTracking.unstable_wrap(jest.fn());
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
|
||||
wrapped = SchedulerTracing.unstable_wrap(jest.fn());
|
||||
});
|
||||
expect(interaction.__count).toBe(1);
|
||||
|
||||
@@ -386,16 +380,16 @@ describe('TrackingSubscriptions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('calls lifecycle methods for track', () => {
|
||||
expect(onInteractionTracked).not.toHaveBeenCalled();
|
||||
it('calls lifecycle methods for trace', () => {
|
||||
expect(onInteractionTraced).not.toHaveBeenCalled();
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
SchedulerTracking.unstable_track(
|
||||
SchedulerTracing.unstable_trace(
|
||||
firstEvent.name,
|
||||
currentTime,
|
||||
() => {
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
firstEvent,
|
||||
);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
@@ -406,12 +400,12 @@ describe('TrackingSubscriptions', () => {
|
||||
);
|
||||
expect(onWorkStopped).not.toHaveBeenCalled();
|
||||
|
||||
SchedulerTracking.unstable_track(
|
||||
SchedulerTracing.unstable_trace(
|
||||
secondEvent.name,
|
||||
currentTime,
|
||||
() => {
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
secondEvent,
|
||||
);
|
||||
expect(
|
||||
@@ -458,19 +452,19 @@ describe('TrackingSubscriptions', () => {
|
||||
const unwrapped = jest.fn();
|
||||
let wrapped;
|
||||
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
firstEvent,
|
||||
);
|
||||
|
||||
SchedulerTracking.unstable_track(secondEvent.name, currentTime, () => {
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTracked).toHaveBeenLastNotifiedOfInteraction(
|
||||
SchedulerTracing.unstable_trace(secondEvent.name, currentTime, () => {
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
|
||||
secondEvent,
|
||||
);
|
||||
|
||||
wrapped = SchedulerTracking.unstable_wrap(unwrapped, threadID);
|
||||
wrapped = SchedulerTracing.unstable_wrap(unwrapped, threadID);
|
||||
expect(onWorkScheduled).toHaveBeenCalledTimes(1);
|
||||
expect(onWorkScheduled).toHaveBeenLastNotifiedOfWork(
|
||||
new Set([firstEvent, secondEvent]),
|
||||
@@ -479,7 +473,7 @@ describe('TrackingSubscriptions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
wrapped();
|
||||
@@ -510,14 +504,14 @@ describe('TrackingSubscriptions', () => {
|
||||
const fnOne = jest.fn();
|
||||
const fnTwo = jest.fn();
|
||||
let wrappedOne, wrappedTwo;
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
wrappedOne = SchedulerTracking.unstable_wrap(fnOne, threadID);
|
||||
SchedulerTracking.unstable_track(secondEvent.name, currentTime, () => {
|
||||
wrappedTwo = SchedulerTracking.unstable_wrap(fnTwo, threadID);
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
wrappedOne = SchedulerTracing.unstable_wrap(fnOne, threadID);
|
||||
SchedulerTracing.unstable_trace(secondEvent.name, currentTime, () => {
|
||||
wrappedTwo = SchedulerTracing.unstable_wrap(fnTwo, threadID);
|
||||
});
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
expect(onWorkCanceled).not.toHaveBeenCalled();
|
||||
expect(onWorkStarted).toHaveBeenCalledTimes(2);
|
||||
@@ -553,25 +547,25 @@ describe('TrackingSubscriptions', () => {
|
||||
|
||||
it('should not end an interaction twice if wrap is used to schedule follow up work within another wrap', () => {
|
||||
const fnOne = jest.fn(() => {
|
||||
wrappedTwo = SchedulerTracking.unstable_wrap(fnTwo, threadID);
|
||||
wrappedTwo = SchedulerTracing.unstable_wrap(fnTwo, threadID);
|
||||
});
|
||||
const fnTwo = jest.fn();
|
||||
let wrappedOne, wrappedTwo;
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
wrappedOne = SchedulerTracking.unstable_wrap(fnOne, threadID);
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
wrappedOne = SchedulerTracing.unstable_wrap(fnOne, threadID);
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
wrappedOne();
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
wrappedTwo();
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -582,29 +576,29 @@ describe('TrackingSubscriptions', () => {
|
||||
const unwrappedOne = jest.fn();
|
||||
const unwrappedTwo = jest.fn();
|
||||
let wrappedOne, wrappedTwo;
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {
|
||||
wrappedOne = SchedulerTracking.unstable_wrap(unwrappedOne, threadID);
|
||||
wrappedTwo = SchedulerTracking.unstable_wrap(unwrappedTwo, threadID);
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {
|
||||
wrappedOne = SchedulerTracing.unstable_wrap(unwrappedOne, threadID);
|
||||
wrappedTwo = SchedulerTracing.unstable_wrap(unwrappedTwo, threadID);
|
||||
});
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
wrappedOne();
|
||||
|
||||
expect(unwrappedOne).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
wrappedOne();
|
||||
|
||||
expect(unwrappedOne).toHaveBeenCalledTimes(2);
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
|
||||
|
||||
wrappedTwo();
|
||||
|
||||
expect(onInteractionTracked).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
|
||||
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
|
||||
expect(
|
||||
onInteractionScheduledWorkCompleted,
|
||||
@@ -612,15 +606,15 @@ describe('TrackingSubscriptions', () => {
|
||||
});
|
||||
|
||||
it('should unsubscribe', () => {
|
||||
SchedulerTracking.unstable_unsubscribe(firstSubscriber);
|
||||
SchedulerTracking.unstable_track(firstEvent.name, currentTime, () => {});
|
||||
SchedulerTracing.unstable_unsubscribe(firstSubscriber);
|
||||
SchedulerTracing.unstable_trace(firstEvent.name, currentTime, () => {});
|
||||
|
||||
expect(onInteractionTracked).not.toHaveBeenCalled();
|
||||
expect(onInteractionTraced).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('disabled', () => {
|
||||
beforeEach(() => loadModules({enableSchedulerTracking: false}));
|
||||
beforeEach(() => loadModules({enableSchedulerTracing: false}));
|
||||
|
||||
// TODO
|
||||
});
|
||||
@@ -1,375 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* 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('Tracking', () => {
|
||||
let SchedulerTracking;
|
||||
let ReactFeatureFlags;
|
||||
|
||||
let advanceTimeBy;
|
||||
let currentTime;
|
||||
|
||||
function loadModules({enableSchedulerTracking}) {
|
||||
jest.resetModules();
|
||||
jest.useFakeTimers();
|
||||
|
||||
currentTime = 0;
|
||||
Date.now = jest.fn().mockImplementation(() => currentTime);
|
||||
|
||||
advanceTimeBy = amount => {
|
||||
currentTime += amount;
|
||||
};
|
||||
|
||||
ReactFeatureFlags = require('shared/ReactFeatureFlags');
|
||||
ReactFeatureFlags.enableSchedulerTracking = enableSchedulerTracking;
|
||||
|
||||
SchedulerTracking = require('schedule/tracking');
|
||||
}
|
||||
|
||||
describe('enableSchedulerTracking enabled', () => {
|
||||
beforeEach(() => loadModules({enableSchedulerTracking: true}));
|
||||
|
||||
it('should return the value of a tracked function', () => {
|
||||
expect(
|
||||
SchedulerTracking.unstable_track('arbitrary', currentTime, () => 123),
|
||||
).toBe(123);
|
||||
});
|
||||
|
||||
it('should return the value of a clear function', () => {
|
||||
expect(SchedulerTracking.unstable_clear(() => 123)).toBe(123);
|
||||
});
|
||||
|
||||
it('should return the value of a wrapped function', () => {
|
||||
let wrapped;
|
||||
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;
|
||||
SchedulerTracking.unstable_track('arbitrary', currentTime, () => {
|
||||
wrapped = SchedulerTracking.unstable_wrap((param1, param2) => {
|
||||
expect(param1).toBe('foo');
|
||||
expect(param2).toBe('bar');
|
||||
done();
|
||||
});
|
||||
});
|
||||
wrapped('foo', 'bar');
|
||||
});
|
||||
|
||||
it('should return an empty set when outside of a tracked event', () => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toContainNoInteractions();
|
||||
});
|
||||
|
||||
it('should report the tracked interaction from within the track callback', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracking.unstable_track('some event', currentTime, () => {
|
||||
const interactions = SchedulerTracking.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'some event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should report the tracked interaction from within wrapped callbacks', done => {
|
||||
let wrappedIndirection;
|
||||
|
||||
function indirection() {
|
||||
const interactions = SchedulerTracking.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'some event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracking.unstable_track('some event', currentTime, () => {
|
||||
wrappedIndirection = SchedulerTracking.unstable_wrap(indirection);
|
||||
});
|
||||
|
||||
advanceTimeBy(50);
|
||||
|
||||
wrappedIndirection();
|
||||
});
|
||||
|
||||
it('should clear the interaction stack for tracked callbacks', () => {
|
||||
let innerTestReached = false;
|
||||
|
||||
SchedulerTracking.unstable_track('outer event', currentTime, () => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
|
||||
SchedulerTracking.unstable_clear(() => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions(
|
||||
[],
|
||||
);
|
||||
|
||||
SchedulerTracking.unstable_track('inner event', currentTime, () => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions(
|
||||
[{name: 'inner event'}],
|
||||
);
|
||||
|
||||
innerTestReached = true;
|
||||
});
|
||||
});
|
||||
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
});
|
||||
|
||||
expect(innerTestReached).toBe(true);
|
||||
});
|
||||
|
||||
it('should clear the interaction stack for wrapped callbacks', () => {
|
||||
let innerTestReached = false;
|
||||
let wrappedIndirection;
|
||||
|
||||
const indirection = jest.fn(() => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
|
||||
SchedulerTracking.unstable_clear(() => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions(
|
||||
[],
|
||||
);
|
||||
|
||||
SchedulerTracking.unstable_track('inner event', currentTime, () => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions(
|
||||
[{name: 'inner event'}],
|
||||
);
|
||||
|
||||
innerTestReached = true;
|
||||
});
|
||||
});
|
||||
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event'},
|
||||
]);
|
||||
});
|
||||
|
||||
SchedulerTracking.unstable_track('outer event', currentTime, () => {
|
||||
wrappedIndirection = SchedulerTracking.unstable_wrap(indirection);
|
||||
});
|
||||
|
||||
wrappedIndirection();
|
||||
|
||||
expect(innerTestReached).toBe(true);
|
||||
});
|
||||
|
||||
it('should support nested tracked events', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
let innerIndirectionTracked = false;
|
||||
let outerIndirectionTracked = false;
|
||||
|
||||
function innerIndirection() {
|
||||
const interactions = SchedulerTracking.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
{name: 'inner event', timestamp: 150},
|
||||
]);
|
||||
|
||||
innerIndirectionTracked = true;
|
||||
}
|
||||
|
||||
function outerIndirection() {
|
||||
const interactions = SchedulerTracking.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
outerIndirectionTracked = true;
|
||||
}
|
||||
|
||||
SchedulerTracking.unstable_track('outer event', currentTime, () => {
|
||||
// Verify the current tracked event
|
||||
let interactions = SchedulerTracking.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
advanceTimeBy(50);
|
||||
|
||||
const wrapperOuterIndirection = SchedulerTracking.unstable_wrap(
|
||||
outerIndirection,
|
||||
);
|
||||
|
||||
let wrapperInnerIndirection;
|
||||
let innerEventTracked = false;
|
||||
|
||||
// Verify that a nested event is properly tracked
|
||||
SchedulerTracking.unstable_track('inner event', currentTime, () => {
|
||||
interactions = SchedulerTracking.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
{name: 'inner event', timestamp: 150},
|
||||
]);
|
||||
|
||||
// Verify that a wrapped outer callback is properly tracked
|
||||
wrapperOuterIndirection();
|
||||
expect(outerIndirectionTracked).toBe(true);
|
||||
|
||||
wrapperInnerIndirection = SchedulerTracking.unstable_wrap(
|
||||
innerIndirection,
|
||||
);
|
||||
|
||||
innerEventTracked = true;
|
||||
});
|
||||
|
||||
expect(innerEventTracked).toBe(true);
|
||||
|
||||
// Verify that the original event is restored
|
||||
interactions = SchedulerTracking.unstable_getCurrent();
|
||||
expect(interactions).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
// Verify that a wrapped nested callback is properly tracked
|
||||
wrapperInnerIndirection();
|
||||
expect(innerIndirectionTracked).toBe(true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('error handling', () => {
|
||||
it('should reset state appropriately when an error occurs in a track callback', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracking.unstable_track('outer event', currentTime, () => {
|
||||
expect(() => {
|
||||
SchedulerTracking.unstable_track('inner event', currentTime, () => {
|
||||
throw Error('intentional');
|
||||
});
|
||||
}).toThrow();
|
||||
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should reset state appropriately when an error occurs in a wrapped callback', done => {
|
||||
advanceTimeBy(100);
|
||||
|
||||
SchedulerTracking.unstable_track('outer event', currentTime, () => {
|
||||
let wrappedCallback;
|
||||
|
||||
SchedulerTracking.unstable_track('inner event', currentTime, () => {
|
||||
wrappedCallback = SchedulerTracking.unstable_wrap(() => {
|
||||
throw Error('intentional');
|
||||
});
|
||||
});
|
||||
|
||||
expect(wrappedCallback).toThrow();
|
||||
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'outer event', timestamp: 100},
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('advanced integration', () => {
|
||||
it('should return a unique threadID per request', () => {
|
||||
expect(SchedulerTracking.unstable_getThreadID()).not.toBe(
|
||||
SchedulerTracking.unstable_getThreadID(),
|
||||
);
|
||||
});
|
||||
|
||||
it('should expose the current set of interactions to be externally manipulated', () => {
|
||||
SchedulerTracking.unstable_track('outer event', currentTime, () => {
|
||||
expect(SchedulerTracking.__interactionsRef.current).toBe(
|
||||
SchedulerTracking.unstable_getCurrent(),
|
||||
);
|
||||
|
||||
SchedulerTracking.__interactionsRef.current = new Set([
|
||||
{name: 'override event'},
|
||||
]);
|
||||
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toMatchInteractions([
|
||||
{name: 'override event'},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should expose a subscriber ref to be externally manipulated', () => {
|
||||
SchedulerTracking.unstable_track('outer event', currentTime, () => {
|
||||
expect(SchedulerTracking.__subscriberRef).toEqual({
|
||||
current: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('enableSchedulerTracking disabled', () => {
|
||||
beforeEach(() => loadModules({enableSchedulerTracking: false}));
|
||||
|
||||
it('should return the value of a tracked function', () => {
|
||||
expect(
|
||||
SchedulerTracking.unstable_track('arbitrary', currentTime, () => 123),
|
||||
).toBe(123);
|
||||
});
|
||||
|
||||
it('should return the value of a wrapped function', () => {
|
||||
let wrapped;
|
||||
SchedulerTracking.unstable_track('arbitrary', currentTime, () => {
|
||||
wrapped = SchedulerTracking.unstable_wrap(() => 123);
|
||||
});
|
||||
expect(wrapped()).toBe(123);
|
||||
});
|
||||
|
||||
it('should return null for tracked interactions', () => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toBe(null);
|
||||
});
|
||||
|
||||
it('should execute tracked callbacks', done => {
|
||||
SchedulerTracking.unstable_track('some event', currentTime, () => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toBe(null);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the value of a clear function', () => {
|
||||
expect(SchedulerTracking.unstable_clear(() => 123)).toBe(123);
|
||||
});
|
||||
|
||||
it('should execute wrapped callbacks', done => {
|
||||
const wrappedCallback = SchedulerTracking.unstable_wrap(() => {
|
||||
expect(SchedulerTracking.unstable_getCurrent()).toBe(null);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
wrappedCallback();
|
||||
});
|
||||
|
||||
describe('advanced integration', () => {
|
||||
it('should not create unnecessary objects', () => {
|
||||
expect(SchedulerTracking.__interactionsRef).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -9,5 +9,5 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
export * from './src/Tracking';
|
||||
export * from './src/TrackingSubscriptions';
|
||||
export * from './src/Tracing';
|
||||
export * from './src/TracingSubscriptions';
|
||||
@@ -37,8 +37,8 @@ export const warnAboutLegacyContextAPI = false;
|
||||
// Gather advanced timing metrics for Profiler subtrees.
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
|
||||
// Track which interactions trigger each commit.
|
||||
export const enableSchedulerTracking = __PROFILE__;
|
||||
// Trace which interactions trigger each commit.
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
|
||||
// Only used in www builds.
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
'use strict';
|
||||
|
||||
// TODO: this is special because it gets imported during build.
|
||||
module.exports = '16.5.0';
|
||||
module.exports = '16.5.2';
|
||||
|
||||
@@ -15,9 +15,11 @@ describe('ReactDOMFrameScheduling', () => {
|
||||
try {
|
||||
global.requestAnimationFrame = undefined;
|
||||
jest.resetModules();
|
||||
expect(() => require('react-dom')).toWarnDev(
|
||||
spyOnDevAndProd(console, 'error');
|
||||
require('react-dom');
|
||||
expect(console.error.calls.count()).toEqual(1);
|
||||
expect(console.error.calls.argsFor(0)[0]).toMatch(
|
||||
"This browser doesn't support requestAnimationFrame.",
|
||||
{withoutStack: true},
|
||||
);
|
||||
} finally {
|
||||
global.requestAnimationFrame = previousRAF;
|
||||
|
||||
@@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false;
|
||||
export const warnAboutLegacyContextAPI = __DEV__;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
export const enableSchedulerTracking = __PROFILE__;
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false;
|
||||
export const warnAboutLegacyContextAPI = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
export const enableSchedulerTracking = __PROFILE__;
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export const {
|
||||
export const enableUserTimingAPI = __DEV__;
|
||||
export const warnAboutLegacyContextAPI = __DEV__;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
export const enableSchedulerTracking = __PROFILE__;
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
|
||||
// Only used in www builds.
|
||||
|
||||
@@ -21,7 +21,7 @@ export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
|
||||
export const warnAboutDeprecatedLifecycles = false;
|
||||
export const warnAboutLegacyContextAPI = false;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
export const enableSchedulerTracking = __PROFILE__;
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false;
|
||||
export const warnAboutLegacyContextAPI = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
export const enableSchedulerTracking = __PROFILE__;
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false;
|
||||
export const warnAboutLegacyContextAPI = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
|
||||
export const enableProfilerTimer = false;
|
||||
export const enableSchedulerTracking = false;
|
||||
export const enableSchedulerTracing = false;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
export const disableInputAttributeSyncing = false;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export const warnAboutDeprecatedLifecycles = false;
|
||||
export const warnAboutLegacyContextAPI = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
|
||||
export const enableProfilerTimer = false;
|
||||
export const enableSchedulerTracking = false;
|
||||
export const enableSchedulerTracing = false;
|
||||
export const enableSuspenseServerRenderer = false;
|
||||
|
||||
// Only used in www builds.
|
||||
|
||||
@@ -34,7 +34,7 @@ export const warnAboutLegacyContextAPI = __DEV__;
|
||||
export let enableUserTimingAPI = __DEV__;
|
||||
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
export const enableSchedulerTracking = __PROFILE__;
|
||||
export const enableSchedulerTracing = __PROFILE__;
|
||||
|
||||
let refCount = 0;
|
||||
export function addUserTimingListener() {
|
||||
|
||||
@@ -18,10 +18,10 @@ const {
|
||||
unstable_getCurrent,
|
||||
unstable_getThreadID,
|
||||
unstable_subscribe,
|
||||
unstable_track,
|
||||
unstable_trace,
|
||||
unstable_unsubscribe,
|
||||
unstable_wrap,
|
||||
} = ReactInternals.ScheduleTracking;
|
||||
} = ReactInternals.ScheduleTracing;
|
||||
|
||||
export {
|
||||
__interactionsRef,
|
||||
@@ -30,7 +30,7 @@ export {
|
||||
unstable_getCurrent,
|
||||
unstable_getThreadID,
|
||||
unstable_subscribe,
|
||||
unstable_track,
|
||||
unstable_trace,
|
||||
unstable_unsubscribe,
|
||||
unstable_wrap,
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "simple-cache-provider",
|
||||
"description": "A basic cache for React applications",
|
||||
"version": "0.8.0",
|
||||
"version": "0.10.0",
|
||||
"repository": "facebook/react",
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -285,5 +285,7 @@
|
||||
"283": "Element type is invalid. Received a promise that resolves to: %s. Promise elements must resolve to a class or function.",
|
||||
"284": "Expected ref to be a function, a string, an object returned by React.createRef(), or null.",
|
||||
"285": "The root failed to unmount after an error. This is likely a bug in React. Please file an issue.",
|
||||
"286": "%s(...): the first argument must be a React class instance. Instead received: %s."
|
||||
"286": "%s(...): the first argument must be a React class instance. Instead received: %s.",
|
||||
"287": "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `schedule/tracking` module with `schedule/tracking-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling",
|
||||
"288": "It is not supported to run the profiling version of a renderer (for example, `react-dom/profiling`) without also replacing the `schedule/tracing` module with `schedule/tracing-profiling`. Your bundler might have a setting for aliasing both modules. Learn more at http://fb.me/react-profiling"
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ if (process.env.REACT_CLASS_EQUIVALENCE_TEST) {
|
||||
}
|
||||
|
||||
expect.extend({
|
||||
...require('./matchers/interactionTracking'),
|
||||
...require('./matchers/interactionTracing'),
|
||||
...require('./matchers/toWarnDev'),
|
||||
...require('./matchers/testRenderer'),
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ global.spyOnProd = function(...args) {
|
||||
};
|
||||
|
||||
expect.extend({
|
||||
...require('../matchers/interactionTracking'),
|
||||
...require('../matchers/interactionTracing'),
|
||||
...require('../matchers/toWarnDev'),
|
||||
...require('../matchers/testRenderer'),
|
||||
});
|
||||
|
||||
@@ -38,6 +38,7 @@ process.on('unhandledRejection', err => {
|
||||
const {
|
||||
UMD_DEV,
|
||||
UMD_PROD,
|
||||
UMD_PROFILING,
|
||||
NODE_DEV,
|
||||
NODE_PROD,
|
||||
NODE_PROFILING,
|
||||
@@ -113,6 +114,7 @@ function getBabelConfig(updateBabelOptions, bundleType, filename) {
|
||||
});
|
||||
case UMD_DEV:
|
||||
case UMD_PROD:
|
||||
case UMD_PROFILING:
|
||||
case NODE_DEV:
|
||||
case NODE_PROD:
|
||||
case NODE_PROFILING:
|
||||
@@ -158,6 +160,7 @@ function getFormat(bundleType) {
|
||||
switch (bundleType) {
|
||||
case UMD_DEV:
|
||||
case UMD_PROD:
|
||||
case UMD_PROFILING:
|
||||
return `umd`;
|
||||
case NODE_DEV:
|
||||
case NODE_PROD:
|
||||
@@ -183,6 +186,8 @@ function getFilename(name, globalName, bundleType) {
|
||||
return `${name}.development.js`;
|
||||
case UMD_PROD:
|
||||
return `${name}.production.min.js`;
|
||||
case UMD_PROFILING:
|
||||
return `${name}.profiling.min.js`;
|
||||
case NODE_DEV:
|
||||
return `${name}.development.js`;
|
||||
case NODE_PROD:
|
||||
@@ -214,6 +219,7 @@ function isProductionBundleType(bundleType) {
|
||||
return false;
|
||||
case UMD_PROD:
|
||||
case NODE_PROD:
|
||||
case UMD_PROFILING:
|
||||
case NODE_PROFILING:
|
||||
case FB_WWW_PROD:
|
||||
case FB_WWW_PROFILING:
|
||||
@@ -244,6 +250,7 @@ function isProfilingBundleType(bundleType) {
|
||||
case NODE_PROFILING:
|
||||
case RN_FB_PROFILING:
|
||||
case RN_OSS_PROFILING:
|
||||
case UMD_PROFILING:
|
||||
return true;
|
||||
default:
|
||||
throw new Error(`Unknown type: ${bundleType}`);
|
||||
@@ -280,7 +287,10 @@ function getPlugins(
|
||||
const forks = Modules.getForks(bundleType, entry, moduleType);
|
||||
const isProduction = isProductionBundleType(bundleType);
|
||||
const isProfiling = isProfilingBundleType(bundleType);
|
||||
const isUMDBundle = bundleType === UMD_DEV || bundleType === UMD_PROD;
|
||||
const isUMDBundle =
|
||||
bundleType === UMD_DEV ||
|
||||
bundleType === UMD_PROD ||
|
||||
bundleType === UMD_PROFILING;
|
||||
const isFBBundle =
|
||||
bundleType === FB_WWW_DEV ||
|
||||
bundleType === FB_WWW_PROD ||
|
||||
@@ -430,7 +440,9 @@ async function createBundle(bundle, bundleType) {
|
||||
}
|
||||
|
||||
const shouldBundleDependencies =
|
||||
bundleType === UMD_DEV || bundleType === UMD_PROD;
|
||||
bundleType === UMD_DEV ||
|
||||
bundleType === UMD_PROD ||
|
||||
bundleType === UMD_PROFILING;
|
||||
const peerGlobals = Modules.getPeerGlobals(bundle.externals, bundleType);
|
||||
let externals = Object.keys(peerGlobals);
|
||||
if (!shouldBundleDependencies) {
|
||||
@@ -580,6 +592,7 @@ async function buildEverything() {
|
||||
for (const bundle of Bundles.bundles) {
|
||||
await createBundle(bundle, UMD_DEV);
|
||||
await createBundle(bundle, UMD_PROD);
|
||||
await createBundle(bundle, UMD_PROFILING);
|
||||
await createBundle(bundle, NODE_DEV);
|
||||
await createBundle(bundle, NODE_PROD);
|
||||
await createBundle(bundle, NODE_PROFILING);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const bundleTypes = {
|
||||
UMD_DEV: 'UMD_DEV',
|
||||
UMD_PROD: 'UMD_PROD',
|
||||
UMD_PROFILING: 'UMD_PROFILING',
|
||||
NODE_DEV: 'NODE_DEV',
|
||||
NODE_PROD: 'NODE_PROD',
|
||||
NODE_PROFILING: 'NODE_PROFILING',
|
||||
@@ -19,6 +20,7 @@ const bundleTypes = {
|
||||
|
||||
const UMD_DEV = bundleTypes.UMD_DEV;
|
||||
const UMD_PROD = bundleTypes.UMD_PROD;
|
||||
const UMD_PROFILING = bundleTypes.UMD_PROFILING;
|
||||
const NODE_DEV = bundleTypes.NODE_DEV;
|
||||
const NODE_PROD = bundleTypes.NODE_PROD;
|
||||
const NODE_PROFILING = bundleTypes.NODE_PROFILING;
|
||||
@@ -58,9 +60,9 @@ const bundles = [
|
||||
bundleTypes: [
|
||||
UMD_DEV,
|
||||
UMD_PROD,
|
||||
UMD_PROFILING,
|
||||
NODE_DEV,
|
||||
NODE_PROD,
|
||||
NODE_PROFILING,
|
||||
FB_WWW_DEV,
|
||||
FB_WWW_PROD,
|
||||
FB_WWW_PROFILING,
|
||||
@@ -77,6 +79,7 @@ const bundles = [
|
||||
bundleTypes: [
|
||||
UMD_DEV,
|
||||
UMD_PROD,
|
||||
UMD_PROFILING,
|
||||
NODE_DEV,
|
||||
NODE_PROD,
|
||||
NODE_PROFILING,
|
||||
@@ -391,7 +394,7 @@ const bundles = [
|
||||
},
|
||||
|
||||
{
|
||||
label: 'schedule-tracking',
|
||||
label: 'schedule-tracing',
|
||||
bundleTypes: [
|
||||
FB_WWW_DEV,
|
||||
FB_WWW_PROD,
|
||||
@@ -401,8 +404,8 @@ const bundles = [
|
||||
NODE_PROFILING,
|
||||
],
|
||||
moduleType: ISOMORPHIC,
|
||||
entry: 'schedule/tracking',
|
||||
global: 'ScheduleTracking',
|
||||
entry: 'schedule/tracing',
|
||||
global: 'ScheduleTracing',
|
||||
externals: [],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -6,6 +6,7 @@ const inlinedHostConfigs = require('../shared/inlinedHostConfigs');
|
||||
|
||||
const UMD_DEV = bundleTypes.UMD_DEV;
|
||||
const UMD_PROD = bundleTypes.UMD_PROD;
|
||||
const UMD_PROFILING = bundleTypes.UMD_PROFILING;
|
||||
const FB_WWW_DEV = bundleTypes.FB_WWW_DEV;
|
||||
const FB_WWW_PROD = bundleTypes.FB_WWW_PROD;
|
||||
const FB_WWW_PROFILING = bundleTypes.FB_WWW_PROFILING;
|
||||
@@ -24,7 +25,11 @@ const forks = Object.freeze({
|
||||
// Optimization: for UMDs, use object-assign polyfill that is already a part
|
||||
// of the React package instead of bundling it again.
|
||||
'object-assign': (bundleType, entry, dependencies) => {
|
||||
if (bundleType !== UMD_DEV && bundleType !== UMD_PROD) {
|
||||
if (
|
||||
bundleType !== UMD_DEV &&
|
||||
bundleType !== UMD_PROD &&
|
||||
bundleType !== UMD_PROFILING
|
||||
) {
|
||||
// It's only relevant for UMD bundles since that's where the duplication
|
||||
// happens. Other bundles just require('object-assign') anyway.
|
||||
return null;
|
||||
@@ -118,6 +123,7 @@ const forks = Object.freeze({
|
||||
switch (bundleType) {
|
||||
case UMD_DEV:
|
||||
case UMD_PROD:
|
||||
case UMD_PROFILING:
|
||||
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.
|
||||
@@ -132,10 +138,11 @@ const forks = Object.freeze({
|
||||
}
|
||||
},
|
||||
|
||||
'schedule/tracking': (bundleType, entry, dependencies) => {
|
||||
'schedule/tracing': (bundleType, entry, dependencies) => {
|
||||
switch (bundleType) {
|
||||
case UMD_DEV:
|
||||
case UMD_PROD:
|
||||
case UMD_PROFILING:
|
||||
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.
|
||||
@@ -143,7 +150,7 @@ const forks = Object.freeze({
|
||||
}
|
||||
// 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 <script> tag
|
||||
return 'shared/forks/ScheduleTracking.umd.js';
|
||||
return 'shared/forks/ScheduleTracing.umd.js';
|
||||
default:
|
||||
// For other bundles, use the shared NPM package.
|
||||
return null;
|
||||
|
||||
@@ -5,6 +5,7 @@ const bundleTypes = require('./bundles').bundleTypes;
|
||||
|
||||
const UMD_DEV = bundleTypes.UMD_DEV;
|
||||
const UMD_PROD = bundleTypes.UMD_PROD;
|
||||
const UMD_PROFILING = bundleTypes.UMD_PROFILING;
|
||||
|
||||
// For any external that is used in a DEV-only condition, explicitly
|
||||
// specify whether it has side effects during import or not. This lets
|
||||
@@ -15,7 +16,7 @@ const importSideEffects = Object.freeze({
|
||||
'prop-types/checkPropTypes': HAS_NO_SIDE_EFFECTS_ON_IMPORT,
|
||||
deepFreezeAndThrowOnMutationInDev: HAS_NO_SIDE_EFFECTS_ON_IMPORT,
|
||||
schedule: HAS_NO_SIDE_EFFECTS_ON_IMPORT,
|
||||
'schedule/tracking': HAS_NO_SIDE_EFFECTS_ON_IMPORT,
|
||||
'schedule/tracing': HAS_NO_SIDE_EFFECTS_ON_IMPORT,
|
||||
});
|
||||
|
||||
// Bundles exporting globals that other modules rely on.
|
||||
@@ -23,7 +24,7 @@ const knownGlobals = Object.freeze({
|
||||
react: 'React',
|
||||
'react-dom': 'ReactDOM',
|
||||
schedule: 'Schedule',
|
||||
'schedule/tracking': 'ScheduleTracking',
|
||||
'schedule/tracing': 'ScheduleTracing',
|
||||
});
|
||||
|
||||
// Given ['react'] in bundle externals, returns { 'react': 'React' }.
|
||||
@@ -32,7 +33,9 @@ function getPeerGlobals(externals, bundleType) {
|
||||
externals.forEach(name => {
|
||||
if (
|
||||
!knownGlobals[name] &&
|
||||
(bundleType === UMD_DEV || bundleType === UMD_PROD)
|
||||
(bundleType === UMD_DEV ||
|
||||
bundleType === UMD_PROD ||
|
||||
bundleType === UMD_PROFILING)
|
||||
) {
|
||||
throw new Error('Cannot build UMD without a global name for: ' + name);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ const {
|
||||
const {
|
||||
UMD_DEV,
|
||||
UMD_PROD,
|
||||
UMD_PROFILING,
|
||||
NODE_DEV,
|
||||
NODE_PROD,
|
||||
NODE_PROFILING,
|
||||
@@ -41,6 +42,7 @@ function getBundleOutputPaths(bundleType, filename, packageName) {
|
||||
return [`build/node_modules/${packageName}/cjs/${filename}`];
|
||||
case UMD_DEV:
|
||||
case UMD_PROD:
|
||||
case UMD_PROFILING:
|
||||
return [
|
||||
`build/node_modules/${packageName}/umd/${filename}`,
|
||||
`build/dist/${filename}`,
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
"filename": "react.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react",
|
||||
"size": 85459,
|
||||
"gzip": 23174
|
||||
"size": 85735,
|
||||
"gzip": 23224
|
||||
},
|
||||
{
|
||||
"filename": "react.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react",
|
||||
"size": 9766,
|
||||
"gzip": 4050
|
||||
"size": 10402,
|
||||
"gzip": 4231
|
||||
},
|
||||
{
|
||||
"filename": "react.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react",
|
||||
"size": 54971,
|
||||
"gzip": 15207
|
||||
"size": 56658,
|
||||
"gzip": 15595
|
||||
},
|
||||
{
|
||||
"filename": "react.production.min.js",
|
||||
@@ -46,29 +46,29 @@
|
||||
"filename": "react-dom.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 661344,
|
||||
"gzip": 154987
|
||||
"size": 667660,
|
||||
"gzip": 156492
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 94512,
|
||||
"gzip": 30805
|
||||
"size": 94426,
|
||||
"gzip": 30739
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 656578,
|
||||
"gzip": 153557
|
||||
"size": 662895,
|
||||
"gzip": 155074
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 94452,
|
||||
"gzip": 30412
|
||||
"size": 94415,
|
||||
"gzip": 30384
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOM-dev.js",
|
||||
@@ -88,28 +88,28 @@
|
||||
"filename": "react-dom-test-utils.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 45669,
|
||||
"gzip": 12470
|
||||
"size": 47057,
|
||||
"gzip": 12756
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-test-utils.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 10223,
|
||||
"gzip": 3796
|
||||
"size": 10224,
|
||||
"gzip": 3802
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-test-utils.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 45383,
|
||||
"gzip": 12405
|
||||
"size": 46771,
|
||||
"gzip": 12693
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-test-utils.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 9993,
|
||||
"size": 9994,
|
||||
"gzip": 3733
|
||||
},
|
||||
{
|
||||
@@ -123,29 +123,29 @@
|
||||
"filename": "react-dom-unstable-native-dependencies.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 77985,
|
||||
"gzip": 20025
|
||||
"size": 63044,
|
||||
"gzip": 16436
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-unstable-native-dependencies.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 13186,
|
||||
"gzip": 4606
|
||||
"size": 11263,
|
||||
"gzip": 3892
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-unstable-native-dependencies.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 77649,
|
||||
"gzip": 19889
|
||||
"size": 62708,
|
||||
"gzip": 16304
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-unstable-native-dependencies.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 12925,
|
||||
"gzip": 4482
|
||||
"size": 10998,
|
||||
"gzip": 3784
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMUnstableNativeDependencies-dev.js",
|
||||
@@ -165,29 +165,29 @@
|
||||
"filename": "react-dom-server.browser.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 107282,
|
||||
"gzip": 28637
|
||||
"size": 108742,
|
||||
"gzip": 28936
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.browser.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 15699,
|
||||
"gzip": 6005
|
||||
"size": 15720,
|
||||
"gzip": 6014
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.browser.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 103320,
|
||||
"gzip": 27620
|
||||
"size": 104780,
|
||||
"gzip": 27915
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.browser.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 15599,
|
||||
"gzip": 5950
|
||||
"size": 15620,
|
||||
"gzip": 5960
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMServer-dev.js",
|
||||
@@ -207,43 +207,43 @@
|
||||
"filename": "react-dom-server.node.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 105288,
|
||||
"gzip": 28167
|
||||
"size": 106748,
|
||||
"gzip": 28492
|
||||
},
|
||||
{
|
||||
"filename": "react-dom-server.node.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 16424,
|
||||
"gzip": 6262
|
||||
"size": 16445,
|
||||
"gzip": 6272
|
||||
},
|
||||
{
|
||||
"filename": "react-art.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-art",
|
||||
"size": 450056,
|
||||
"gzip": 100892
|
||||
"size": 452475,
|
||||
"gzip": 101602
|
||||
},
|
||||
{
|
||||
"filename": "react-art.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-art",
|
||||
"size": 86739,
|
||||
"gzip": 26617
|
||||
"size": 86669,
|
||||
"gzip": 26613
|
||||
},
|
||||
{
|
||||
"filename": "react-art.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-art",
|
||||
"size": 380168,
|
||||
"gzip": 83359
|
||||
"size": 382588,
|
||||
"gzip": 83986
|
||||
},
|
||||
{
|
||||
"filename": "react-art.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-art",
|
||||
"size": 50857,
|
||||
"gzip": 15635
|
||||
"size": 50794,
|
||||
"gzip": 15601
|
||||
},
|
||||
{
|
||||
"filename": "ReactART-dev.js",
|
||||
@@ -291,29 +291,29 @@
|
||||
"filename": "react-test-renderer.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 392455,
|
||||
"gzip": 86004
|
||||
"size": 394852,
|
||||
"gzip": 86595
|
||||
},
|
||||
{
|
||||
"filename": "react-test-renderer.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 52093,
|
||||
"gzip": 15903
|
||||
"size": 52018,
|
||||
"gzip": 15911
|
||||
},
|
||||
{
|
||||
"filename": "react-test-renderer.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 387938,
|
||||
"gzip": 84840
|
||||
"size": 390336,
|
||||
"gzip": 85433
|
||||
},
|
||||
{
|
||||
"filename": "react-test-renderer.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 51799,
|
||||
"gzip": 15751
|
||||
"size": 51727,
|
||||
"gzip": 15738
|
||||
},
|
||||
{
|
||||
"filename": "ReactTestRenderer-dev.js",
|
||||
@@ -326,29 +326,29 @@
|
||||
"filename": "react-test-renderer-shallow.development.js",
|
||||
"bundleType": "UMD_DEV",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 24870,
|
||||
"gzip": 6782
|
||||
"size": 26222,
|
||||
"gzip": 7035
|
||||
},
|
||||
{
|
||||
"filename": "react-test-renderer-shallow.production.min.js",
|
||||
"bundleType": "UMD_PROD",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 7340,
|
||||
"gzip": 2398
|
||||
"size": 7336,
|
||||
"gzip": 2404
|
||||
},
|
||||
{
|
||||
"filename": "react-test-renderer-shallow.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 19946,
|
||||
"gzip": 5551
|
||||
"size": 21298,
|
||||
"gzip": 5799
|
||||
},
|
||||
{
|
||||
"filename": "react-test-renderer-shallow.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 8056,
|
||||
"gzip": 2670
|
||||
"size": 8077,
|
||||
"gzip": 2676
|
||||
},
|
||||
{
|
||||
"filename": "ReactShallowRenderer-dev.js",
|
||||
@@ -361,50 +361,50 @@
|
||||
"filename": "react-noop-renderer.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-noop-renderer",
|
||||
"size": 24166,
|
||||
"gzip": 5472
|
||||
"size": 24480,
|
||||
"gzip": 5530
|
||||
},
|
||||
{
|
||||
"filename": "react-noop-renderer.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-noop-renderer",
|
||||
"size": 9072,
|
||||
"gzip": 3150
|
||||
"size": 9125,
|
||||
"gzip": 3170
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-reconciler",
|
||||
"size": 375974,
|
||||
"gzip": 81428
|
||||
"size": 378388,
|
||||
"gzip": 82064
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-reconciler",
|
||||
"size": 50424,
|
||||
"gzip": 15131
|
||||
"size": 50485,
|
||||
"gzip": 15151
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler-persistent.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-reconciler",
|
||||
"size": 374478,
|
||||
"gzip": 80840
|
||||
"size": 376785,
|
||||
"gzip": 81416
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler-persistent.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-reconciler",
|
||||
"size": 50435,
|
||||
"gzip": 15137
|
||||
"size": 50496,
|
||||
"gzip": 15157
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler-reflection.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-reconciler",
|
||||
"size": 15111,
|
||||
"gzip": 4723
|
||||
"size": 16463,
|
||||
"gzip": 5001
|
||||
},
|
||||
{
|
||||
"filename": "react-reconciler-reflection.production.min.js",
|
||||
@@ -453,7 +453,7 @@
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-is",
|
||||
"size": 1920,
|
||||
"gzip": 731
|
||||
"gzip": 732
|
||||
},
|
||||
{
|
||||
"filename": "ReactIs-dev.js",
|
||||
@@ -473,8 +473,8 @@
|
||||
"filename": "simple-cache-provider.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "simple-cache-provider",
|
||||
"size": 9101,
|
||||
"gzip": 2929
|
||||
"size": 10431,
|
||||
"gzip": 3205
|
||||
},
|
||||
{
|
||||
"filename": "simple-cache-provider.production.min.js",
|
||||
@@ -487,8 +487,8 @@
|
||||
"filename": "create-subscription.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "create-subscription",
|
||||
"size": 8188,
|
||||
"gzip": 2836
|
||||
"size": 9518,
|
||||
"gzip": 3106
|
||||
},
|
||||
{
|
||||
"filename": "create-subscription.production.min.js",
|
||||
@@ -501,148 +501,148 @@
|
||||
"filename": "React-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react",
|
||||
"size": 52540,
|
||||
"gzip": 14542
|
||||
"size": 52924,
|
||||
"gzip": 14672
|
||||
},
|
||||
{
|
||||
"filename": "React-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react",
|
||||
"size": 14245,
|
||||
"gzip": 3977
|
||||
"gzip": 3978
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOM-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 679499,
|
||||
"gzip": 155980
|
||||
"size": 680213,
|
||||
"gzip": 155823
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOM-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 294428,
|
||||
"gzip": 54460
|
||||
"size": 290991,
|
||||
"gzip": 53748
|
||||
},
|
||||
{
|
||||
"filename": "ReactTestUtils-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 42405,
|
||||
"gzip": 11428
|
||||
"size": 42463,
|
||||
"gzip": 11444
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMUnstableNativeDependencies-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 69916,
|
||||
"gzip": 17129
|
||||
"size": 59004,
|
||||
"gzip": 14969
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMUnstableNativeDependencies-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 33515,
|
||||
"gzip": 6691
|
||||
"size": 26900,
|
||||
"gzip": 5426
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMServer-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-dom",
|
||||
"size": 104426,
|
||||
"gzip": 27277
|
||||
"size": 104558,
|
||||
"gzip": 27310
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOMServer-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react-dom",
|
||||
"size": 34371,
|
||||
"gzip": 8247
|
||||
"size": 34423,
|
||||
"gzip": 8270
|
||||
},
|
||||
{
|
||||
"filename": "ReactART-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-art",
|
||||
"size": 385292,
|
||||
"gzip": 82097
|
||||
"size": 386331,
|
||||
"gzip": 82504
|
||||
},
|
||||
{
|
||||
"filename": "ReactART-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "react-art",
|
||||
"size": 164073,
|
||||
"gzip": 27807
|
||||
"size": 163773,
|
||||
"gzip": 27778
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-dev.js",
|
||||
"bundleType": "RN_FB_DEV",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 510517,
|
||||
"gzip": 113049
|
||||
"size": 512877,
|
||||
"gzip": 113656
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-prod.js",
|
||||
"bundleType": "RN_FB_PROD",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 220295,
|
||||
"gzip": 38378
|
||||
"size": 220037,
|
||||
"gzip": 38376
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-dev.js",
|
||||
"bundleType": "RN_OSS_DEV",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 510244,
|
||||
"gzip": 112977
|
||||
"size": 512530,
|
||||
"gzip": 113567
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-prod.js",
|
||||
"bundleType": "RN_OSS_PROD",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 209872,
|
||||
"gzip": 36698
|
||||
"size": 209614,
|
||||
"gzip": 36695
|
||||
},
|
||||
{
|
||||
"filename": "ReactFabric-dev.js",
|
||||
"bundleType": "RN_FB_DEV",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 500465,
|
||||
"gzip": 110574
|
||||
"size": 502836,
|
||||
"gzip": 111191
|
||||
},
|
||||
{
|
||||
"filename": "ReactFabric-prod.js",
|
||||
"bundleType": "RN_FB_PROD",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 202067,
|
||||
"gzip": 35161
|
||||
"size": 201848,
|
||||
"gzip": 35194
|
||||
},
|
||||
{
|
||||
"filename": "ReactFabric-dev.js",
|
||||
"bundleType": "RN_OSS_DEV",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 500501,
|
||||
"gzip": 110590
|
||||
"size": 502872,
|
||||
"gzip": 111207
|
||||
},
|
||||
{
|
||||
"filename": "ReactFabric-prod.js",
|
||||
"bundleType": "RN_OSS_PROD",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 202103,
|
||||
"gzip": 35175
|
||||
"size": 201884,
|
||||
"gzip": 35209
|
||||
},
|
||||
{
|
||||
"filename": "ReactTestRenderer-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 393184,
|
||||
"gzip": 83849
|
||||
"size": 394234,
|
||||
"gzip": 84247
|
||||
},
|
||||
{
|
||||
"filename": "ReactShallowRenderer-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "react-test-renderer",
|
||||
"size": 18225,
|
||||
"gzip": 4802
|
||||
"size": 18283,
|
||||
"gzip": 4788
|
||||
},
|
||||
{
|
||||
"filename": "ReactIs-dev.js",
|
||||
@@ -676,15 +676,15 @@
|
||||
"filename": "schedule.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "schedule",
|
||||
"size": 15711,
|
||||
"gzip": 4717
|
||||
"size": 14175,
|
||||
"gzip": 4343
|
||||
},
|
||||
{
|
||||
"filename": "schedule.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "schedule",
|
||||
"size": 2844,
|
||||
"gzip": 1244
|
||||
"size": 3260,
|
||||
"gzip": 1428
|
||||
},
|
||||
{
|
||||
"filename": "SimpleCacheProvider-dev.js",
|
||||
@@ -704,50 +704,50 @@
|
||||
"filename": "react-noop-renderer-persistent.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "react-noop-renderer",
|
||||
"size": 24285,
|
||||
"gzip": 5486
|
||||
"size": 24599,
|
||||
"gzip": 5543
|
||||
},
|
||||
{
|
||||
"filename": "react-noop-renderer-persistent.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "react-noop-renderer",
|
||||
"size": 9094,
|
||||
"gzip": 3158
|
||||
"size": 9147,
|
||||
"gzip": 3176
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.profiling.min.js",
|
||||
"bundleType": "NODE_PROFILING",
|
||||
"packageName": "react-dom",
|
||||
"size": 97473,
|
||||
"gzip": 31084
|
||||
"size": 97527,
|
||||
"gzip": 31075
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-profiling.js",
|
||||
"bundleType": "RN_OSS_PROFILING",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 217341,
|
||||
"gzip": 38083
|
||||
"size": 217507,
|
||||
"gzip": 38262
|
||||
},
|
||||
{
|
||||
"filename": "ReactFabric-profiling.js",
|
||||
"bundleType": "RN_OSS_PROFILING",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 208788,
|
||||
"gzip": 36549
|
||||
"size": 209220,
|
||||
"gzip": 36778
|
||||
},
|
||||
{
|
||||
"filename": "Schedule-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "schedule",
|
||||
"size": 15950,
|
||||
"gzip": 4768
|
||||
"size": 14361,
|
||||
"gzip": 4374
|
||||
},
|
||||
{
|
||||
"filename": "Schedule-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "schedule",
|
||||
"size": 7909,
|
||||
"gzip": 1952
|
||||
"size": 8327,
|
||||
"gzip": 2105
|
||||
},
|
||||
{
|
||||
"filename": "react.profiling.min.js",
|
||||
@@ -761,35 +761,35 @@
|
||||
"bundleType": "FB_WWW_PROFILING",
|
||||
"packageName": "react",
|
||||
"size": 14245,
|
||||
"gzip": 3977
|
||||
"gzip": 3978
|
||||
},
|
||||
{
|
||||
"filename": "ReactDOM-profiling.js",
|
||||
"bundleType": "FB_WWW_PROFILING",
|
||||
"packageName": "react-dom",
|
||||
"size": 301143,
|
||||
"gzip": 55840
|
||||
"size": 298012,
|
||||
"gzip": 55267
|
||||
},
|
||||
{
|
||||
"filename": "ReactNativeRenderer-profiling.js",
|
||||
"bundleType": "RN_FB_PROFILING",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 226024,
|
||||
"gzip": 39610
|
||||
"size": 226187,
|
||||
"gzip": 39805
|
||||
},
|
||||
{
|
||||
"filename": "ReactFabric-profiling.js",
|
||||
"bundleType": "RN_FB_PROFILING",
|
||||
"packageName": "react-native-renderer",
|
||||
"size": 208747,
|
||||
"gzip": 36532
|
||||
"size": 209179,
|
||||
"gzip": 36760
|
||||
},
|
||||
{
|
||||
"filename": "schedule-tracking.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "schedule",
|
||||
"size": 10893,
|
||||
"gzip": 2574
|
||||
"size": 10514,
|
||||
"gzip": 2411
|
||||
},
|
||||
{
|
||||
"filename": "schedule-tracking.production.min.js",
|
||||
@@ -803,14 +803,14 @@
|
||||
"bundleType": "NODE_PROFILING",
|
||||
"packageName": "schedule",
|
||||
"size": 3337,
|
||||
"gzip": 991
|
||||
"gzip": 992
|
||||
},
|
||||
{
|
||||
"filename": "ScheduleTracking-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "schedule",
|
||||
"size": 10534,
|
||||
"gzip": 2307
|
||||
"size": 10608,
|
||||
"gzip": 2330
|
||||
},
|
||||
{
|
||||
"filename": "ScheduleTracking-prod.js",
|
||||
@@ -825,6 +825,62 @@
|
||||
"packageName": "schedule",
|
||||
"size": 6984,
|
||||
"gzip": 1258
|
||||
},
|
||||
{
|
||||
"filename": "react.profiling.min.js",
|
||||
"bundleType": "UMD_PROFILING",
|
||||
"packageName": "react",
|
||||
"size": 12608,
|
||||
"gzip": 4777
|
||||
},
|
||||
{
|
||||
"filename": "react-dom.profiling.min.js",
|
||||
"bundleType": "UMD_PROFILING",
|
||||
"packageName": "react-dom",
|
||||
"size": 97449,
|
||||
"gzip": 31534
|
||||
},
|
||||
{
|
||||
"filename": "schedule-tracing.development.js",
|
||||
"bundleType": "NODE_DEV",
|
||||
"packageName": "schedule",
|
||||
"size": 10496,
|
||||
"gzip": 2410
|
||||
},
|
||||
{
|
||||
"filename": "schedule-tracing.production.min.js",
|
||||
"bundleType": "NODE_PROD",
|
||||
"packageName": "schedule",
|
||||
"size": 718,
|
||||
"gzip": 374
|
||||
},
|
||||
{
|
||||
"filename": "schedule-tracing.profiling.min.js",
|
||||
"bundleType": "NODE_PROFILING",
|
||||
"packageName": "schedule",
|
||||
"size": 3333,
|
||||
"gzip": 991
|
||||
},
|
||||
{
|
||||
"filename": "ScheduleTracing-dev.js",
|
||||
"bundleType": "FB_WWW_DEV",
|
||||
"packageName": "schedule",
|
||||
"size": 10591,
|
||||
"gzip": 2327
|
||||
},
|
||||
{
|
||||
"filename": "ScheduleTracing-prod.js",
|
||||
"bundleType": "FB_WWW_PROD",
|
||||
"packageName": "schedule",
|
||||
"size": 899,
|
||||
"gzip": 425
|
||||
},
|
||||
{
|
||||
"filename": "ScheduleTracing-profiling.js",
|
||||
"bundleType": "FB_WWW_PROFILING",
|
||||
"packageName": "schedule",
|
||||
"size": 6979,
|
||||
"gzip": 1257
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5,6 +5,7 @@ const reactVersion = require('../../package.json').version;
|
||||
|
||||
const UMD_DEV = Bundles.bundleTypes.UMD_DEV;
|
||||
const UMD_PROD = Bundles.bundleTypes.UMD_PROD;
|
||||
const UMD_PROFILING = Bundles.bundleTypes.UMD_PROFILING;
|
||||
const NODE_DEV = Bundles.bundleTypes.NODE_DEV;
|
||||
const NODE_PROD = Bundles.bundleTypes.NODE_PROD;
|
||||
const NODE_PROFILING = Bundles.bundleTypes.NODE_PROFILING;
|
||||
@@ -49,6 +50,16 @@ ${license}
|
||||
${source}`;
|
||||
},
|
||||
|
||||
/***************** UMD_PROFILING *****************/
|
||||
[UMD_PROFILING](source, globalName, filename, moduleType) {
|
||||
return `/** @license React v${reactVersion}
|
||||
* ${filename}
|
||||
*
|
||||
${license}
|
||||
*/
|
||||
${source}`;
|
||||
},
|
||||
|
||||
/***************** NODE_DEV *****************/
|
||||
[NODE_DEV](source, globalName, filename, moduleType) {
|
||||
return `/** @license React v${reactVersion}
|
||||
|
||||
Reference in New Issue
Block a user