Skip to content

Commit

Permalink
Basic chrome debugger support (#2197)
Browse files Browse the repository at this point in the history
## Description

#### Problem
Reanimated uses JSI and this makes impossible remote debugging by chrome inspector. 
#### Solution
If someone uses chrome inspector debugging, Reanimated replaces JSI bindings with pure JS implementation from the web version. This allows using chrome debugger in an application whose contains reanimated.
#### Known limitation
- reanimated 1
#### TODO:
- [x] gesture handler
- [x] fast reload
- [x] test ios
- [x] test web
- [x] test jest
  • Loading branch information
piaskowyk committed Jul 26, 2021
1 parent bb62c77 commit 1d698d8
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 145 deletions.
7 changes: 3 additions & 4 deletions __tests__/__snapshots__/plugin.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ var f = function () {
_f.asString = \\"function f(){const{x,objX}=jsThis._closure;{return{res:x+objX.x};}}\\";
_f.__workletHash = 10184269015616;
_f.__location = \\"${ process.cwd() }/jest tests fixture (4:4)\\";
_f.__optimalization = 3;
global.__reanimatedWorkletInit(_f);
Expand All @@ -40,7 +39,6 @@ exports[`babel plugin doesn't capture globals 1`] = `
_f.asString = \\"function f(){console.log(\\\\\\"test\\\\\\");}\\";
_f.__workletHash = 6265462104213;
_f.__location = \\"${ process.cwd() }/jest tests fixture (2:6)\\";
_f.__optimalization = 2;
global.__reanimatedWorkletInit(_f);
Expand All @@ -62,7 +60,7 @@ var _reactNativeReanimated = _interopRequireWildcard(require(\\"react-native-rea
function Box() {
var offset = (0, _reactNativeReanimated.useSharedValue)(0);
var animatedStyles = (0, _reactNativeReanimated.useAnimatedStyle)(function () {
const _f = function () {
var _f = function _f() {
return {
transform: [{
translateX: offset.value * 255
Expand All @@ -71,11 +69,12 @@ function Box() {
};
_f._closure = {
offset
offset: offset
};
_f.asString = \\"function _f(){const{offset}=jsThis._closure;{return{transform:[{translateX:offset.value*255}]};}}\\";
_f.__workletHash = 7114514849439;
_f.__location = \\"${ process.cwd() }/jest tests fixture (7:48)\\";
_f.__optimalization = 3;
global.__reanimatedWorkletInit(_f);
Expand Down
12 changes: 10 additions & 2 deletions src/ReanimatedModule.native.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { NativeModules } from 'react-native';
import ReanimatedModuleCompat from './ReanimatedModuleCompat';
import { nativeShouldBeMock } from './reanimated2/PlatformChecker';

const { ReanimatedModule } = NativeModules;
let exportedModule;
if (nativeShouldBeMock()) {
exportedModule = ReanimatedModuleCompat;
} else {
const { ReanimatedModule } = NativeModules;
exportedModule = ReanimatedModule;
}

export default ReanimatedModule;
export default exportedModule;
12 changes: 7 additions & 5 deletions src/createAnimatedComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
DefaultExiting,
DefaultLayout,
} from './reanimated2/layoutReanimation/defaultAnimations/Default';
import { isJest, isChromeDebugger } from './reanimated2/PlatformChecker';

const NODE_MAPPING = new Map();

Expand Down Expand Up @@ -79,7 +80,7 @@ export default function createAnimatedComponent(Component, options = {}) {
constructor(props) {
super(props);
this._attachProps(this.props);
if (process.env.JEST_WORKER_ID) {
if (isJest()) {
this.animatedStyle = { value: {} };
}
this.sv = makeMutable({});
Expand Down Expand Up @@ -116,7 +117,6 @@ export default function createAnimatedComponent(Component, options = {}) {
_attachNativeEvents() {
const node = this._getEventViewRef();
const viewTag = findNodeHandle(options.setNativeProps ? this : node);

for (const key in this.props) {
const prop = this.props[key];
if (prop instanceof AnimatedEvent) {
Expand Down Expand Up @@ -314,7 +314,7 @@ export default function createAnimatedComponent(Component, options = {}) {
styles.forEach((style) => {
if (style?.viewDescriptors) {
style.viewDescriptors.add({ tag: viewTag, name: viewName });
if (process.env.JEST_WORKER_ID) {
if (isJest()) {
/**
* We need to connect Jest's TestObject instance whose contains just props object
* with the updateProps() function where we update the properties of the component.
Expand Down Expand Up @@ -488,7 +488,9 @@ export default function createAnimatedComponent(Component, options = {}) {
props[key] = dummyListener;
}
} else if (!(value instanceof AnimatedNode)) {
props[key] = value;
if (key !== 'onGestureHandlerStateChange' || !isChromeDebugger()) {
props[key] = value;
}
} else if (value instanceof AnimatedValue) {
// if any prop in animated component is set directly to the `Value` we set those props to the first value of `Value` node in order
// to avoid default values for a short moment when `Value` is being asynchrounously sent via bridge and initialized in the native side.
Expand All @@ -500,7 +502,7 @@ export default function createAnimatedComponent(Component, options = {}) {

render() {
const props = this._filterNonAnimatedProps(this.props);
if (process.env.JEST_WORKER_ID) {
if (isJest()) {
props.animatedStyle = this.animatedStyle;
}

Expand Down
17 changes: 8 additions & 9 deletions src/reanimated2/Hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { useEffect, useRef, useCallback } from 'react';
import { isJest, isWeb, shouldBeUseWeb } from './PlatformChecker';

import WorkletEventHandler from './WorkletEventHandler';
import {
Expand All @@ -16,7 +17,6 @@ import updateProps, { updatePropsJestWrapper, colorProps } from './UpdateProps';
import { initialUpdaterRun, cancelAnimation } from './animations';
import { getTag } from './NativeMethods';
import NativeReanimated from './NativeReanimated';
import { Platform } from 'react-native';
import { makeViewDescriptorsSet, makeViewsRefSet } from './ViewDescriptorsSet';
import { processColor } from './Colors';

Expand Down Expand Up @@ -453,7 +453,7 @@ export function useAnimatedStyle(updater, dependencies, adapters) {
const adaptersHash = adapters ? buildWorkletsHash(adapters) : null;
const animationsActive = useSharedValue(true);
let animatedStyle;
if (process.env.JEST_WORKER_ID) {
if (isJest()) {
animatedStyle = useRef({});
}

Expand Down Expand Up @@ -500,7 +500,7 @@ export function useAnimatedStyle(updater, dependencies, adapters) {
};
}

if (canApplyOptimalisation(upadterFn) && Platform.OS !== 'web') {
if (canApplyOptimalisation(upadterFn) && !shouldBeUseWeb()) {
if (hasColorProps(upadterFn())) {
upadterFn = () => {
'worklet';
Expand All @@ -509,7 +509,7 @@ export function useAnimatedStyle(updater, dependencies, adapters) {
return style;
};
}
} else if (Platform.OS !== 'web') {
} else if (!shouldBeUseWeb()) {
optimalization = 0;
upadterFn = () => {
'worklet';
Expand All @@ -522,7 +522,7 @@ export function useAnimatedStyle(updater, dependencies, adapters) {
upadterFn.__optimalization = optimalization;
}

if (process.env.JEST_WORKER_ID) {
if (isJest()) {
fun = () => {
'worklet';
jestStyleUpdater(
Expand Down Expand Up @@ -563,8 +563,6 @@ export function useAnimatedStyle(updater, dependencies, adapters) {
useEffect(() => {
animationsActive.value = true;
return () => {
// initRef.current = null;
// viewsRef = null;
animationsActive.value = false;
};
}, []);
Expand Down Expand Up @@ -728,10 +726,11 @@ export function useAnimatedGestureHandler(handlers, dependencies) {
savedDependencies
);
initRef.current.savedDependencies = dependencies;
const useWeb = isWeb();

const handler = (event) => {
'worklet';
event = Platform.OS === 'web' ? event.nativeEvent : event;
event = useWeb ? event.nativeEvent : event;

const FAILED = 1;
const BEGAN = 2;
Expand Down Expand Up @@ -772,7 +771,7 @@ export function useAnimatedGestureHandler(handlers, dependencies) {
}
};

if (Platform.OS === 'web') {
if (isWeb()) {
return handler;
}

Expand Down
5 changes: 3 additions & 2 deletions src/reanimated2/NativeMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { findNodeHandle } from 'react-native';
import { isChromeDebugger } from './PlatformChecker';

export function getTag(view) {
return findNodeHandle(view);
Expand All @@ -18,7 +19,7 @@ export function getTag(view) {
*/
export function measure(animatedRef) {
'worklet';
if (!_WORKLET) {
if (!_WORKLET && !isChromeDebugger()) {
throw new Error('(measure) method cannot be used on RN side!');
}
const viewTag = animatedRef();
Expand All @@ -31,7 +32,7 @@ export function measure(animatedRef) {

export function scrollTo(animatedRef, x, y, animated) {
'worklet';
if (!_WORKLET) {
if (!_WORKLET && !isChromeDebugger()) {
return;
}
const viewTag = animatedRef();
Expand Down
61 changes: 0 additions & 61 deletions src/reanimated2/NativeReanimated.native.ts

This file was deleted.

67 changes: 66 additions & 1 deletion src/reanimated2/NativeReanimated.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,70 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { Platform } from 'react-native';
import reanimatedJS from './js-reanimated';
import { nativeShouldBeMock } from './PlatformChecker';

export default reanimatedJS;
let exportedModule;
if (nativeShouldBeMock()) {
exportedModule = reanimatedJS;
} else {
const InnerNativeModule = global.__reanimatedModuleProxy;

const NativeReanimated = {
native: true,
useOnlyV1: InnerNativeModule == null,

installCoreFunctions(valueSetter) {
return InnerNativeModule.installCoreFunctions(valueSetter);
},

makeShareable(value) {
return InnerNativeModule.makeShareable(value);
},

makeMutable(value) {
return InnerNativeModule.makeMutable(value);
},

makeRemote(object) {
return InnerNativeModule.makeRemote(object);
},

startMapper(mapper, inputs = [], outputs = [], updater, tag, name) {
return InnerNativeModule.startMapper(
mapper,
inputs,
outputs,
updater,
tag,
name
);
},

stopMapper(mapperId) {
return InnerNativeModule.stopMapper(mapperId);
},

registerEventHandler(eventHash, eventHandler) {
return InnerNativeModule.registerEventHandler(eventHash, eventHandler);
},

unregisterEventHandler(registrationId) {
return InnerNativeModule.unregisterEventHandler(registrationId);
},

getViewProp(viewTag, propName, callback) {
return InnerNativeModule.getViewProp(viewTag, propName, callback);
},
};

if (NativeReanimated.useOnlyV1 && Platform.OS === 'android') {
console.warn(
`If you want to use Reanimated 2 then go through our installation steps https://docs.swmansion.com/react-native-reanimated/docs/installation`
);
}

