diff --git a/packages/scheduler/index.native.js b/packages/scheduler/index.native.js new file mode 100644 index 0000000000..2113288011 --- /dev/null +++ b/packages/scheduler/index.native.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +export * from './src/forks/SchedulerNative'; diff --git a/packages/scheduler/npm/index.native.js b/packages/scheduler/npm/index.native.js new file mode 100644 index 0000000000..4b65547421 --- /dev/null +++ b/packages/scheduler/npm/index.native.js @@ -0,0 +1,7 @@ +'use strict'; + +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/scheduler.native.production.min.js'); +} else { + module.exports = require('./cjs/scheduler.native.development.js'); +} diff --git a/packages/scheduler/package.json b/packages/scheduler/package.json index 3266c05bad..ec6ae75805 100644 --- a/packages/scheduler/package.json +++ b/packages/scheduler/package.json @@ -2,7 +2,6 @@ "name": "scheduler", "version": "0.23.0", "description": "Cooperative scheduler for the browser environment.", - "main": "index.js", "repository": { "type": "git", "url": "https://github.com/facebook/react.git", @@ -23,6 +22,7 @@ "LICENSE", "README.md", "index.js", + "index.native.js", "unstable_mock.js", "unstable_post_task.js", "cjs/", diff --git a/packages/scheduler/src/forks/Scheduler.js b/packages/scheduler/src/forks/Scheduler.js index 09c0d26d7f..b0d7469d9e 100644 --- a/packages/scheduler/src/forks/Scheduler.js +++ b/packages/scheduler/src/forks/Scheduler.js @@ -46,7 +46,7 @@ import { export type Callback = boolean => ?Callback; -type Task = { +export opaque type Task = { id: number, callback: Callback | null, priorityLevel: PriorityLevel, diff --git a/packages/scheduler/src/forks/SchedulerNative.js b/packages/scheduler/src/forks/SchedulerNative.js new file mode 100644 index 0000000000..a7370d92a6 --- /dev/null +++ b/packages/scheduler/src/forks/SchedulerNative.js @@ -0,0 +1,112 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict + */ + +import * as Scheduler from './Scheduler'; +import type {Callback, Task} from './Scheduler'; +import type {PriorityLevel} from '../SchedulerPriorities'; +import typeof * as SchedulerExportsType from './Scheduler'; +import typeof * as SchedulerNativeExportsType from './SchedulerNative'; + +// This type is supposed to reflect the actual methods and arguments currently supported by the C++ implementation: +// https://github.com/facebook/react-native/blob/main/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerBinding.cpp +type NativeSchedulerType = { + unstable_ImmediatePriority: PriorityLevel, + unstable_UserBlockingPriority: PriorityLevel, + unstable_NormalPriority: PriorityLevel, + unstable_IdlePriority: PriorityLevel, + unstable_LowPriority: PriorityLevel, + unstable_scheduleCallback: ( + priorityLevel: PriorityLevel, + callback: Callback, + ) => Task, + unstable_cancelCallback: (task: Task) => void, + unstable_getCurrentPriorityLevel: () => PriorityLevel, + unstable_shouldYield: () => boolean, + unstable_requestPaint: () => void, + unstable_now: () => DOMHighResTimeStamp, +}; + +declare var nativeRuntimeScheduler: void | NativeSchedulerType; + +export const unstable_UserBlockingPriority: PriorityLevel = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_UserBlockingPriority + : Scheduler.unstable_UserBlockingPriority; + +export const unstable_NormalPriority: PriorityLevel = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_NormalPriority + : Scheduler.unstable_NormalPriority; + +export const unstable_IdlePriority: PriorityLevel = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_IdlePriority + : Scheduler.unstable_IdlePriority; + +export const unstable_LowPriority: PriorityLevel = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_LowPriority + : Scheduler.unstable_LowPriority; + +export const unstable_ImmediatePriority: PriorityLevel = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_ImmediatePriority + : Scheduler.unstable_ImmediatePriority; + +export const unstable_scheduleCallback: ( + priorityLevel: PriorityLevel, + callback: Callback, +) => Task = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_scheduleCallback + : Scheduler.unstable_scheduleCallback; + +export const unstable_cancelCallback: (task: Task) => void = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_cancelCallback + : Scheduler.unstable_cancelCallback; + +export const unstable_getCurrentPriorityLevel: () => PriorityLevel = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_getCurrentPriorityLevel + : Scheduler.unstable_getCurrentPriorityLevel; + +export const unstable_shouldYield: () => boolean = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_shouldYield + : Scheduler.unstable_shouldYield; + +export const unstable_requestPaint: () => void = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_requestPaint + : Scheduler.unstable_requestPaint; + +export const unstable_now: () => number | DOMHighResTimeStamp = + typeof nativeRuntimeScheduler !== 'undefined' + ? nativeRuntimeScheduler.unstable_now + : Scheduler.unstable_now; + +// These were never implemented on the native scheduler because React never calls them. +// For consistency, let's disable them altogether and make them throw. +export const unstable_next: any = throwNotImplemented; +export const unstable_runWithPriority: any = throwNotImplemented; +export const unstable_wrapCallback: any = throwNotImplemented; +export const unstable_continueExecution: any = throwNotImplemented; +export const unstable_pauseExecution: any = throwNotImplemented; +export const unstable_getFirstCallbackNode: any = throwNotImplemented; +export const unstable_forceFrameRate: any = throwNotImplemented; +export const unstable_Profiling: any = null; + +function throwNotImplemented() { + throw Error('Not implemented.'); +} + +// Flow magic to verify the exports of this file match the original version. +export type {Callback, Task}; +((((null: any): SchedulerExportsType): SchedulerNativeExportsType): SchedulerExportsType); diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index 23b779ddf8..579d9b6ca2 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -935,6 +935,17 @@ const bundles = [ externals: ['ReactNativeInternalFeatureFlags'], }, + /******* React Scheduler Native *******/ + { + bundleTypes: [NODE_DEV, NODE_PROD], + moduleType: ISOMORPHIC, + entry: 'scheduler/index.native', + global: 'SchedulerNative', + minifyWithProdErrorCodes: false, + wrapWithModuleBoundaries: false, + externals: ['ReactNativeInternalFeatureFlags'], + }, + /******* React Scheduler Post Task (experimental) *******/ { bundleTypes: [ diff --git a/scripts/rollup/validate/eslintrc.cjs.js b/scripts/rollup/validate/eslintrc.cjs.js index bf24ac234a..e8c2943b93 100644 --- a/scripts/rollup/validate/eslintrc.cjs.js +++ b/scripts/rollup/validate/eslintrc.cjs.js @@ -52,6 +52,9 @@ module.exports = { // act IS_REACT_ACT_ENVIRONMENT: 'readonly', + + // Native Scheduler + nativeRuntimeScheduler: 'readonly', }, parserOptions: { ecmaVersion: 2020,