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

Remove old IE polyfill code #10238

Merged
merged 3 commits into from
Aug 3, 2017
Merged

Conversation

jquense
Copy link
Contributor

@jquense jquense commented Jul 20, 2017

This is a bit of an experiment in what can be pulled out here. I’m not yet convinced it’s a good idea. I need to fixup my branch at least.

  • Removes onClick logic for radio and checkboxes, believe that was ie8 only

  • removes a substantial chunk of of the input polypill. ie9 partially supports onInput already, and we only need to add in the selection change event to handle the cases it doesn’t work on, e.g. deleting text

For everything else we don’t distinguish between when to use change vs input (such as for select inputs) since we listen to both and dedupe.

I tested against the fixtures on IE9 with positive results!

@jquense jquense requested review from nhunzaker and sophiebits and removed request for sophiebits July 20, 2017 17:12
topLevelType === 'topKeyDown'
topLevelType === 'topInput' ||
topLevelType === 'topChange' ||
topLevelType === 'topSelectionChange'
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 might be worth keeping the top level keyUp and keyDown since it's easy

Copy link
Contributor

Choose a reason for hiding this comment

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

What would we lose?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the original comment:

99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
propertychange on the first input event after setting value from a
script and fires only keydown, keypress, keyup. Catching keyup usually
gets it and catching keydown lets us fire an event for the first
keystroke if user does a key repeat (it'll be a little delayed: right
before the second keystroke). Other input methods (e.g., paste) seem to
fire selectionchange normally.

It says IE8 only but one never knows right? We could add them back for sense of security, downside is just a few more lines of code, and maybe cargo-culting in code.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think having them here plus a todo for further investigation sounds good to me.


// For IE8 and IE9.
// In IE9 the input event does not fire for deleting text. Luckily
// selectionchange does, so we also listen for that in those cases.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this true? I tested this build out in IE9 on Windows 7 and it wasn't dispatching change events for deletion. But I also tested out master and I saw the same problem. Are you seeing something different?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oops it is true, but we aren't hitting this path, because the targetInst is null...I wonder if that is related to selectionchange not having the right target? why would the instance be null in this case?

and this bug is definitely in master as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok yeah this bug is probably in all versions of react. The Event responder can't find the associated instance for this event because the target is the document. This would be true for any weird events like this...

@aweary
Copy link
Contributor

aweary commented Jul 20, 2017

I think it'd be great if we could land this. I published the DOM fixtures with this build here:

http://remove-ie9-change-polyfills.surge.sh/

@jquense
Copy link
Contributor Author

jquense commented Jul 20, 2017

Updated with fixed logic

@nhunzaker
Copy link
Contributor

Very cool. @jquense I didn't want to let this grow cold. I should be able to get a solid chunk of time to dig into this later today.


// On the selectionchange event, the target is the document which isn't
// helpful becasue we need the input, so we use the activeElement instead.
if (!isTextInputEventSupported && topLevelType === 'topSelectionChange') {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

so this was the problem (and is the problem on master/stable) there is no targetInst for this event so there is no way this event will get published to react-land

Copy link
Contributor

Choose a reason for hiding this comment

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

Does getActiveElement not return the correct node for getting the instance from getInstanceFromNode?

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 does generally, The null check is out of caution, since this depends on on the input being focused, there may be edge cases where focus drops or some programatic driving of the browser doesn't set focus, etc. I don't think there is much we can do about such edge cases and wanted to limit the possible effect to only cases where the polyfill was being used.

Copy link
Contributor

@nhunzaker nhunzaker Jul 20, 2017

Choose a reason for hiding this comment

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

This is a frustrating constraint, but it sounds we can't do anything about it. 👍.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We were already tracking the active element for this code so the constraint isn't new, i'm just deferring to activeElement instead of caching it locally in a variable.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, cool.

@@ -54,7 +54,7 @@ describe('ChangeEventPlugin', () => {
);

setUntrackedValue(input, true);
ReactTestUtils.SimulateNative.click(input);
ReactTestUtils.SimulateNative.change(input);
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry if this was asked before: why the switch from click to change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Radios and Checkboxes were listening for onClick, i removed that in favor of just listening for onChange/onInput like text inputs.

I'm not entirely sure why the original code used click, the comment suggested it was for IE8, it appears to work fine in IE9 though

Copy link
Contributor

Choose a reason for hiding this comment

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

Cool. I like this better too, but I wasn't sure on the legacy. 👍

@jquense
Copy link
Contributor Author

jquense commented Jul 20, 2017

It should be noted that this narrows the scope of the onInput polyfill to only IE9, originally it was falling back to the polyfill for any env that didn't have onInput, but at this point I think that check is exactly the same as "just IE9" given the support in other browsers.

clearTimeout(id);
};
}());
</script>
Copy link
Contributor

