React / ReactDOM: 16.4.2
I'm having trouble reproducing this, but I'm raising it in the hope that someone can give me some clues as to the cause. I have a large application which is using Fragment
in a few places, like so:
<React.Fragment>
<div>Child 1-1</div>
<div>Child 1-2</div>
</React.Fragment>
<React.Fragment>
<div>Child 2-1</div>
<div>Child 2-2</div>
</React.Fragment>
In everything but Internet Explorer, this renders as you'd expect:
<div>Child 1-1</div>
<div>Child 1-2</div>
<div>Child 2-1</div>
<div>Child 2-2</div>
However, for some reason in Internet Explorer 11, these are being rendered as some weird tags:
<jscomp_symbol_react.fragment16>
<div>Child 1-1</div>
<div>Child 1-2</div>
</jscomp_symbol_react.fragment16>
<jscomp_symbol_react.fragment16>
<div>Child 2-1</div>
<div>Child 2-2</div>
</jscomp_symbol_react.fragment16>
I've tried pausing the code at the transpiled _react.createElement(_react.Fragment)
line, and the _react.Fragment
export is a string with the same name as the tag (jscomp_symbol_react.fragment16
). I think this is just the correct way in which the symbol polyfill works and that React should recognize it as something other than an HTML tag.
What's even weirder is that this only happens sometimes. If two components in my app are using fragments, the first one to render may have the above issue, the second may not. If an affected component re-renders, the rendered DOM will be corrected. I haven't found a solid pattern to this yet.
I have a fairly typical webpack + babel setup, and using the babel-polyfill for symbol support. I'm really not sure what parts of my setup are relevant to this so please let me know if you need any extra info. Again, I'm trying to create a reproduction outside of my application but if anyone can offer me some clues in the meantime I'd be incredibly grateful.
Is it possible that you load babel-polyfill
between react
and react-dom
is loaded, so one of them thinks Symbol is supported, but the other one thinks Symbol isn't supported? Then they would get out of sync which can lead to confusing behavior.
See https://github.com/facebook/react/issues/8379#issuecomment-263962787 for a similar problem. You can search for typeof Symbol
checks in both react
and react-dom
bundles, and put some logs there to verify if they “agree” whether Symbol
exists or not.
Thanks for your reply.
I'm getting somewhere with this now. After deconstructing my app bit-by-bit, the surprising cause of this appears to be... Google Maps!
I'm loading the Google Maps JavaScript API with a script tag, then loading my bundled app with another script tab. If I reverse these, it works.
It looks like the Google Maps API includes a Symbol polyfill of its own which is somehow confusing things. I'm still none the wiser as to why though as after looking at the lines of code you suggested I'm even more confused...
There are three instances that I can see where React libraries (react, react-dom, and react-is) are checking for Symbol.for
, and all three say it does exist and appear to point to the same function which, as far as I can tell, is the core-js implementation, not Google Maps':
Symbol.for function (key) { return has(SymbolRegistry, key += '') ? SymbolRegistry[key] : SymbolRegistry[key] = $Symbol(key); }
So irrespective of whether Google Maps is loaded first, last, or not at all the bundled application and all of the React libraries appear to use the same core-js polyfill of Symbol. So why this is an issue at all is a mystery to me, as is why loading Google Maps first has any influence over it.
Also, since you mentioned it, and just in case the Google Maps thing is a red herring, I'm pretty sure I'm loading babel-polyfill before everything else by having the following in my webpack config:
entry: [
'babel-polyfill',
path.resolve(__dirname, 'src/index.js') /* my entry point */
]
As far as I'm aware, this will load the polyfill before anything else.
Thanks again.
If you can reduce it to a reproducible example (now that you know it has something to do with Google Maps) I can take a look.
Thanks! I think I've got it down to its bare bones here:
https://github.com/jamiewinder/ie11-fragment-issue
You should be able to just run yarn run build-run
. If you look at the DOM in Internet Explorer 11 you should see the weird tag. If you click the Update button on the component (which re-renders it), the tag then goes away.
If you then reverse the script tags in index.html (so Google Maps is loaded last) then the weird tag never appears in the first place!
Thanks. I won't have time to dig into this in close future but I'll leave this for somebody motivated.
have dealt with this same issue in InstantSearch.js (we were using preact), and the fix was this: https://github.com/developit/preact-compat/pull/423
We do check for for
though.
The problem is that core-js polyfill for Symbol.for
uses global Symbol which doesn't get polyfilled because it is already defined by gmaps. However, maps' implementation of Symbol returns string while correct implementations return actual symbol or object, so it's possible to check if Symbol returns value of valid type. It's quite hacky though and I'm not sure whether this check should be implemented in core-js or React.
As @sanniassin pointed out, the Google Maps polyfill is causing Symbol()
to return strings. There are various places in the React code that check the typeof an element's type
, and often checking for string types before checking for the REACT_FRAGMENT_TYPE
'Symbol' e.g here
the Google Maps polyfill is causing Symbol() to return strings
Jeez. Okay. Can we report it to them?
I had the same issue before and I solved it by fixing the version of Google Maps
<script src="https://maps.googleapis.com/maps/api/js/33/2?v=3"></script>
I tried it in your example and it is working fine.
Do you mean a newer version fixes it? Or an older one?
Unfortunately older one
Seems to be an issue with the Symbol polyfill implementation from the Closure compiler, see Sam Saccone's tweet
I filed https://github.com/google/closure-compiler/issues/3052. I don't think we'll be adding more "bad Symbol polyfill" checks — IMO something that GCC should fix.
According to https://github.com/google/closure-compiler/issues/3052#issuecomment-413696150, one workaround would be to ensure that core-js
code (which you run via babel-polyfill
) executes earlier than the Google Maps bundle. I guess you could load the Google Maps API asynchronously (and not assume it's loaded yet in your app code) by creating a dynamic script tag and hooking into its onload
event.
Thanks, that's what I ended up doing. My bundled app is the first script to run, so core-js gets to install its polyfill first.
Adding the Google Maps library is also now done with the load-google-maps-api library to ensure it's done within the polyfilled app but before the parts of the app that use it. Works well.
Thanks for all of your help with this.
Many thanks to all. I'm using ReCaptcha from Google and I had the same. When I moved the recaptcha script call AFTER my bundle.js, everything went just fine.
#
Most helpful comment
Seems to be an issue with the Symbol polyfill implementation from the Closure compiler, see Sam Saccone's tweet