Skip to content
This repository has been archived by the owner on Sep 20, 2019. It is now read-only.
This repository has been archived by the owner on Sep 20, 2019. It is now read-only.

webcomponents-loader usage causes IE11 SCRIPT28 Out of stack space #972

Closed
morewry opened this issue Jul 17, 2018 · 29 comments
Closed

webcomponents-loader usage causes IE11 SCRIPT28 Out of stack space #972

morewry opened this issue Jul 17, 2018 · 29 comments
Assignees

Comments

@morewry
Copy link

morewry commented Jul 17, 2018

I am having a complicated-for-me issue with my Web Components and webcomponents-loader in @webcomponents/webcomponentsjs@2.0.2. This issue has been encountered by others before, but the information in the issues has not been sufficient for me to track down the root cause or fix it.

I work on a shared library consumed by multiple applications, so I have Web Components published as npm modules. The component I'm debugging is (currently) built with Rollup using Babel@6. It is configured to use babel-plugin-transform-custom-element-classes and babel-plugin-transform-runtime via babel-preset-env with babel-runtime as a dependency.

Note: I first encountered the IE11 stack overflow while building the Web Component with Webpack and having the application use webcomponents-bundle and babel-polyfill. My first attempt to prevent or work around the issue was to start using webcomponents-loader as I'd originally intended, stop the use of babel-polyfill, and begin using the "runtime" approach above. I then ran into known issues with Webpack and babel-plugin-transform-runtime. So I switched to Rollup as it was something I'd intended to try, it spit out more recognizable code to help me debug, and it didn't have those known issues. Then I ran into the issue again with this combination.

Ultimately, these are the ones that are identified as needed in runtime for the Web Component:

  • babel-runtime/core-js/object/set-prototype-of
  • babel-runtime/core-js/reflect/construct
  • babel-runtime/core-js/object/get-prototype-of
  • babel-runtime/helpers/classCallCheck
  • babel-runtime/helpers/createClass
  • babel-runtime/helpers/possibleConstructorReturn
  • babel-runtime/helpers/inherits
  • babel-runtime/core-js/json/stringify
  • babel-runtime/core-js/object/freeze
  • babel-runtime/core-js/object/values
  • babel-runtime/core-js/object/keys
  • babel-runtime/core-js/object/assign
  • babel-runtime/helpers/defineProperty
  • babel-runtime/core-js/weak-map
  • babel-runtime/helpers/slicedToArray
  • babel-runtime/core-js/object/entries
  • babel-runtime/helpers/get

Next, the Web Component is used in an application. The application I'm debugging is an Angular 1.x application (however, I don't think it being Angular is particularly relevant to the issue). The application is built with Webpack using Babel@6 with babel-preset-env.

At that point, we still need Web Component polyfills, for which we are attempting to use the webcomponents-loader in @webcomponents/webcomponentsjs@2.0.2. My recommendation to my users is including the Web Component polyfills via a script tag in the head.

<head>
  <script src="./@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
</head>

The bundled application is included via a script tag in the body. This includes the Web Component, the polyfills listed above via babel-runtime, and the application's code.

<body>
  <script src="./main.js"></script>
</body>

In IE 11, I get a stack overflow error: SCRIPT28: Out of stack space in File: webcomponents-sd-ce-pf.js, Line: 55, Column: 813. This corresponds to the line that reads defProp(this, tag, defValue(value, { c: true, w: true }));.

ie11-errors

Note: The second error here can be ignored for the purposes of this issue.

webcomponents-line-problem

I have read some of the other issues about this error from this and other projects, including #942 and #968. Like #968, if I load all of core-js before webcomponents-loader, the error goes away.

<head>
  <script src="//cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/core.min.js"></script>
  <script src="./@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
</head>

However, I don't view this as a fix and need to isolate the root problem further.

As a library author, I don't have day-to-day oversight of the application builds. It's in no one's best interest for me to ask for a bunch of special configuration and knowledge about "chunking"or "load order" from each application team. Luckily, as an internal library author, I know our support needs, so my goal is to get this to a place where it more-or-less works like your typical third party npm dependency with a typical Webpack configuration.

We're on track for that with the current "runtime" setup, except for Web Component polyfills and this error. Web Component polyfills can remain an un-bundled exception that has to be loaded independently--but not if it means I have to reinvent the way we're doing everything else due Web Component polyfills needing other polyfills that can't work in tandem with our application bundles and the polyfills inside it. Or whatever the issue is.

