Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: web compatibility #406

Merged
merged 34 commits into from
Feb 25, 2019
Merged

Conversation

jaulz
Copy link
Contributor

@jaulz jaulz commented Jan 9, 2019

The motivation for me was to use react-navigation@^3 and I stumbled across quite a few missing imports. This PR will introduce some shims so it shouldn't be a problem anymore.

@jaulz jaulz mentioned this pull request Jan 9, 2019
@osdnk
Copy link
Contributor

osdnk commented Jan 9, 2019

@jaulz
Hi, thanks for you PR. I believe it's a crucial step for RNGH!
Is it WIP? If yes, please add proper label?

@jaulz
Copy link
Contributor Author

jaulz commented Jan 9, 2019

@osdnk sorry, I found some issues with the original commit and pushed a fix now 😊As requested I added some comments and it should be in a state where you could please take a look. I tried to touch the existing files at a minimum and also cross checked on native devices if it still works as expected.

Copy link
Contributor

@osdnk osdnk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't digged in this PR yet. Now leaving one comment, but it's not crucial.

import gestureHandlerRootHOC from './gestureHandlerRootHOC';

const State = {
UNDETERMINED: 'UNDETERMINED',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move it out somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should we move out in detail? State constants?

Copy link
Contributor

@osdnk osdnk Jan 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. If you need them here, I wish to have them in separated file in order not to duplicate code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, makes more than sense 😊 Was not sure before since these constants were used in GestureHandler.js as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, well, we intentionally wanted to take them from native site every time. How I think there's no need to do it. You could think about removing extracting from from Java and Objective-C if it's not big deal for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, the constants are used in the native part as well. Hence it actually makes sense to read them in the JavaScript part from the native side. Should I undo the changes in GestureHandler.js for the time being?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's fine now

@@ -0,0 +1,3 @@
import AnimatedEvent from 'react-native-web/dist/vendor/react-native/Animated/AnimatedEvent';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If AnimatedEvent needs to be used directly, you may want to ask that it is added to the Animated export from React Native rather than relying on the fragility of reaching into internals.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will check on their repository and raise a PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will keep track here: facebook/react-native#22984

ToolbarAndroid,
ViewPagerAndroid,
DrawerLayoutAndroid,
WebView,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module is being removed from React Native and isn't included in react-native-web either

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which one in detail? Currently, I see that all of these components are exported though some of them as UnimplementedView which is fine I guess.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info!

}

setNativeProps() {
// No implementation so far but is needed to avoid null calls
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to use this.container.current.setNativeProps

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally left this out since I think we do not need to pass on props for stub components. This would just generate warnings since most of the props are custom.

x,
},
});
node.addEventListener('click', clickHandler);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using these DOM events directly means you're not hooked into the responder event system

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any link for me to see how we could improve this?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with the behaviour/implementation of the native TapGestureHandler. But if it turns out to be preferable to use the responder events, you could pass the event handlers to createHandler and forward them to the component.

static displayName = name;

render() {
return <TouchableWithoutFeedback {...this.props} />;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are meant to be used as buttons in the UI, you should add accessibilityRole="button"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hint!

@miracle2k
Copy link
Contributor

Sorry for the interjection:

I was trying this PR, but the thing I run into is that my babel transforms the access to this in the static property in this line (https://github.com/kmagiera/react-native-gesture-handler/blob/master/touchables/GenericTouchable.js#L56) into

GenericTouchable2.propTypes = _objectSpread({}, (void 0).internalPropTypes, (void 0).publicPropTypes);

(i.e., it replaces this with undefined).

Clearly something is wrong with the way I have setup my babel for the react-native-web compile. Can @jaulz or someone else share a working babel config?

@necolas
Copy link

necolas commented Jan 12, 2019

That just looks like incorrect code. this should be the class name instead

@miracle2k
Copy link
Contributor

@necolas Funny. If I change those lines to

static propTypes = {
    ... GenericTouchable.internalPropTypes,
    ... GenericTouchable.publicPropTypes,
  };

It compiles with webpack, but then react-native@0.57.8 in the iOS emulator says:

Cannot read property 'internalPropTypes' of undefined

The exact opposite behaviour.

@miracle2k
Copy link
Contributor

miracle2k commented Jan 12, 2019

I am fairly certain this is related to the Hot Module Reloading transform inserted by metro here by merging into babelrc this partial config.

Transforming the file in question with babel and using only metro-react-native-babel-preset, the output is sensible: https://gist.github.com/miracle2k/3bc7f1c50080397dbf0d92cfb3101677#file-generictouchable-babel-with-metro-preset-js.

But the actual code generated by react-native for the iOS emulator looks like this: https://gist.github.com/miracle2k/3bc7f1c50080397dbf0d92cfb3101677#file-generictouchable-rn-compilation-js
Notice the _wrapComponent calls which come from the react-transform plugin: https://github.com/facebook/metro/blob/master/packages/metro-babel7-plugin-react-transform/src/index.js#L420.

The problem goes away if I manually edit the file linked above (reactNativeTransformer.js#L131) to ensure the transform is not added. Then, like @necolas says, using the classname instead of this works. Note that the current react-native ships with an old metro version, v0.48.5, so the problem may or may not be fixed in a newer one.

I can see that @osdnk added this code quite recently. Maybe as a workaround for this issue we could rewrite that part and pull the re-used proptypes into the global module scope.

@osdnk
Copy link
Contributor

osdnk commented Jan 12, 2019

I will merge it if needed.

miracle2k added a commit to miracle2k/react-native-gesture-handler that referenced this pull request Jan 13, 2019
osdnk pushed a commit that referenced this pull request Jan 13, 2019
Fixes the issue we encountered #406 (comment)

To review, the problem is as follows:

The correct syntax is:

```
static propTypes = {
    ...GenericTouchable.internalPropTypes
}
```

Metro/Babel compiles this to:

```
// Define GenericTouchable
GenericTouchable.propTypes = (0, _objectSpread2.default)({}, GenericTouchable.internalPropTypes, GenericTouchable.publicPropTypes);
```

But when metro then runs the HMR transform, this becomes:

```
// Create _class
_class.propTypes = (0, _objectSpread2.default)({}, GenericTouchable.internalPropTypes, GenericTouchable.publicPropTypes),
```

It rewrites the class name to `_class` during initialization, but misses the references in the spread, which then causes a undefined-access exception.

See this Gist for full outputs: https://gist.github.com/miracle2k/3bc7f1c50080397dbf0d92cfb3101677#file-generictouchable-babel-with-metro-preset-js

Part of the problem seems to be that metro uses a very old version of [react-hot-loader](facebook/metro#336).

The code as it is currently in the library, using `...this.publicPropTypes` has two problems: First, it does not compile at all with babel, when this library becomes imported as part of using `react-native-web`.

Second, while it does compile using metro, the generated code instead will be:

```
// Create _class
_class.propTypes = (0, _objectSpread2.default)({}, this.internalPropTypes, this.publicPropTypes),
```

With `this` probably referring to the window or global scope, thus not causing a crash, but not actually setting the proptypes correctly.
@jaulz jaulz changed the title fix: web compatibility [WIP] fix: web compatibility Jan 14, 2019
@jaulz jaulz changed the title [WIP] fix: web compatibility fix: web compatibility Jan 14, 2019
@jaulz
Copy link
Contributor Author

jaulz commented Jan 14, 2019

@osdnk @brentvatne it would be great if could you have another look. I assume we could even implement a proper PanGestureHandler with the help of PanResponder from react-native-web but this might be something for the future.

DrawerLayout.js Outdated Show resolved Hide resolved
GestureHandler.web.js Outdated Show resolved Hide resolved
GestureHandler.web.js Outdated Show resolved Hide resolved
GestureHandler.web.js Outdated Show resolved Hide resolved
GestureHandler.web.js Outdated Show resolved Hide resolved
@axhamre
Copy link

axhamre commented Feb 19, 2019

May I ask what's the status here?

@jaulz
Copy link
Contributor Author

jaulz commented Feb 19, 2019

@kmagiera could you please check the latest version?

@iamnader
Copy link

excited for this. thanks for all the work here folks

Copy link
Member

@kmagiera kmagiera left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jaulz so much for working on this. This PR is excellent 👌

I left one small comment, however I'm going to merge this anyways. If you would like to make respond to that comment please submit a separate PR.

};

render() {
let Handler = handlers[handlerName];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this check could be moved outside of the render method and directly to createHandler

@kmagiera kmagiera merged commit c9f7c46 into software-mansion:master Feb 25, 2019
@jaulz jaulz deleted the fix/web-compatibility branch February 26, 2019 10:03
@jaulz jaulz restored the fix/web-compatibility branch February 27, 2019 16:43
@jaulz
Copy link
Contributor Author

jaulz commented Feb 27, 2019

@kmagiera do you have any timeline for a new release? Thanks for merging by the way 😊

@kmagiera
Copy link
Member

will try to send out new release tomorrow

@alidcast
Copy link

alidcast commented Mar 4, 2019

just tried using release with this PR for web and ran into errors. what do we need to configure to get it running - looks like index.web needs to be resolved over index, anything else?

it'd be great we we could just have a simple alias (like we do react-native to react-native-web)

@jaulz
Copy link
Contributor Author

jaulz commented Mar 4, 2019

@alidcastano if you add the .web.js suffix to your Webpack configuration (in resolve.extensions) it should work immediately.

facebook-github-bot pushed a commit to facebook/react-native that referenced this pull request Mar 11, 2019
Summary:
Initially if a `react-native-web` project were to use a library that required internals `expo/webpack-config` would polyfill those internals. This `Platform.web` was used for cases where `react-native` modules needed other internal `react-native` modules, ex: `Animated/src/AnimatedEvent -> Renderer/shims/ReactNative -> Renderer/oss/ReactNativeRenderer-dev -> Core/InitializeCore -> Devtools/setupDevtools -> WebSocket/WebSocket -> Utilities/Platform`

The consensus is that if any `react-native` library references a `react-native` internal (ex: `react-native/*`), it should continue to throw errors. We've removed the use of internals from all of the Unimodules, `react-navigation`, and `react-native-gesture-handler`. This covers a wide enough area for a lot of projects to get web support.

* Add emitters for libs referencing internals necolas/react-native-web#1275
* Remove monkey patch that bundles RN, libs that use internals will crash instead expo/expo-cli#409
* Remove all unsupported internals and polyfills from the Expo suite expo/expo#3676
* Remove internals from react-native-gesture-handler software-mansion/react-native-gesture-handler#406

* Related #23387

[GENERAL] [REMOVED] - Platform.web.js
Pull Request resolved: #23830

Differential Revision: D14406145

Pulled By: hramos

fbshipit-source-id: bdda99a334d33f5543fdb954eb80e2e7186f985a
RNGestureHandlerModule.updateGestureHandler(this._handlerTag, newConfig);
};

_dropGestureHandler = () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it not used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_dropGestureHandler is not used anywhere. Isn't it a bug?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, good catch! Sorry..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

np, thanks!

osdnk added a commit that referenced this pull request May 13, 2019
/pull/406/files#diff-88fa64c878efe14d137f130ddbe000a5R185
From unknown reason, it has been changed here.

Probably it's just a mistake, but it was leading to memory leaks.
@orestis-z
Copy link

orestis-z commented Jun 7, 2019

I opened an issue for two encountered bugs here: #632
Please have a look.

janicduplessis pushed a commit to janicduplessis/react-native-gesture-handler that referenced this pull request Feb 16, 2020
…-mansion#412)

Fixes the issue we encountered software-mansion#406 (comment)

To review, the problem is as follows:

The correct syntax is:

```
static propTypes = {
    ...GenericTouchable.internalPropTypes
}
```

Metro/Babel compiles this to:

```
// Define GenericTouchable
GenericTouchable.propTypes = (0, _objectSpread2.default)({}, GenericTouchable.internalPropTypes, GenericTouchable.publicPropTypes);
```

But when metro then runs the HMR transform, this becomes:

```
// Create _class
_class.propTypes = (0, _objectSpread2.default)({}, GenericTouchable.internalPropTypes, GenericTouchable.publicPropTypes),
```

It rewrites the class name to `_class` during initialization, but misses the references in the spread, which then causes a undefined-access exception.

See this Gist for full outputs: https://gist.github.com/miracle2k/3bc7f1c50080397dbf0d92cfb3101677#file-generictouchable-babel-with-metro-preset-js

Part of the problem seems to be that metro uses a very old version of [react-hot-loader](facebook/metro#336).

The code as it is currently in the library, using `...this.publicPropTypes` has two problems: First, it does not compile at all with babel, when this library becomes imported as part of using `react-native-web`.

Second, while it does compile using metro, the generated code instead will be:

```
// Create _class
_class.propTypes = (0, _objectSpread2.default)({}, this.internalPropTypes, this.publicPropTypes),
```

With `this` probably referring to the window or global scope, thus not causing a crash, but not actually setting the proptypes correctly.
janicduplessis pushed a commit to janicduplessis/react-native-gesture-handler that referenced this pull request Feb 16, 2020
The motivation for me was to use `react-navigation@^3` and I stumbled across quite a few missing imports. This PR will introduce some shims so it shouldn't be a problem anymore.
janicduplessis pushed a commit to janicduplessis/react-native-gesture-handler that referenced this pull request Feb 16, 2020
software-mansion/pull/406/files#diff-88fa64c878efe14d137f130ddbe000a5R185
From unknown reason, it has been changed here.

Probably it's just a mistake, but it was leading to memory leaks.
@Manishalexin
Copy link

When trying to import from RNGH in react native web project, it throws with this error,
"Support for the experimental syntax 'exportDefaultFrom' isn't currently enabled", adding babel plugins for these doesn't help.

Minimum reproducible demo,
https://codesandbox.io/s/polished-paper-tdmyp

@brentvatne
Copy link
Contributor

brentvatne commented Apr 5, 2020

@Manishalexin - you should use babel-preset-expo and the react-native-web setup that you get when you init a project with expo-cli - npm i -g expo-cli && expo init, or follow this guide to add to an existing project: https://docs.expo.io/versions/latest/guides/running-in-the-browser/

here's an example of it running in snack: https://snack.expo.io/@notbrent/jealous-coffee

@Manishalexin
Copy link

Thank you @brentvatne it's working with babel-preset-expo in babel config and I have to use expo start. React scripts & react-scripts-rewired still fails. So, now the storybook fails as it still uses react scripts. I used the setup here, https://github.com/expo/examples/tree/master/with-storybook but it doesn't work as I believe it's only for the expo projects. Any suggestions on how to make it work?

I am using a bare workflow, with react native cli.

@jpaas
Copy link

jpaas commented May 19, 2020

Also running into this on a create-react-app project using RNGH 1.6.1

SyntaxError: .../node_modules/react-native-gesture-handler/DrawerLayout.js: Support for the experimental syntax 'flow' isn't currently enabled (30:8):

  28 | const SETTLING = 'Settling';
  29 |
> 30 | export type PropType = {
     |        ^
  31 |   children: any,
  32 |   drawerBackgroundColor?: string,
  33 |   drawerPosition: 'left' | 'right',

@afilp
Copy link

afilp commented Aug 21, 2020

I do not use expo, how can we solve the dreaded /react-native-gesture-handler/DrawerLayout.js: Support for the experimental syntax 'exportDefaultFrom' isn't currently enabled (30:8): issue?
I tried using react-app-rewired but this does not seem to work, I get other errors and I am not sure if we should go this way.

Thanks a lot!

I also tried the expo solution (although the app is not an expo app), but now I get this weird error:

 web  Failed to compile.
D:/R/myApp/node_modules/react-native/Libraries/Network/XMLHttpRequest.js
Module not found: Can't resolve './RCTNetworking' in 'D:\R\myApp\node_modules\react-native\Li
braries\Network'
Error from chokidar (D:\): Error: EBUSY: resource busy or locked, lstat 'D:\pagefile.sys'

EDIT: This was related to reactotron, so not an issue, see here for solution:
https://forums.expo.io/t/failed-to-compile-cant-resolve-rctnetworking/26273/7

@jaulz jaulz deleted the fix/web-compatibility branch September 3, 2020 05:56
@kopax-polyconseil
Copy link

Hi, I am trying to add react-native-web support on an existing react native ios android application,

I still have error such as this one :

 FAIL  src/features/search/pages/__tests__/SearchFilter.test.tsx
  ● Test suite failed to run

    TypeError: (0 , _reactNative.requireNativeComponent) is not a function

      1 | import { t } from '@lingui/macro'
      2 | import React, { useState } from 'react'
    > 3 | import { TouchableOpacity } from 'react-native-gesture-handler'
        | ^
      4 | import styled from 'styled-components/native'
      5 | 
      6 | import { DateFilter } from 'features/search/atoms/Buttons'

      at Object.<anonymous> (node_modules/react-native-gesture-handler/GestureHandlerButton.js:3:32)
      at Object.<anonymous> (node_modules/react-native-gesture-handler/GestureButtons.js:6:1)
      at Object.<anonymous> (node_modules/react-native-gesture-handler/GestureHandler.js:10:1)
      at Object.<anonymous> (node_modules/react-native-gesture-handler/Swipeable.js:10:1)
      at Object.<anonymous> (node_modules/react-native-gesture-handler/index.js:1:1)
      at Object.<anonymous> (src/features/search/sections/OfferDate.tsx:3:1)
      at Object.<anonymous> (src/features/search/sections/index.ts:8:1)
      at Object.<anonymous> (src/features/search/pages/SearchFilter.tsx:10:1)
      at Object.<anonymous> (src/features/search/pages/__tests__/SearchFilter.test.tsx:12:1)

Looking at your discussion, I assume it should work out of the box with react-native-gesture-handler v1.6.0, why am I still getting those requireNative? Thanks a lot for this awsome lib!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.