diff --git a/.eslintrc.js b/.eslintrc.js index 7ccc303a040a..bcab1b2756c1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -428,12 +428,6 @@ module.exports = { TaskController: 'readonly', }, }, - { - files: ['packages/scheduler/npm/index.native.js'], - globals: { - nativeRuntimeScheduler: 'readonly', - }, - }, ], env: { diff --git a/packages/scheduler/index.native.js b/packages/scheduler/index.native.js new file mode 100644 index 000000000000..2113288011d2 --- /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 index 323c201b1ef9..06b1063df6fe 100644 --- a/packages/scheduler/npm/index.native.js +++ b/packages/scheduler/npm/index.native.js @@ -1,9 +1,7 @@ 'use strict'; -if (typeof nativeRuntimeScheduler !== 'undefined') { - module.exports = nativeRuntimeScheduler; -} else if (process.env.NODE_ENV === 'production') { - module.exports = require('./cjs/scheduler.production.min.js'); +if (process.env.NODE_ENV === 'production') { + module.exports = require('./cjs/scheduler-native.production.min.js'); } else { - module.exports = require('./cjs/scheduler.development.js'); + module.exports = require('./cjs/scheduler-native.development.js'); } diff --git a/packages/scheduler/package.json b/packages/scheduler/package.json index 3266c05bad38..79ea3bcb8666 100644 --- a/packages/scheduler/package.json +++ b/packages/scheduler/package.json @@ -23,6 +23,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 09c0d26d7ff6..b0d7469d9ea4 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 000000000000..a7370d92a650 --- /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 f29fe5e17a43..c1bd7b5dead9 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 bf24ac234a39..e8c2943b9334 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,