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

[WIP] Add support for React Native as a target #265

Merged
merged 28 commits into from
Feb 6, 2018

Conversation

eliperkins
Copy link
Contributor

@eliperkins eliperkins commented Nov 27, 2017

What: Adds support for using 🏎 in React Native. Closes #185.

Why: Prior to this, React Native could not be targeted, as there are DOM-specific codepaths. This ensures those codepaths are not followed on React Native.

How: Added the basic downshift implementation into a React Native app and started hammering out errors, stripping away DOM-related code.

Checklist:

None of these are done yet! This is a work-in-progress. Putting this up for review as a check to make sure I'm headed in the right direction.

  • Documentation
  • Tests
  • Ready to be merged
  • Added myself to contributors table

src/downshift.js Outdated
@@ -621,7 +630,7 @@ class Downshift extends Component {
this.internalSetState({
type: Downshift.stateChangeTypes.changeInput,
isOpen: true,
inputValue: event.target.value,
inputValue: isReactNative() ? event : event.target.value,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems a bit odd, since the onChangeText prop on React Native returns just the text as a string, not an object. Is there a better way to go about this?

src/downshift.js Outdated
setA11yStatus(status)
// TODO: make this work.
if (!isReactNative()) {
setA11yStatus(status)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like setA11yStatus calls a bunch of DOM-specific APIs, which don't exist on React Native. Should we fork the logic and send this a11y status elsewhere?

src/utils.js Outdated
* @return {Boolean} whether or not the platform is React native
*/
function isReactNative() {
return navigator != null && navigator.product === 'ReactNative'
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can this be prevaled?

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 think the answer is no, since this needs to exist at runtime. Maybe there's a better alternative to use here that could help us cut down on some function calls.

@eliperkins
Copy link
Contributor Author

Alright, spent some time playing around with this today, and it looks like there's some corners to be cut to get this to work on React Native.

There's a few functions that are DOM-specific, like scrollIntoView and setA11yStatus, so this mainly cuts off calls to those functions and remaps event handlers like onClick to React Native's onPress and most things Just Work™! 🎊

With regards to scrollIntoView being DOM-specific, there are methods like FlatList.scrollToItem, but this would force consumers to use a FlatList component, which I don't think is the greatest. Users can implement this themselves if they choose to use a FlatList, I think.

@gricard Had mentioned in #185 (comment) that there are a few accessibility props that we could pass to input, button, and item views, but I omitted those for now, since they're accessibilityTraits and React isn't too keen on us passing those camel-case properties to DOM elements. We could switch these out with the aria- properties since those have no effect on React Native. If this is something we want, let me know!

I'd love to find a cleaner way to get this in without littering isReactNative() calls everywhere, too! Feedback is more than welcome.

Additionally, should I add in a React Native test suite as well? I believe this would just involve adding react-native and related Jest test utils to the test suite, and then writing a few components for this (see also: these Jest docs).

@eliperkins
Copy link
Contributor Author

Oh! Additionally, there's a sample project here: https://github.com/eliperkins/DownshiftNative

src/downshift.js Outdated
const node = this.getItemNodeFromIndex(this.getState().highlightedIndex)
const rootNode = this._rootNode
scrollIntoView(node, rootNode)
// TODO: this whole method is DOM specific...
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we just omit this logic here? This is specific to DOM and to get this to work with React Native, we'd have to force consumers to use a ScrollView and pass us the ref.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, we'll probably want some different logic here for React Native

@eliperkins
Copy link
Contributor Author

One last question, should we omit a call to validateGetRootPropsCalledCorrectly on React Native or should we force consumers to create a component with an "innerRef" and pass it to us? I don't quite understand validateGetRootPropsCalledCorrectly and isDOMElement well enough to have fork logic in validateGetRootPropsCalledCorrectly to get it to be quiet when passing a <View> instead of a <div>.

@gricard
Copy link

gricard commented Nov 29, 2017

Nice! Thanks for picking up the torch there. I got wicked sidetracked. 👍

Copy link
Member

@kentcdodds kentcdodds left a comment

Choose a reason for hiding this comment

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

I didn't have a whole lot of time to review, but left a few comments.

I think in general I'd prefer if we could do something similar with this that we do with preact. Specifically, that we have a separate build version of the library for the react native version. That way folks can use that build and people using the react build don't have to suffer a perf penalty for all the logic around react native.

This is going to require a fair amount of work. But I'm convinced it'll be better for the community if we do it as part of downshift rather than building another project... Maybe I'm wrong... But I don't think so.

src/downshift.js Outdated
@@ -172,6 +173,13 @@ class Downshift extends Component {
}

getItemNodeFromIndex = index => {
if (isReactNative()) {
throw new Error(
Copy link
Member

Choose a reason for hiding this comment

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

We don't need to worry about throwing an error because getItemNodeFromIndex is not publicly exposed so this should never be called :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Heh, good call. This was part of my debugging earlier to figure out what codepath was being followed to call this. I'll remove it!

src/downshift.js Outdated
const node = this.getItemNodeFromIndex(this.getState().highlightedIndex)
const rootNode = this._rootNode
scrollIntoView(node, rootNode)
// TODO: this whole method is DOM specific...
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, we'll probably want some different logic here for React Native

@kentcdodds
Copy link
Member

Oh, also, THANK YOU SO MUCH FOR WORKING ON THIS! 🎉

@eliperkins
Copy link
Contributor Author

Specifically, that we have a separate build version of the library for the react native version

@kentcdodds sounds good! I think that approach makes sense. It looks like the Preact build pipeline is pretty embedded into kcd-scripts and the Rollup config. Would you like it if I worked the React Native build pipeline into kcd-scripts or just keep it local to this project?

@kentcdodds
Copy link
Member

Let's keep it separate. No need to abstract it away until we know what it looks like 😉

I do expect it to be pretty similar though. Some environment variable we use with preval. We could probably make a rollup.config.rn.js file for this

@eliperkins
Copy link
Contributor Author

eliperkins commented Nov 29, 2017

I took a quick pass at this, it seems like BUILD_FILENAME_PREFIX came in pretty handy here to spit React Native-specific builds out to a different place.

I've added a new build script (that still needs to get hooked into the normal build script) called build:react-native which adds a new env var and output directory. This means we can preval our isReactNative logic here.

Unfortunately, it looks like our calls to Boolean(preval`true`) don't get minified away and we need the Boolean calls based on this comment: https://github.com/paypal/downshift/blob/4dc8bf2f4d88a03d2ec485ae36a2490976fe886e/src/downshift.js#L596-L597
so we don't gain all that much in terms of limiting codepaths for non-React Native targets.

I hope I understood your comment about creating a new target here, and took the right approach! Feedback is more than welcome. 😄

@eliperkins
Copy link
Contributor Author

Oh man, I didn't realize the package.json work that needs to get done too. Looking into that now.

@kentcdodds
Copy link
Member

so we don't gain all that much in terms of limiting codepaths for non-React Native targets.

Yeah... I think that the babel plugin we're using for dead code elimination doesn't handle Boolean(false) very well. I think the core issue is in babel's path.evaluate function. Shouldn't be too terribly difficult to solve, and would be really handy to fix eventually.

Judging from this UglifyJS doesn't actually handle this very well either. So perhaps a better solution would be to solve the issues with integrating preval with babel-plugin-istanbul then we wouldn't need the Boolean cast at all. I think that may be the best solution...

@kentcdodds
Copy link
Member

Thanks so much for all your work on this. It's awesome!

package.json Outdated
@@ -9,6 +9,7 @@
"scripts": {
"add-contributor": "kcd-scripts contributors add",
"build": "kcd-scripts build --bundle --p-react",
"build:react-native": "BUILD_REACT_NATIVE=true BUILD_FILENAME_PREFIX=react-native kcd-scripts build --bundle",
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'm not sure the best way to combine this build step with the normal build without clobbering some of the niceties of kcd-scripts build (by using && to run both commands).

Copy link
Member

Choose a reason for hiding this comment

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

I'd just have build:web and a build:native scripts and then a build script that just runs them both: npm run build:web --silent && npm run build:native --silent 👌

src/utils.js Outdated
@@ -224,6 +226,17 @@ function isDOMElement(element) {
}
}

/**
* React Native sets `navigator.product` to a constant `ReactNative`.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comment is no longer valid and should be removed.

@eliperkins
Copy link
Contributor Author

Alright, I kinda tackled this with as minimal destruction as I could.

I ended committing a package.json directly to the project, since there's a decent amount of logic baked into kcd-scripts to do this for Preact.

Additionally, I appeased babel-plugin-istanbul and preval by telling Istanbul to ignore the preval'ed statements. Not a great long-term solution, but I think it should suit our needs, meaning we get to drop the Boolean cast and get better minification! The downside of this means littering an handful of /* istanbul ignore */s in those codepaths.

I think the biggest open question I have is this comment: #265 (comment). I'm not sure the best way to include this in the current build script without extending kcd-scripts to know to invoke more commands. I'd love some feedback related to this.

@codecov-io
Copy link

codecov-io commented Dec 1, 2017

Codecov Report

Merging #265 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #265   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           4      4           
  Lines         324    327    +3     
  Branches       80     84    +4     
=====================================
+ Hits          324    327    +3
Impacted Files Coverage Δ
src/downshift.js 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 531bd8e...9755629. Read the comment docs.

donysukardi pushed a commit to donysukardi/downshift that referenced this pull request Jan 9, 2018
@eliperkins
Copy link
Contributor Author

Hey @kentcdodds! Happy New Year! 🎊

Any chance you could take another peek at this at some point in the next few days? I'd love a little more advice regarding two things:

  1. What are the best next steps I could take to get this merged in?
  2. What is the best way to tackle this sucker? [WIP] Add support for React Native as a target #265 (comment)

Cheers!

Copy link
Member

@kentcdodds kentcdodds left a comment

Choose a reason for hiding this comment

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

Things are looking great! Just a few comments.

Thanks again for working on this!

package.json Outdated
@@ -9,6 +9,7 @@
"scripts": {
"add-contributor": "kcd-scripts contributors add",
"build": "kcd-scripts build --bundle --p-react",
"build:react-native": "BUILD_REACT_NATIVE=true BUILD_FILENAME_PREFIX=react-native kcd-scripts build --bundle",
Copy link
Member

Choose a reason for hiding this comment

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

I'd just have build:web and a build:native scripts and then a build script that just runs them both: npm run build:web --silent && npm run build:native --silent 👌

src/utils.js Outdated
// Disabling coverage here is necessary due to a weird deal with
// babel-plugin-istanbul + preval.macro. No idea...
/* istanbul ignore next (preact) */
const isPreact = preval`module.exports = process.env.BUILD_PREACT === 'true'`
Copy link
Member

Choose a reason for hiding this comment

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

I think that these will actually need to be inlined as they were before to make sure the code is removed properly. I realize it's not as clean, but it'll work better.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This PR got me interested and I agree - better to have those branches DCE-ed.

Copy link
Contributor Author

@eliperkins eliperkins Feb 5, 2018

Choose a reason for hiding this comment

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

Hm, I'm not sure what you mean by making sure the code is removed properly, @kentcdodds, nor do I know what "DCE-ed" means @Andarist. Can you clarify?

If I understand @kentcdodds, he's referring to the code being removed when the production minified bundle is created by Rollup, which seems like it is, according to my tests. Here are some examples:

dist/downshift.umd.min.js vs preact/downshift.umd.min.js

screen shot 2018-02-05 at 3 55 11 pm

Note that this constant is different, using the isPreact constant pulled in from the utils module.

dist/downshift.umd.min.js

this.scrollHighlightedItemIntoView=function(){!function(e,t){var n=S(e,t);if(null!==n){var o=getComputedStyle(n),i=n.getBoundingClientRect(), /* ...rest of scrollIntoView impl */

Notes that there is no runtime check to the isReactNative constant in this function body.

I believe since these are inlined as constants of true or false, Rollup is able to minify that codepath away. If this isn't what these comments are talking about, I'd love some help here!

Copy link
Member

Choose a reason for hiding this comment

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

Thanks! I'm less concerned about the umd builds and more concerned about all the other ones. Could you run the builds and see if Rollup was able to eliminate those? If not, could you try to inline the preval usage and see if Rollup can eliminate it that way. I know it's not pretty, but we've gotta work with the tools we have.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, gotcha. Rollup does not eliminate them there. I'll add the prevals back in, inline!

Do you have more reading for me to learn more about why someone might not use the umd.min version of the build so I can understand the benefit of optimizing those builds?

src/downshift.js Outdated
@@ -661,7 +674,9 @@ class Downshift extends Component {
this.internalSetState({
type: Downshift.stateChangeTypes.changeInput,
isOpen: true,
inputValue: event.target.value,
inputValue: isReactNative
? /* istanbul ignore next (react-native) */ event
Copy link
Member

Choose a reason for hiding this comment

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

Interesting! In react native the event is considered the inputValue? That's a surprise... Is it really a string? The inputValue should be a string that's the value of the input. Other parts of the code make that assumption. Just want to clarify that in react native event is a string that's the value of the input. If not, then we need to get the actual string value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yup! This specific callback, onChangeText, takes a function that is called with the text as a string, that's it.

Other callbacks on TextInput that are more generic for the input itself (like onBlur or onSubmitEditing) return an event as a Proxy in the shape of { nativeEvent: { text: string } }, however, this specific callback just gives us a string.

Copy link
Collaborator

@Andarist Andarist left a comment

Choose a reason for hiding this comment

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

I don't think there is a need to produce module entry for react-native. From what I know metro bundler doesn't understand ESM, only CJS.

You could also remove need for separate react-native directory which enforces importing from downshift/react-native and not directly from downshift.

There are 2 ways for doing this:

  1. put "react-native": "dist/downshift.native.js" in your root package.json
  2. change your "main" in root package.json from dist/downshift.cjs.js to dist/downshift. Let node and company add .js extension automatically. Create your react-native bundle at <pkg.root>/dist/downshift.native.js and let Metro Bundler choose this automatically over regular .js extension.

Both options will allow for import downshift from 'downshift' in React Native

@kentcdodds
Copy link
Member

Thanks! I prefer option 1 👍

@Andarist
Copy link
Collaborator

Andarist commented Feb 1, 2018

It would probably be good to add support for this in your kcd-scripts, like some warning when you do not have react-native key in your root package.json, but you are building for react native target?

@kentcdodds
Copy link
Member

Maybe so... But let's get it working here first 😉

@eliperkins
Copy link
Contributor Author

Ah! Thanks so much for the feedback @Andarist!!!

I apologize I haven't gotten around to wrapping this up yet, it's been super busy for me with work and life. I should be able to spend an hour or two on this tomorrow though! ❤️

The build command now builds for both web and native targets
This will prevent us from smashing against different build targets by sharing a build directory.

This also uses the "react-native" key in the package.json to tell Metro
Bundler where to get the module from.
This will allow Rollup to optimize builds for UMD, ESM and CJS, without minification.
@Andarist
Copy link
Collaborator

Andarist commented Feb 5, 2018

I can finish this up. I'm not a maintainer of this package though, so you'd have to invite me to your fork I guess.

const rootNode = this._rootNode
scrollIntoView(node, rootNode)
/* istanbul ignore else (react-native) */
if (preval`module.exports = process.env.BUILD_REACT_NATIVE !== 'true'`) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

i dont think preval is actually needed here, rollup should handle this just fine with rollup-plugin-replace

Copy link
Member

Choose a reason for hiding this comment

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

I like that idea. Let's add a feature to kcd-scripts and then upgrade this to use that feature.

I think we'll want to configure that somehow though (CLI args?) because there are some process.env.* variables that we want to leave as-is.

@kentcdodds
Copy link
Member

@Andarist, I've added you as a collaborator to downshift 👍 Thanks for all your help so far. Here's the normal thing I show peopel when I add them:

Thanks so much for your help! I've added you as a collaborator on the project. Please make sure that you review the other/MAINTAINING.md and CONTRIBUTING.md files (specifically the bit about the commit messages and the git hooks) and familiarize yourself with the code of conduct (we're using the contributor covenant). You might also want to watch the repo to be notified when someone files an issue/PR. Please continue to make PRs as you feel the need (you can make your branches directly on the repo rather than your fork if you want). Thanks! And welcome to the team :)

@Andarist
Copy link
Collaborator

Andarist commented Feb 5, 2018

Cool, it doesnt seem there is much to be done. I will wrap this up tomorrow (its midnight here already) and ping you for a review.

@kentcdodds
Copy link
Member

Super duper!

@Andarist
Copy link
Collaborator

Andarist commented Feb 6, 2018

@kentcdodds pretty much done, I've tweaked the build setup and it was the only thing I was looking at - I didn't actually test this on RN (functionality-wise).

Things I've noticed while doing this:

  • would be cool to support building for react-native as core feature of kcd-scripts - now I had to figure my way around standard setup (i.e. had to use --no-clean flag etc)
  • would be great to support rollup-plugin-replacein kcd-scripts, that way those lines with preval could get more readable
  • i have no idea what root_handleClick is, i dont see it anywhere in the project and it caches this.props.onClick which can lead to stale values being used

package.json Outdated
"module": "dist/downshift.esm.js",
"typings": "typings/index.d.ts",
"scripts": {
"add-contributor": "kcd-scripts contributors add",
"build": "npm run build:web --silent && npm run build:native --silent",
"build:web": "kcd-scripts build --bundle --p-react",
"build:native": "BUILD_REACT_NATIVE=true BUILD_FILENAME_PREFIX=react-native kcd-scripts build --out-dir native",
"build:native": "BUILD_REACT_NATIVE=true BUILD_FILENAME_SUFFIX=.native kcd-scripts build --bundle cjs --no-clean",
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's the rationale around including the --no-clean flag here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

build:web are and build:native are ran sequentially, kcd-scripts build --bundle removes the target directory, so its removed during build:web and I dont want to remove what was just built by it by running build:native

the goal for me was to not introduce a separate directory and Ive wanted to output react-native version into dist

Copy link
Contributor Author

@eliperkins eliperkins Feb 6, 2018

Choose a reason for hiding this comment

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

What do you think of adding --no-clean only to the build command, rather than build:native? That way, the build:native command can be run safely, clearing out the dist directory, while the build command would be able to handle the sequential case like you mentioned.

Copy link
Collaborator

Choose a reason for hiding this comment

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

that makes sense

Copy link
Collaborator

Choose a reason for hiding this comment

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

@eliperkins changed

package.json Outdated
@@ -29,8 +29,7 @@
"files": [
"dist",
"typings",
"preact",
"react-native"
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 tidying this up for me!

@Andarist
Copy link
Collaborator

Andarist commented Feb 6, 2018

@eliperkins
I've missed your one comment, because GitHub has hid it because some files changed there after you have commented there. I prefer to have a sideways conversation here, so there is bigger chance that it won't be missed later.

By DCE-ed I've meant dead code eliminated. It's actually UglifyJS which does it and not rollup, let's look on a sample code after its gets built with rollup:

{
    key: 'input_getOnChangeKey',
    value: function input_getOnChangeKey() {
      /* istanbul ignore next (preact) */
      if (isPreact) {
        return 'onInput';
        /* istanbul ignore next (react-native) */
      } else if (isReactNative) {
        return 'onChangeText';
      } else {
        return 'onChange';
      }
    }
  }, 

We can that it is not eliminated here (without minification).

I've removed input_getOnChangeKey helper and just inlined this if/else at the call site, but generally this details doesn't matter (except we've shaven off few bytes, because there is no method now) and it looks like this now:

    var onChangeKey = void 0;
    /* istanbul ignore next (preact) */
    onChangeKey = 'onChange';

Still without minification. It seems that rollup also does some dead code elimination on its own, but has less superior algorithm.

When it comes to UglifyJS there are also many versions out there and there are also many settings that one can specify for it. Dunno if such constants can be easily inlined in every case if they are not local. I was under the impression that many times it fails and this wouldn't be properly dead code eliminated.

For sure flat bundling helps here, because if it would be split across files uglifyJS wouldnt be able to eliminate this, that is something im 100% sure.

But anyway as we cannot be sure what kind of minification settings or uglifyJS version consumers' are using it's just better to put those constant conditions as local as possible as it's always easier to analyze local situation than more global one and we can make it easier for other tools (also other minifiers out there) to handle this properly.

Copy link
Member

@kentcdodds kentcdodds left a comment

Choose a reason for hiding this comment

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

Looking great!

package.json Outdated
"build": "kcd-scripts build --bundle --p-react",
"build": "npm run build:web --silent && npm run build:native --silent -- --no-clean",
"build:web": "kcd-scripts build --bundle --p-react",
"build:native": "BUILD_REACT_NATIVE=true BUILD_FILENAME_SUFFIX=.native kcd-scripts build --bundle cjs",
Copy link
Member

Choose a reason for hiding this comment

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

Let's add a devDependency on cross-env and use that here so this works on windows machines as well (considering the setup script will run validate which will run the build. I want to make sure that script always works on windows.

Copy link
Collaborator

Choose a reason for hiding this comment

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

done

const rootNode = this._rootNode
scrollIntoView(node, rootNode)
/* istanbul ignore else (react-native) */
if (preval`module.exports = process.env.BUILD_REACT_NATIVE !== 'true'`) {
Copy link
Member

Choose a reason for hiding this comment

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

I like that idea. Let's add a feature to kcd-scripts and then upgrade this to use that feature.

I think we'll want to configure that somehow though (CLI args?) because there are some process.env.* variables that we want to leave as-is.

@kentcdodds
Copy link
Member

i have no idea what root_handleClick is, i dont see it anywhere in the project and it caches this.props.onClick which can lead to stale values being used

I think that's probably a left-over mistake or something. Feel free to remove it as part of this PR! Thanks!

@Andarist
Copy link
Collaborator

Andarist commented Feb 6, 2018

I like that idea. Let's add a feature to kcd-scripts and then upgrade this to use that feature.

I can do that, but this shouldnt hold off this PR

I think we'll want to configure that somehow though (CLI args?) because there are some process.env.* variables that we want to leave as-is.

Not sure what variables you'd like to leave as is, I'd just take all process.env.* and put it through rollup-plugin-replace. One must actually use env var in a code for it to have any effect, so danger of using some additional env var that was not supposed to get through is actually pretty low imho.

I think that's probably a left-over mistake or something. Feel free to remove it as part of this PR! Thanks!

gonna send separate PR for this

@kentcdodds
Copy link
Member

The thing is we want to use process.env.NODE_ENV for some things: https://github.com/paypal/downshift/blob/531bd8ea83ae5ecc3c163357ac9be4dc721d2060/src/downshift.js#L78

I imagine we'll want to use it in the future as well. Currently the UMD bundle replaces that (development for umd and production for umd.min), but for cjs and esm we want to leave those as-is. But honestly those are probably the only ones we'd care to leave as-is so we can probably make that work 👍

I agree that should not hold up this PR.

Is this ready to merge then?

@kentcdodds
Copy link
Member

I think when we merge this we'll merge this with a note that it's experimental and could break. Would be good to get feedback on it before it's official.

@Andarist
Copy link
Collaborator

Andarist commented Feb 6, 2018

I imagine we'll want to use it in the future as well. Currently the UMD bundle replaces that (development for umd and production for umd.min), but for cjs and esm we want to leave those as-is. But honestly those are probably the only ones we'd care to leave as-is so we can probably make that work 👍

damn, I totally forgot about process.env.NODE_ENV checks, you are right ofc - it's probably the only cause we'd like to omit for cjs & es bundles

Is this ready to merge then?

from my POV - yes

I think when we merge this we'll merge this with a note that it's experimental and could break. Would be good to get feedback on it before it's official.

Sure thing.

Copy link
Member

@kentcdodds kentcdodds left a comment

Choose a reason for hiding this comment

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

Awesome. I'm merging this now.

Here's what we need before react-native support becomes stable:

  1. A committed maintainer (I don't use RN, so I can't maintain it). I think at least 2 of you are committed here :)
  2. At least one integration test (see ./other/misc-tests). I don't know what would be involved, but I would like to make sure we have something in place to not break RN before we commit to supporting it.
  3. Documentation

Once we get all of those, then we can officially announce it and commit to not breaking things (intentionally) without semver major.

@kentcdodds kentcdodds merged commit 6f9a306 into downshift-js:master Feb 6, 2018
Rendez pushed a commit to Rendez/downshift that referenced this pull request Sep 30, 2018
Rendez pushed a commit to Rendez/downshift that referenced this pull request Sep 30, 2018
…target (downshift-js#265)

* Add isReactNative util function

This can be used to determine if the current target is React Native.

See facebook/react-native#10881 and https://github.com/facebook/react-native/blob/70c359000a2df091c3939f4c19db6024af992d43/Libraries/Core/InitializeCore.js#L194-L195 for more info.

* Ensure correct onChange prop is supplied for React Native

* Configure onPress item prop

* Ensure navigator is defined before calling for a property

* Fix typo

* Wrap mouse event listener in non-ReactNative checks

* Ensure call to get item node from index throws on React Native

* Ensure correct event handler is passed to getButtonProps

* Ensure no calls to getItemNodeFromIndex on React Native

* Use a safer check for testing for React Native

This fixes errors that are thrown on SSR builds

* Add build script for React Native product

* Use preval macro to determine if product is React Native

This should help eliminate some overhead to non-React Native targets.

* Add react-native directory to gitignore

* Add react-native directory to distributed files

This matches the same delivery technique as preact

* Remove unnecesary comments

* Remove React Native specific error

* Update comment about isReactNative

* Move isPreact preval to utils

This will match the isReactNative preval as well, unifying these methods.

Additionally, we can drop the Boolean cast, improving minification, if we disable Istanbul in here.

* Disable coverage on React Native specific codepaths

Since we don't have a test suite for React Native yet, we can't cover these paths.

* Add react-native package directory

This will allow for a separate react-native build using this directory

* Fix bad rebase

* Ensure that internal state is still set on React Native

* Add separate command for building web

The build command now builds for both web and native targets

* Use babel over Rollup for React Native builds

This will prevent us from smashing against different build targets by sharing a build directory.

This also uses the "react-native" key in the package.json to tell Metro
Bundler where to get the module from.

* Prefer using inline prevals over exporting a constant

This will allow Rollup to optimize builds for UMD, ESM and CJS, without minification.

* Remove unneeded call to scrollHighlightedItemIntoView

* Further tweaks for react native build setup

* Use cross-env to set env vars
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.

Implement support for React Native
6 participants