exportedModule = NativeReanimated;
}

export default exportedModule;
21 changes: 21 additions & 0 deletions src/reanimated2/PlatformChecker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Platform } from 'react-native';

export function isJest(): boolean {
return !!process.env.JEST_WORKER_ID;
}

export function isChromeDebugger(): boolean {
return !(global as any).nativeCallSyncHook || (global as any).__REMOTEDEV__;
}

export function isWeb(): boolean {
return Platform.OS === 'web';
}

export function shouldBeUseWeb() {
return isJest() || isChromeDebugger() || isWeb();
}

export function nativeShouldBeMock() {
return isJest() || isChromeDebugger();
}
4 changes: 2 additions & 2 deletions src/reanimated2/UpdateProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// @ts-nocheck
import { processColor } from './Colors';
import { makeShareable, isConfigured } from './core';
import { Platform } from 'react-native';
import { _updatePropsJS } from './js-reanimated';
import { shouldBeUseWeb } from './PlatformChecker';

// copied from react-native/Libraries/Components/View/ReactNativeStyleAttributes
export const colorProps = [
Expand All @@ -27,7 +27,7 @@ export const colorProps = [
const ColorProperties = !isConfigured() ? [] : makeShareable(colorProps);

let updatePropsByPlatform;
if (Platform.OS === 'web' || process.env.JEST_WORKER_ID) {
if (shouldBeUseWeb()) {
updatePropsByPlatform = (_, updates, maybeViewRef) => {
'worklet';
maybeViewRef.items.forEach((item, _) => {
Expand Down

0 comments on commit 1d698d8

Please sign in to comment.