@nhunzaker nhunzaker Jul 20, 2017

Choose a reason for hiding this comment

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

Where does requestAnimationFrame come in?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

React apparently requires it, I got a warning for it being missing. Not sure what the official place to snag it is

Copy link
Contributor

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Fiber currently requires it, I think this way is fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is fine.

};
}());
</script>
<script src="https://unpkg.com/babel-polyfill@6.23.0/dist/polyfill.min.js"></script>
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think using babel-polyfill will be problematic at all? It might make it easy to miss changes that won't work in all our supported browsers by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that's a good question...we should probably use a very focused set of polyfills according to what React says it requires. Should also help keep React honest about that as well :P

I just didn't know what React requires now, for instance in DEV you need Set which didn't seem obvious

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, I like that with requestAnimationFrame we have an invariant so it fails early. I feel like we should do the same with other stuff like Set or Map if we have a hard requirement on those without fallbacks.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, please let’s keep this focused on Map and Set.

topLevelType === 'topSelectionChange' ||
topLevelType === 'topKeyUp' ||
topLevelType === 'topKeyDown'
topLevelType === 'topInput' ||
Copy link
Contributor

Choose a reason for hiding this comment

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

If getTargetInstForInputEventPolyfill is only used in a browser (IE9) that doesn't support the input event, does it make sense to check for topInput?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Its like a half-polyfill, we actually do rely on IE9's native onInput but patch around it so it's not unusably buggy. Specifically it works fine except when deleting text (lol), the selectionchange covers that case.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK cool, got it. For some reason, I was thinking IE9 didn't fire input events 😄

@nhunzaker
Copy link
Contributor

@jquense I did a local build and booted this up. I can not change the fixture select or react version dropdown. (neither can I on http://remove-ie9-change-polyfills.surge.sh/):

cange

This is in Chrome 59. Any idea what's going on?

@aweary
Copy link
Contributor

aweary commented Jul 20, 2017

I'm seeing that same problem as well.

On another note, it looks like the Angular team ran into the backspace issue and used the change and keydown events to side-step it. Could we do the same?

Reference: angular/angular.js#936

@jquense
Copy link
Contributor Author

jquense commented Jul 20, 2017

O wow selects in Chrome do some very weird things when you listen for both Input and Change, the change event has an empty value. (wat?). Lets go back to just using change for that, the intent wasn't really to change that behavior anyway.

@jquense
Copy link
Contributor Author

jquense commented Jul 20, 2017

To recap:

  • select and file inputs: listen to change
  • ie9 text inputs: listen to change input, selectionchange, keydown, and keyup
  • everything else: change and input

multiple events are deduped

@nhunzaker
Copy link
Contributor

Cool. I'll pick up heavy duty browser QA and report back.

}

