Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function shouldUseTurboAnimatedModule(): boolean {
if (ReactNativeFeatureFlags.cxxNativeAnimatedEnabled()) {
return false;
} else {
return Platform.OS === 'ios' && global.RN$Bridgeless === true;
return Platform.OS === 'ios';
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,12 +417,9 @@ class MessageQueue {
const n = callableModuleNames.length;
const callableModuleNameList = callableModuleNames.join(', ');

// TODO(T122225939): Remove after investigation: Why are we getting to this line in bridgeless mode?
const isBridgelessMode =
global.RN$Bridgeless === true ? 'true' : 'false';
invariant(
false,
`Failed to call into JavaScript module method ${module}.${method}(). Module has not been registered as callable. Bridgeless Mode: ${isBridgelessMode}. Registered callable JavaScript modules (n = ${n}): ${callableModuleNameList}.
`Failed to call into JavaScript module method ${module}.${method}(). Module has not been registered as callable. Registered callable JavaScript modules (n = ${n}): ${callableModuleNameList}.
A frequent cause of the error is that the application entry file path is incorrect. This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`,
);
}
Expand Down
29 changes: 9 additions & 20 deletions packages/react-native/Libraries/Core/registerCallableModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,16 @@ type RegisterCallableModule = (
moduleOrFactory: Module | (void => Module),
) => void;

const registerCallableModule: RegisterCallableModule = (function () {
if (global.RN$Bridgeless === true) {
return (name, moduleOrFactory) => {
if (typeof moduleOrFactory === 'function') {
global.RN$registerCallableModule(name, moduleOrFactory);
return;
}

global.RN$registerCallableModule(name, () => moduleOrFactory);
};
const registerCallableModule: RegisterCallableModule = (
name,
moduleOrFactory,
) => {
if (typeof moduleOrFactory === 'function') {
global.RN$registerCallableModule(name, moduleOrFactory);
return;
}

const BatchedBridge = require('../BatchedBridge/BatchedBridge').default;
return (name, moduleOrFactory) => {
if (typeof moduleOrFactory === 'function') {
BatchedBridge.registerLazyCallableModule(name, moduleOrFactory);
return;
}

BatchedBridge.registerCallableModule(name, moduleOrFactory);
};
})();
global.RN$registerCallableModule(name, () => moduleOrFactory);
};

export default registerCallableModule;
3 changes: 0 additions & 3 deletions packages/react-native/Libraries/Core/setUpBatchedBridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
import registerModule from './registerCallableModule';

registerModule('Systrace', () => require('../Performance/Systrace'));
if (!(global.RN$Bridgeless === true)) {
registerModule('JSTimers', () => require('./Timers/JSTimers').default);
}
registerModule('RCTLog', () => require('../Utilities/RCTLog').default);
registerModule(
'RCTDeviceEventEmitter',
Expand Down
120 changes: 37 additions & 83 deletions packages/react-native/Libraries/Core/setUpTimers.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,86 +19,40 @@ if (__DEV__) {
}

// In bridgeless mode, timers are host functions installed from cpp.
if (global.RN$Bridgeless === true) {
// This is the flag that tells React to use `queueMicrotask` to batch state
// updates, instead of using the scheduler to schedule a regular task.
// We use a global variable because we don't currently have any other
// mechanism to pass feature flags from RN to React in OSS.
global.RN$enableMicrotasksInReact = true;

polyfillGlobal(
'queueMicrotask',
() =>
require('../../src/private/webapis/microtasks/specs/NativeMicrotasks')
.default.queueMicrotask,
);

// We shim the immediate APIs via `queueMicrotask` to maintain the backward
// compatibility.
polyfillGlobal(
'setImmediate',
() => require('./Timers/immediateShim').setImmediate,
);
polyfillGlobal(
'clearImmediate',
() => require('./Timers/immediateShim').clearImmediate,
);

polyfillGlobal(
'requestIdleCallback',
() =>
require('../../src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks')
.default.requestIdleCallback,
);

polyfillGlobal(
'cancelIdleCallback',
() =>
require('../../src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks')
.default.cancelIdleCallback,
);
} else {
/**
* Set up timers.
* You can use this module directly, or just require InitializeCore.
*/
const defineLazyTimer = (
name:
| 'cancelAnimationFrame'
| 'cancelIdleCallback'
| 'clearInterval'
| 'clearTimeout'
| 'requestAnimationFrame'
| 'requestIdleCallback'
| 'setInterval'
| 'setTimeout',
) => {
polyfillGlobal(name, () => require('./Timers/JSTimers').default[name]);
};
defineLazyTimer('setTimeout');
defineLazyTimer('clearTimeout');
defineLazyTimer('setInterval');
defineLazyTimer('clearInterval');
defineLazyTimer('requestAnimationFrame');
defineLazyTimer('cancelAnimationFrame');
defineLazyTimer('requestIdleCallback');
defineLazyTimer('cancelIdleCallback');

// Polyfill it with promise (regardless it's polyfilled or native) otherwise.
polyfillGlobal(
'queueMicrotask',
() => require('./Timers/queueMicrotask.js').default,
);

// When promise was polyfilled hence is queued to the RN microtask queue,
// we polyfill the immediate APIs as aliases to the ReactNativeMicrotask APIs.
// Note that in bridgeless mode, immediate APIs are installed from cpp.
polyfillGlobal(
'setImmediate',
() => require('./Timers/JSTimers').default.queueReactNativeMicrotask,
);
polyfillGlobal(
'clearImmediate',
() => require('./Timers/JSTimers').default.clearReactNativeMicrotask,
);
}
// This is the flag that tells React to use `queueMicrotask` to batch state
// updates, instead of using the scheduler to schedule a regular task.
// We use a global variable because we don't currently have any other
// mechanism to pass feature flags from RN to React in OSS.
global.RN$enableMicrotasksInReact = true;

polyfillGlobal(
'queueMicrotask',
() =>
require('../../src/private/webapis/microtasks/specs/NativeMicrotasks')
.default.queueMicrotask,
);

// We shim the immediate APIs via `queueMicrotask` to maintain the backward
// compatibility.
polyfillGlobal(
'setImmediate',
() => require('./Timers/immediateShim').setImmediate,
);
polyfillGlobal(
'clearImmediate',
() => require('./Timers/immediateShim').clearImmediate,
);

polyfillGlobal(
'requestIdleCallback',
() =>
require('../../src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks')
.default.requestIdleCallback,
);

polyfillGlobal(
'cancelIdleCallback',
() =>
require('../../src/private/webapis/idlecallbacks/specs/NativeIdleCallbacks')
.default.cancelIdleCallback,
);
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export function get<Config extends {...}>(
): HostComponent<Config> {
ReactNativeViewConfigRegistry.register(name, () => {
const {native, verify} = getRuntimeConfig?.(name) ?? {
native: !global.RN$Bridgeless,
native: false,
verify: false,
};

Expand Down
8 changes: 3 additions & 5 deletions packages/react-native/Libraries/ReactNative/UIManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@ import type {UIManagerJSInterface} from '../Types/UIManagerJSInterface';
import {getFabricUIManager} from './FabricUIManager';
import nullthrows from 'nullthrows';

const UIManagerImpl: UIManagerJSInterface =
require('./BridgelessUIManager').default;

function isFabricReactTag(reactTag: number): boolean {
// React reserves even numbers for Fabric.
return reactTag % 2 === 0;
}

const UIManagerImpl: UIManagerJSInterface =
global.RN$Bridgeless === true
? require('./BridgelessUIManager').default
: require('./PaperUIManager').default;

// $FlowFixMe[cannot-spread-interface]
const UIManager: UIManagerJSInterface = {
...UIManagerImpl,
Expand Down
9 changes: 3 additions & 6 deletions packages/react-native/Libraries/Text/TextNativeComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import type {TextProps} from './TextProps';

import {enablePreparedTextLayout} from '../../src/private/featureflags/ReactNativeFeatureFlags';
import {createViewConfig} from '../NativeComponent/ViewConfig';
import UIManager from '../ReactNative/UIManager';
import createReactNativeComponentClass from '../Renderer/shims/createReactNativeComponentClass';

export type NativeTextProps = Readonly<{
Expand Down Expand Up @@ -82,11 +81,9 @@ export const NativeText: HostComponent<NativeTextProps> =
) as any;

export const NativeVirtualText: HostComponent<NativeTextProps> =
!global.RN$Bridgeless && !UIManager.hasViewManagerConfig('RCTVirtualText')
? NativeText
: (createReactNativeComponentClass('RCTVirtualText', () =>
createViewConfig(virtualTextViewConfig),
) as any);
createReactNativeComponentClass('RCTVirtualText', () =>
createViewConfig(virtualTextViewConfig),
) as any;

export const NativeSelectableText: HostComponent<NativeTextProps> =
enablePreparedTextLayout()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ jest
describe('codegenNativeComponent', () => {
beforeEach(() => {
jest.restoreAllMocks();
// $FlowExpectedError[cannot-write]
global.RN$Bridgeless = false;
jest.spyOn(console, 'warn').mockImplementation(() => {});
});

Expand Down Expand Up @@ -75,16 +73,7 @@ describe('codegenNativeComponent', () => {
);
});

it('should NOT warn if called directly in BRIDGE mode', () => {
// $FlowExpectedError[cannot-write]
global.RN$Bridgeless = false;
codegenNativeComponent<$FlowFixMe>('ComponentName');
expect(console.warn).not.toHaveBeenCalled();
});

it('should warn if called directly in BRIDGELESS mode', () => {
// $FlowExpectedError[cannot-write]
global.RN$Bridgeless = true;
it('should warn if called directly', () => {
codegenNativeComponent<$FlowFixMe>('ComponentName');
expect(console.warn).toHaveBeenCalledWith(
`Codegen didn't run for ComponentName. This will be an error in the future. Make sure you are using @react-native/babel-preset when building your JavaScript code.`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function codegenNativeComponent<Props extends {...}>(
componentName: string,
options?: NativeComponentOptions,
): NativeComponentType<Props> {
if (global.RN$Bridgeless === true && __DEV__) {
if (__DEV__) {
console.warn(
`Codegen didn't run for ${componentName}. This will be an error in the future. Make sure you are using @react-native/babel-preset when building your JavaScript code.`,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import android.os.PowerManager
import android.os.PowerManager.WakeLock
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
import com.facebook.react.jstasks.HeadlessJsTaskConfig
import com.facebook.react.jstasks.HeadlessJsTaskContext.Companion.getInstance
import com.facebook.react.jstasks.HeadlessJsTaskEventListener
Expand Down Expand Up @@ -126,40 +125,21 @@ public abstract class HeadlessJsTaskService : Service(), HeadlessJsTaskEventList

protected val reactContext: ReactContext?
get() {
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
val reactHost =
checkNotNull(reactHost) { "ReactHost is not initialized in New Architecture" }
return reactHost.currentReactContext
} else {
val reactInstanceManager = reactNativeHost.reactInstanceManager
return reactInstanceManager.currentReactContext
}
val reactHost = checkNotNull(reactHost) { "ReactHost is not initialized in New Architecture" }
return reactHost.currentReactContext
}

private fun createReactContextAndScheduleTask(taskConfig: HeadlessJsTaskConfig) {
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
val reactHost = checkNotNull(reactHost)
reactHost.addReactInstanceEventListener(
object : ReactInstanceEventListener {
override fun onReactContextInitialized(context: ReactContext) {
invokeStartTask(context, taskConfig)
reactHost.removeReactInstanceEventListener(this)
}
}
)
reactHost.start()
} else {
val reactInstanceManager = reactNativeHost.reactInstanceManager
reactInstanceManager.addReactInstanceEventListener(
object : ReactInstanceEventListener {
override fun onReactContextInitialized(context: ReactContext) {
invokeStartTask(context, taskConfig)
reactInstanceManager.removeReactInstanceEventListener(this)
}
val reactHost = checkNotNull(reactHost)
reactHost.addReactInstanceEventListener(
object : ReactInstanceEventListener {
override fun onReactContextInitialized(context: ReactContext) {
invokeStartTask(context, taskConfig)
reactHost.removeReactInstanceEventListener(this)
}
)
reactInstanceManager.createReactContextInBackground()
}
}
)
reactHost.start()
}

public companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.interfaces.fabric.ReactSurface;
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags;
import com.facebook.react.modules.core.PermissionListener;
import com.facebook.react.views.view.WindowUtilKt;
import com.facebook.systrace.Systrace;
Expand Down Expand Up @@ -144,29 +143,9 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
}
}
}
if (ReactNativeNewArchitectureFeatureFlags.enableBridgelessArchitecture()) {
mReactDelegate =
new ReactDelegate(
getPlainActivity(), getReactHost(), mainComponentName, launchOptions);
} else {
mReactDelegate =
new ReactDelegate(
getPlainActivity(),
getReactNativeHost(),
mainComponentName,
launchOptions,
isFabricEnabled()) {
@Override
@Nullable
protected ReactRootView createRootView() {
ReactRootView rootView = ReactActivityDelegate.this.createRootView();
if (rootView == null) {
rootView = super.createRootView();
}
return rootView;
}
};
}
mReactDelegate =
new ReactDelegate(
getPlainActivity(), getReactHost(), mainComponentName, launchOptions);
if (mainComponentName != null) {
loadApp(mainComponentName);
}
Expand Down
Loading
Loading