On which note... It was hard to tell, but it seemed like #942 identified the issue as being conflicting polyfills for Promise, but that doesn't seem likely in this scenario. As you can verify in the runtime list above, I am not directly using Promise in the Web Component and the app is using Angular 1.x's $q instead of native promises, so no Promise polyfill except the one in webcomponents-loader should be loaded (and that's the case, so far as I can tell in the final Webpack vomit bundle). But there was also some stuff about Google Closure in there... I couldn't really tell what the problem and solution were from reading it.

Some additional issues: jods4/aurelia-webpack-build#33
aurelia/cli#843
aurelia/skeleton-navigation#821
angular/zone.js#316
zloirock/core-js#143
zloirock/core-js#96
preactjs/preact#453
SharePoint/sp-dev-docs#888

I keep coming back to the idea that we should externalize and conditionally load all of our polyfills, possibly via https://polyfill.io, but since none of the Web Component polyfills are on already on there, that option has been more than I've had time to take on. Especially in terms of limiting the potential polyfills to only things that are used...which would be nice.

@morewry
Copy link
Author

morewry commented Jul 20, 2018

Although it's not a viable approach for my purposes, I tried loading webcomponents-loader asynchronously, just to see.

The result was interesting.

Promise is undefined webcomponents-loader

Promise.all whenloadedFns.map

My reading of this is that webcomponents-loader uses Promise, which is one of the things it needs to load a polyfill for. But that code using Promise presumably should only run after the polyfill is loaded...if so, how does this error occur?

Although I didn't think this was really the issue, I went back to synchronously loading and tried loading just a Promise polyfill beforehand, instead of all of core-js. That took me back to the original error.

<script src="//cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.min.js"></script>
<script src="./@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>

Out of stack space / Stack overflow

symbol.js defProp

Again, this is webcomponentsjs@2.0.2.

@morewry
Copy link
Author

morewry commented Jul 20, 2018

<script src="//cdn.polyfill.io/v2/polyfill.min.js"></script>
<script src="./@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>

This also prevents the error, which may be useful to someone.

To narrow it down, though, I created a polyfills file so I could build and test combinations of different specific core-js polyfills. First one I tried was for Symbol, given the error is really from the symbol.js polyfill included in webcomponents-sd-ce-pf.js

polyfills.js
import 'core-js/fn/symbol';
app index.html
<head>
  <script type="text/javascript" src="polyfills.js"></script>
  <script src="./@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
</head>

This also resolves the IE 11 error. I'd love to understand why the Symbol polyfill used by webcomponents-loader causes a stack overflow in IE11 and why it presumably only happens for some users.

What appears to be fixing the problem here is that a Symbol polyfill that doesn't cause a stack overflow gets loaded and creates window.Symbol. Then the feature is detected in @webcomponents/webcomponentsjs/src/symbol.js, so the other polyfill that is built into webcomponents-sd-ce-pf (es-symbol/dist/symbol.js) doesn't get used.

Remember, I'm not trying to bundle webcomponents-loader. It's not being touched by my build process at all; I'm simply adding a script tag to the head pointing to the webcomponents-loader published in the npm package @webcomponents/webcomponentsjs@2.0.2. I'm not using Symbol in my Web Component. The app is not using Symbol, either.

So, from my perspective at the moment, it appears that this package is using a broken Symbol polyfill...but if that's so, why isn't an issue for everyone using the package?

@morewry
Copy link
Author

morewry commented Jul 20, 2018

I've looked a little bit more into the es-symbol polyfill and note that the last update to it was three years ago, it has only 2,009 downloads per week on npm, and only 4 dependents on npm. While lack of updates can mean a module is stable and downloads are not an accurate measure of real usage, taken in combination with the fact that the GitHub issue I filed is the very first one filed in the es-symbol repo, I might suggest it's not the best choice if there is a more heavily vetted polyfill for Symbol.

In comparison, core-js was updated this month, has 7,073,884 downloads per week on npm, 6,280 dependents on npm, 17 open GitHub issues, 312 closed GitHub issues, and is used by babel, which could potentially make its Symbol polyfill the most highly used Symbol polyfill available.

Just a thought, since I'm not 100% sure this is the issue, but it certainly looks that way to me right now.

@lpellegr
Copy link

lpellegr commented Jul 29, 2018

I am encountering the same issue testing on IE11 a Polymer 3 PWA built for differential serving with Polymer bundler .

@TimvdLippe
Copy link
Contributor

@morewry Thanks for the very thorough investigation and sorry for running into this complicated issue.

I keep coming back to the idea that we should externalize and conditionally load all of our polyfills, possibly via https://polyfill.io, but since none of the Web Component polyfills are on already on there, that option has been more than I've had time to take on. Especially in terms of limiting the potential polyfills to only things that are used...which would be nice.

This appears to be WIP by @bedeoverend at polyfillpolyfill/polyfill-service#1376

So, from my perspective at the moment, it appears that this package is using a broken Symbol polyfill...but if that's so, why isn't an issue for everyone using the package?

I am curious as well, as our IE11 are passing just fine. I wonder what the difference in configuration is. If you are able to figure it out, do you mind filing a PR on this repo with a regression test? That would be greatly appreciated to make sure we do not regress in the future.

That said, I would be open to switching to a different Symbol polyfill, if these are fixing the real-world issues and we do not regress for current users. For that, we need 1. regression tests for the current issues 2. pick a good polyfill (core-js seems good?) 3. make sure we do not break current users.

If you do not have time for all 3 action points, please work on action point 1 and I can work from there.

Once again thanks for your efforts thus far and hopefully we can address this in the near future!

@morewry
Copy link
Author

morewry commented Jul 31, 2018

@TimvdLippe,

I am most likely in a place of diminishing returns.

I know that replacing the Symbol polyfill fixes it for me. I realize that there is more to find; some additional circumstance that causes the stack overflow. I'd even previously used the polyfills in prototypes without this error, but there are a lot of moving parts. Much as I would like to help further, getting it down to the unit level on this type of thing is a time issue for me, because I'm just not that good an "engineer". I'm sort of a web designer who coded too much and became a front end web developer just in time to find myself trapped in a JavaScript hellscape.

In terms of what I'm doing now, I'm exploring some possibilities inspired by https://github.com/webcomponents/webcomponentsjs/issues/891, because it seemed promising from my perspective. Unfortunately, I was shortly stymied in my reverse engineering. I can't quite tell why the Symbol polyfill is being included, because I only see Symbol in code that exists to check on support for or further polyfill Symbol, not in code that appears to actually use Symbol.

I've gotten as far as creating my own entrypoint for the polyfills I know I need.

// for CustomEvent; also includes Object.assign and Array.from (unnecessarily for me)
import '@webcomponents/webcomponents-platform/webcomponents-platform.js';
import '@webcomponents/shadydom/src/shadydom.js';
import '@webcomponents/custom-elements/src/custom-elements.js';

According to babel-plugin-transform-runtime, these are the polyfills needed for those imports:

import _Object$getOwnPropertyNames from 'babel-runtime/core-js/object/get-own-property-names';
import _Object$assign from 'babel-runtime/core-js/object/assign';
import _Array$from from 'babel-runtime/core-js/array/from';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
import _getIterator from 'babel-runtime/core-js/get-iterator';
import _Object$create from 'babel-runtime/core-js/object/create';
import _Object$getPrototypeOf from 'babel-runtime/core-js/object/get-prototype-of';
import _Object$defineProperty from 'babel-runtime/core-js/object/define-property';
import _Object$getOwnPropertyDescriptor from 'babel-runtime/core-js/object/get-own-property-descriptor';
import _Set from 'babel-runtime/core-js/set';
import _Object$defineProperties from 'babel-runtime/core-js/object/define-properties';
import _typeof from 'babel-runtime/helpers/typeof';
import _slicedToArray from 'babel-runtime/helpers/slicedToArray';
import _Map from 'babel-runtime/core-js/map';
import _toConsumableArray from 'babel-runtime/helpers/toConsumableArray';
import _Promise from 'babel-runtime/core-js/promise';
import _Object$setPrototypeOf from 'babel-runtime/core-js/object/set-prototype-of';

Some of these are handled in ways the plugin doesn't deal with (e.g. Object.assign and Array.from being embedded in @webcomponents/webcomponents-platform/webcomponents-platform.js). Some may relate to my current confusion (possibly _getIterator alone or in combination with some of the others accomplishes what @webcomponents/webcomponentsjs/src/symbol.js is doing?). Some may be handled in a different way during the distribution build steps of the packages?

Does this look right? It seems like a reasonable list of things that might be used in these polyfills, but I rely a great deal on documentation to help me understand third party implementations.

PS: I know of that PR (polyfillpolyfill/polyfill-service#1376), but (a) it's only for Custom Elements and (b) it's over a year old and hasn't had any activity from the author since then. For those reasons I don't see it as evidence of anything actively underway or likely to happen soon.

@morewry
Copy link
Author

morewry commented Jul 31, 2018

I sort of left out an important point, which was to ask, given the things included in @webcomponents/webcomponentsjs/entrypoints/webcomponents-sd-ce-pf-index.js, roughly:

import '@webcomponents/webcomponents-platform/webcomponents-platform.js';
import '@webcomponents/template/template.js';
import '@webcomponents/webcomponentsjs/src/promise.js';
// what's this for? import '@webcomponents/webcomponentsjs/src/symbol.js';
// what's this for? import '@webcomponents/webcomponentsjs/src/flag-parser.js';
import '@webcomponents/shadydom/src/shadydom.js';
import '@webcomponents/custom-elements/src/custom-elements.js';
import '@webcomponents/shadycss/entrypoints/scoping-shim.js';
// what's this for? import '@webcomponents/url/url.js';
// what's this for? import '@webcomponents/webcomponentsjs/src/baseuri.js';
// what's this for? import '@webcomponents/webcomponentsjs/src/unresolved.js';

What are the commented out items needed for?

@morewry
Copy link
Author

morewry commented Jul 31, 2018

And would it be possible to get a file in the distribution of @webcomponents/webcomponents-platform that doesn't pre-bundle Object.assign and Array.from polyfills?

@morewry
Copy link
Author

morewry commented Aug 1, 2018

And one last question, the additional code with events / flushing that's in @webcomponents/webcomponentsjs/webcomponents-bundle-index.js and @webcomponents/webcomponentsjs/webcomponents-loader.js, is that only needed to support potentially loading the polyfills asynchronously? I was somewhat surprised to find these alone made my components work in IE 11 when loaded synchronously:

import '@webcomponents/webcomponents-platform/webcomponents-platform.js';
import '@webcomponents/shadydom/src/shadydom.js';
import '@webcomponents/custom-elements/src/custom-elements.js';

I figured I was going to have a few more steps before I got to a working state.

@morewry
Copy link
Author

morewry commented Aug 9, 2018

A summary, in case these last few posts were unclear:

While I'd like to help, I don't yet feel capable of writing unit tests around the Symbol issue, because I don't know why it's in the bundle. Not knowing why means I don't understand the circumstances in which it runs. Not understanding the circumstances in which it runs means I don't know what scenarios to test or how to simulate them.

I don't understand why a number of things are in the bundle. I'd like to know purpose of all of these:

  • @webcomponents/webcomponentsjs/src/symbol.js
  • @webcomponents/webcomponentsjs/src/flag-parser.js
  • @webcomponents/url/url.js
  • @webcomponents/webcomponentsjs/src/baseuri.js
  • @webcomponents/webcomponentsjs/src/unresolved.js

In addition, @webcomponents/webcomponentsjs/webcomponents-bundle-index.js and @webcomponents/webcomponentsjs/webcomponents-loader.js entry points contain some orchestration code that I'd like to better understand the purpose of:

  • Is it essential for covering edge cases that can arise when synchronously loaded?
  • Is it to support asynchronous loading and is it unnecessary otherwise?
  • Even if/when it's unnecessary, does it confer performance benefits?

@dfreedm dfreedm self-assigned this Aug 9, 2018
@dfreedm dfreedm added the ie label Aug 9, 2018
dfreedm added a commit that referenced this issue Aug 16, 2018
- Switch out symbol polyfill to FinancialTimes' version
(promise-library)

Fixes #979
Related #972 - need to see if this implicitly fixes the IE 11 Symbol
issue
@bashmish
Copy link

bashmish commented Aug 20, 2018

First of all, this is not the case that this issue only happens to you. It happens to all of my colleagues around working with web components. The only fix that sort of worked for us is including the full babel-polyfill.js (which effectively is entire core-js bundled in one file) before webcomponents-lite.js file. At least it worked in webcomponentsjs 1.x.

Since 2.x was released it became less stable. First of all, now it works only with the loader file webcomponents-loader.js. And second, it is unstable now and still fails sometimes, looks like there is some race condition.

I see there is a fix from @azakus regarding timing issues #982 (comment)

Hopefully this will make the polyfill more stable and allow to include only the necessary polyfills.

@bashmish
Copy link

bashmish commented Aug 20, 2018

But I still feel like the webcomponents polyfill can be improved a lot.

I don't understand why would anyone include any polyfills into another polyfill. In a perfect world you should not rely on the feature which requires polyfill if you are writing another polyfill. Next, if you do want to use such a feature, just require it as a prerequisite for using your polyfill. Most app developers will include all necessary polyfills anyway, because much 3rd party code is using modern features and the code must work in IE11. So this is not a big deal to configure some extra polyfills specifically for webcomponents polyfill.

I can imagine that you wanted to simplify the usage of Web Components for new comers and make the code work with just one simple script tag <script src="src/bower_components/webcomponentsjs/webcomponents-loader.js"></script>.... but this simplicity is not worth it and leads to such confusing bugs and inability to fully control the polyfills and the order in which they are loaded in the application.

I debugged the loader behavior if all the necessary polyfills are present at the time the loader is executed. And in IE11 it still loads the bundle with polyfills injected webcomponents-sd-ce-pf.js. I think the idea was to not load the polyfills if they were not needed, that's why there is another bundle webcomponents-sd-ce.js. And this file should be also used in IE11, not only in Firefox for example.

So I'm even more confused now about what is expected behavior of the loader and if there are any tests checking for the correct behavior.

@raiseandfall
Copy link

FYI #982 (& 2.1.0) fixed the IE11 stack space issue on my side.

@TimvdLippe
Copy link
Contributor

Closing this per above comment. We are discussing the decision of external polyfill inclusion in #1007

@morewry
Copy link
Author

morewry commented Sep 28, 2018

Thanks, all!

@JeanRemiDelteil
Copy link

@TimvdLippe as of 2.1.3 I'm still having the same issue.
It's a regression from 2.1.2, as it was working at this point (I started testing from 2.1.0)

It seems that #982 fixed it, then probably #1005 broke it again (not sure)

@TimvdLippe
Copy link
Contributor

@JeanRemiDelteil I think at this point it is better to use #1007 then.

@JeanRemiDelteil
Copy link

@TimvdLippe Maybe, however, even with a "barren" bundle, (which would be good to provide), the other bundles including the Symbol polyfill would still be broken.

It's pretty sad to have a regression on a patch version.

@TimvdLippe
Copy link
Contributor

@JeanRemiDelteil We ran into the regression as well in our Polymer tests and this issue is on our radar. We are discussing potential solutions later this week and hope to have a working strategy next week.

@liorwohl
Copy link

liorwohl commented Nov 12, 2018

i'm also getting out of stack space in es5 build of my webcomponent, only in pages with large DOM, my polyfills.ts is different:
(i'm not using shadow-dom for the es5 build)

import 'core-js/es6/object';
import 'core-js/es6/array';
import 'unfetch/polyfill/index.js';
import 'classlist.js';
import '@webcomponents/custom-elements/custom-elements.min.js';
import '@webcomponents/custom-elements/src/native-shim.js';
import 'zone.js/dist/zone';

for simple short pages its working fine in IE11 and Edge.

@JeanRemiDelteil
Copy link

JeanRemiDelteil commented Nov 12, 2018

@liorwohl for now you should stick to previous working version:
"@webcomponents/webcomponentsjs": "=2.1.2",

@liorwohl
Copy link

@liorwohl for now you should stick to previous working version:
"@webcomponents/webcomponentsjs": "=2.1.2",

but im using this:
"@webcomponents/custom-elements": "1.2.1"

@LarsDenBakker
Copy link

LarsDenBakker commented Jan 27, 2019

For anyone running into this issue, we've created a language polyfills free webcomponent polyfills loader based on dynamic imports: https://open-wc.org/building/polyfills-loader.html

@JulianeH
Copy link

We had the same problem. In our case it worked once after deleting the cache. For us it worked to change the server cache settings.

@SetTrend
Copy link

SetTrend commented Apr 4, 2019

We're facing the same issue here. I'm not sure whether it is a webcomponentsjs issue or a Babel issue, so I filed the bug at Babel first: aurelia/cli#843 (comment)

@JeanRemiDelteil
Copy link

@JeanRemiDelteil We ran into the regression as well in our Polymer tests and this issue is on our radar. We are discussing potential solutions later this week and hope to have a working strategy next week.

@TimvdLippe Any news ? Since this issue is closed it may have disappear from the radars, but new functionalities keep getting added ('prepareAdoptedCssText' for ex.) but it's broken on IE11.

I'm pretty reluctant to drop full support of IE11, I have a minimum working state to maintain for accessibility.

At least update the readMe to remove compatibility with IE11 !

@TimvdLippe
Copy link
Contributor

At least update the readMe to remove compatibility with IE11 !

The polyfill works with IE11, however if you use a certain combination of polyfills together with this polyfill, it could break. Per our investigation, this is not so much of an issue of our polyfill per-se. However, we are shipping additional non-webcomponents polyfills currently that could potentially become problematic. For that improvement, please see #1007.

Note that you can already use the regular bundles as-is. You will only run into potential issues if you use the loader. If you are running into issues with the loader, I encourage you to check out https://open-wc.org/building/polyfills-loader.html

@JeanRemiDelteil
Copy link

I'm checking https://open-wc.org/building/polyfills-loader.html
it seems promising !

@JeanRemiDelteil
Copy link

The ideal development environment uses no tools, just an up-to-date browser and a simple HTTP server.

I just want to send these guys flowers

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

No branches or pull requests