if (getTargetInstFunc) {
var inst = getTargetInstFunc(topLevelType, targetInst);
var inst = getTargetInstFunc(topLevelType, targetInst, targetNode);
if (inst) {
var event = createAndAccumulateChangeEvent(
Copy link
Contributor

Choose a reason for hiding this comment

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

@jquense can we use targetNode as nativeEventTarget for selection events in IE9? When you start backspacing it registers a change event but it gets undefined for event.target.value since event.target is still the document.

Copy link
Contributor

@aweary aweary Jul 20, 2017

Choose a reason for hiding this comment

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

If we use this same check to branch when calling createAndAccumulateChangeEvent it should fix input backspacing in IE9 (tested locally).

var event = createAndAccumulateChangeEvent(
  inst,
  nativeEvent,
  (!isTextInputEventSupported && topLevelType === 'topSelectionChange')
     ? targetNode
      : nativeEventTarget,
);

We can dedupe that check with a constant, but yeah. I think that should be work?

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 so! I forgot about actual event target, good call

@nhunzaker
Copy link
Contributor

nhunzaker commented Jul 21, 2017

Found an issue in IE9. EDIT: Sorry, looks like @aweary beat me to it.

  1. Open the text input fixture (http://localhost:3000/text-inputs
  2. Go go "Cursor when editing email inputs"
  3. Enter "user@example.com"
  4. Backspace
  5. I receive the following error:
Warning: A component is changing a controlled input of type email to be uncontrolled...https://fb.me/react-controlled-components
    in input (at InputTestCase.js:46)
    in fieldset (at InputTestCase.js:44)
    in div (at InputTestCase.js:43)
    in div (at Fixture.js:13)
    in Fixture (at InputTestCase.js:40)
    in InputTestCase (at index.js:56)

This is because the value is getting lost, like e.target.value is undefined and that throws our controlled input validations.

This is not an issue in IE10, IE11, or Edge.

@jquense
Copy link
Contributor Author

jquense commented Jul 24, 2017

the eventTarget issue should be fixed btw

@nhunzaker
Copy link
Contributor

Tested successfully in:

Chrome 59, 51
Opera 46
Safari 10.1*
Firefox 48
IE 11
Edge 15
Yandex 14.12
iOS 8
Chrome Android 5.1

*Safari does not accept key input on range inputs, unless I've missed something

Copy link
Collaborator

@gaearon gaearon left a comment

Choose a reason for hiding this comment

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

Seems like this is good to go, except for the fixtures polyfill part? I trust you folks to test this well :-)

@jquense
Copy link
Contributor Author

jquense commented Aug 2, 2017

ok updated the polyfill situation. I ended up getting a CRA upgrade in there and moving the loader stuff into webpack-land so I didn't have to get a browser build of the core-js polyfills i wanted

@gaearon
Copy link
Collaborator

gaearon commented Aug 2, 2017

It would be nice to separate fixture changes in another PR (we can take it sooner). So that if we end up reverting this, we don't risk merge conflicts in fixtures.

@jquense
Copy link
Contributor Author

jquense commented Aug 2, 2017

The up[grade was sort of triggered by how I needed to tweak the entry to allow the more focused polyfilling. I could split it out and then rebase just the onChange on top of it if that's easier. Or structure the commits a bit better so you can revert the one cleanly if needed

Upgrade to react-scripts v1 and include required polyfills for older
browsers
@gaearon
Copy link
Collaborator

gaearon commented Aug 2, 2017

I'm just proposing to split any changes in src from other changes. Other changes could get in earlier separately (even if they cause fixture to fail).

@jquense
Copy link
Contributor Author

jquense commented Aug 2, 2017

I cleaned up the commits. I can split them into two PR's but it seems like we are pretty ready to go with this, so it may not save much. That is unless @nhunzaker or @aweary won't have a chance to test again for a while.

@nhunzaker
Copy link
Contributor

@jquense I can do some thorough QA later today, if it can wait 3 hours.

@jquense
Copy link
Contributor Author

jquense commented Aug 2, 2017

of course, no rush :)

@aweary
Copy link
Contributor

aweary commented Aug 2, 2017

I'm a little busy this week, but I can possibly get some QA in tomorrow if there's still a need for it ❤️

@nhunzaker
Copy link
Contributor

I did it! This works in the following browsers:

  • Chrome OSX Sierra 59
  • Safari OSX Sierra 10.1
  • Safari OSX Lion 6
  • IE 9 Windows 7
  • IE10 Windows 7
  • IE11 Windows 10
  • Edge 15 Windows 10
  • Firefox 46 Windows 10
  • Opera 38 Windows 10
  • Nexus 6 Android 5
  • Safari iPhone 4s IOS 6
  • Safari iPhone 6s IOS 10
  • Yandex 17.7 OSX Sierra

@gaearon gaearon merged commit 0b220d0 into facebook:master Aug 3, 2017
@gaearon
Copy link
Collaborator

gaearon commented Aug 3, 2017

Thanks!

@jquense
Copy link
Contributor Author

jquense commented Aug 3, 2017

pour one out for the super clever ie8 onInput polyfill 🍾

@jquense jquense deleted the trim-ie8-change-code branch August 3, 2017 14:01
@gaearon
Copy link
Collaborator

gaearon commented Aug 3, 2017

Not too fast, maybe we’ll have to revert 😛 These things are tricky

@jquense
Copy link
Contributor Author

jquense commented Aug 3, 2017

indeed, i've learned that the hard way.

flarnie added a commit to flarnie/react that referenced this pull request Aug 17, 2017
**what is the change?:**
This reverts facebook@0b220d0
Which was part of facebook#10238

**why make this change?:**
When trying to sync the latest React with FB's codebase, we had failing
integration tests.

It looks like they are running with an old version of Chrome and there
is something related to file upload that fails when these polyfills are
missing.

For now we'd like to revert this to unblock syncing, but it's worth
revisiting this change to try and add some polyfill for FB and remove it
from React, or to fix whatever the specific issue was with our file
upload error.

**test plan:**
`yarn test` and also built and played with the `dom` and `packaging`
fixtures
flarnie added a commit that referenced this pull request Aug 17, 2017
**what is the change?:**
This reverts 0b220d0
Which was part of #10238

**why make this change?:**
When trying to sync the latest React with FB's codebase, we had failing
integration tests.

It looks like they are running with an old version of Chrome and there
is something related to file upload that fails when these polyfills are
missing.

For now we'd like to revert this to unblock syncing, but it's worth
revisiting this change to try and add some polyfill for FB and remove it
from React, or to fix whatever the specific issue was with our file
upload error.

**test plan:**
`yarn test` and also built and played with the `dom` and `packaging`
fixtures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants