Comments (23)
I think it's a WKWebView bug with something <paper-textarea>
is doing. It only happens when creating the element from document.createElement()
. It doesn't happen when the markup is parsed by the browser (that's why wrapping it works).
I'd actually recommend opening a bug on https://github.com/PolymerElements/paper-input. They can do more investigating to figure out why that error is thrown when creating a textarea programmatically.
There may not be anything the Polymer team can do with their element, but it'd be the starting point to create a bug with Apple and link details. Should also help raise awareness incase someone tries to use <paper-textarea>
with another framework like Angular that uses document.createElement()
.
from origami.
I have experience with UIWebView and WKWebView in the Angular 2 context, but not with Polymer.
I would assume UIWebView (the default for cordova-based projects) would have memory issues, but not WKWebView. If this is a cordova project I'd first do a sanity check and make sure the plugins you have to force WKWebView are working.
Next, are you serving ES6 or ES5-compiled in the web view, and are you using WeakMaps in your components? That's my first big warning flag with memory issues and ES6 since polyfilled WeakMaps are notorious for memory leaks.
If you're positive WKWebView is working and you don't have any obvious ES6-related memory leak areas like WeakMap, the next step I'd do is to take a JS memory profile of the WKWebView until you get the error and see what objects are eating up the memory.
I haven't heard of nor seen anything yet with Polymer or Angular and memory leaks, nor have I seen anything yet with Origami that could cause a leak. They are notoriously difficult bugs to find though...
from origami.
Thanks for the answer. It's not a cordova app but a normal web app, which gets called with wkwebview.
Just one question: what do you mean with "WeakMaps in your components"?
Are there different build options with polymer build to include or exclude these?
from origami.
The WeakMap is a type of Map in JavaScript that stores values by weak object reference instead of strings. That means when an object gets garbage collected, the WeakMap reference and value are also garbage collected.
Polyfills for a WeakMap have no way to do this natively, which results in a small memory leak on older browsers (or if the polyfill is being used instead of the native WeakMap). They're not a hidden feature or anything, you'd know if you were using them so I'm gonna guess they aren't the cause.
I think I'm a bit confused on how your web app is being called. Just through Safari or Chrome on iOS like a normal webpage? Or are you using a separate native app to view the webpage? What iOS version are you on?
from origami.
The app gets called in two separate ways:
- Like a normal web page through Google chrome
- Through our native iOS app with WkWebView
So our approach was to build only a native app for iOS to fill the gaps of the ServiceWorker (like to enable push notifications, offline support, etc.). Which Safari, obviously doesn't have but chrome does.
On Google chrome (all versions) the app works without issues. Still need to run the JS Profile though...
And on our Safari native app the web app crashes after approximately 5-7 seconds on interaction. So the process:
- The app loads within 3 seconds
- The user logs in
- The user starts using the app for about 5 seconds
- Total crash happens without error message. So screen just gets blank.
This is the browser version of WkWebView (verified with http://www.whoishostingthis.com/tools/user-agent/):
Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Mobile/14F89
So we're serving the Polymer ES6 bundled
directory. Generated like described in https://github.com/hotforfeature/origami/blob/master/docs/production-build.md. Because Safari 10 should be able to handle ES6.
The behavior can get reproduced with both WkWebView and native Safari.
I will test now the behavior with ES5...
from origami.
Update: We have identified that the root cause for the out of ram issue is this line of code:
@ViewChild('messageInput') private messageInput: ElementRef;
const targetElement = this.messageInput.nativeElement.shadowRoot.querySelector('#input').shadowRoot.querySelector('#textarea');
And targetElement
is null. Surprising thing is that this error only happens on safari iOS. @hotforfeature is there another way we need to access the shadow root on safari iOS?
from origami.
After some debugging we found out the following:
We wrote these debug statements:
const msgInputElem: any = this.messageInput.nativeElement;
var targetElement: any;
console.debug(msgInputElem);
console.debug(Polymer.dom);
console.debug(‘Polymer.dom(this.messageInput.nativeElement):‘);
console.debug(Polymer.dom(this.messageInput.nativeElement));
console.debug(‘Polymer.dom(this.messageInput.nativeElement).shadowRoot:‘);
console.debug(Polymer.dom(this.messageInput.nativeElement).shadowRoot);
// shadowRoot not supported by all browsers
if(this.messageInput.nativeElement.shadowRoot) {
targetElement = msgInputElem.shadowRoot.querySelector(‘#input’).shadowRoot.querySelector(‘#textarea’);
} else if (Polymer.dom(this.messageInput.nativeElement)) {
targetElement = Polymer.dom(this.messageInput.nativeElement);
console.debug(‘check’);
if(targetElement) {
console.debug(‘node.querySelector --> ‘);
const node = Polymer.dom(this.messageInput.nativeElement).node;
console.debug(node.querySelector);
const input = node.querySelector(‘#input’);
console.debug(‘input’);
console.debug(input);
console.debug(‘.querySelector(#textarea)‘);
console.debug(input.querySelector(‘#textarea’));
targetElement = input.querySelector(‘#textarea’);
console.debug(targetElement);
}
}
This code generates the following output:
What I have troubles understanding, is why console.debug(input);
results into null. But on safari desktop the above code works. So I thought it is maybe an angular/polymer issue on WkWebView?
from origami.
I'm still not entirely convinced WKWebView is being used here, since I would expect to see the word Safari/x
at the end of the user agent string after Mobile/14F89
. I would use this SO answer example to do some deeper checking and ensure WKWebView is being used.
Polymer.dom
should be deprecated for the most part. It really only serves as a legacy patch for Polymer 1.x/2.x elements that need to use Polymer.dom
for 1.x features. shadowRoot
is natively available on Safari and polyfilled when using webcomponentsjs. Can you add a line for console.log('shadowRoot', 'shadowRoot' in document.createElement('div'));
?
Finally, are you using webcomponentjs at all, and if so, are you using webcomponentsReady()
from Origami before bootstrapping in main.ts?
from origami.
Thanks again for your great support @hotforfeature. Here are my answers:
Running this code:
console.log(‘shadowRoot’, ‘shadowRoot’ in document.createElement(‘div’));
Gave the output: shadowRoot - true
Running this code:
if (navigator.platform.substr(0,2) === 'iP'){
//iOS (iPhone, iPod or iPad)
var lte9 = /constructor/i.test(window.HTMLElement);
var nav = window.navigator, ua = nav.userAgent, idb = !!window.indexedDB;
if (ua.indexOf('Safari') !== -1 && ua.indexOf('Version') !== -1 && !nav.standalone){
//Safari (WKWebView/Nitro since 6+)
console.log('Safari');
} else if ((!idb && lte9) || !window.statusbar.visible) {
//UIWebView
console.log('UIWebView');
} else if ((window.webkit && window.webkit.messageHandlers) || !lte9 || idb){
//WKWebView
console.log('WKWebView');
}
}
Gave the output "WKWebView". Additionally we ran the test on http://www.whoishostingthis.com/tools/user-agent/ again and got exactly the same: Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/603.2.4 (KHTML, like Gecko) Mobile/14F89
Tested with an hardware iPhone 5 with a WKWebView native app. I'm 110% sure that we are testing it with a WKWebView application.
Are you sure that shadow root is available in WKWebView
? Because accessing it with this.messageInput.nativeElement.shadowRoot
gives us null
. This is the reason we went back to using Polymer.dom
.
Yes we are using webcomponentjs: <script src="assets/bower_components/webcomponentsjs/webcomponents-loader.js"></script>
and we are listening for webcomponentsReady()
from Origami:
webcomponentsReady().then(() => {
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule, {
enableLegacyTemplate: false
}).then(() => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/worker-basic.min.js');
}
});
}).catch(error => {
// No WebComponent support and webcomponentsjs is not loaded
console.error(error);
});
from origami.
Got the idea to use Polymer.dom
from here: https://stackoverflow.com/questions/43937386/queryselector-not-working-in-shadow-dom-in-polymer-2
from origami.
iOS 10 WKWebView natively supports Shadow DOM, so yes you should be good to go.
shadowRoot
will be null if .attachShadow({ mode: 'open' })
hasn't been called yet. Perhaps that's where the problem lies.
Ahh, I see something I didn't catch in your screenshot:
I'm betting your element is defining attributes on itself via setAttribute()
in its constructor before the connectedCallback()
is called (attached()
in legacy Polymer). This is throwing an error, which stops the element from being instantiated and attachShadow()
from being called.
from origami.
Hmm, the thing is: It's not my element. It's a PolymerElement. This is what's behind @ViewChild('messageInput')
:
<paper-textarea #messageInput autocomplete="on" label="{{'chat.type' | translate}}" id="newMessage" class="form-control create-message-input"
name="newMessage" no-label-float max-rows="5" auto-validate="false" (keydown)="createMessageInputKeyPressed($event)"
(keypress)="createMessageInputKeyPressed($event)" formControlName="newMessage"></paper-textarea>
So I kinda doubt that google messed up the setAttribute()
method. Additionally we made sure that exactly this line is causing the error. So we commented out const targetElement = this.messageInput.nativeElement.shadowRoot.querySelector('#input').shadowRoot.querySelector('#textarea');
I'm working on a open repository now, where the error could get reproduced.
from origami.
OK, finished our experiments now. We ran the following tests:
- We generated a normal polymer project with Polymer starter kit and everything worked as excpected. So the error only comes up if angular (or origami) is included
- We created this minimal origami project: https://github.com/BorntraegerMarc/polymer-chat and the WKWebView crashes at the exact same component. Because of this: https://github.com/BorntraegerMarc/polymer-chat/blob/master/src/app/message/input/message-input.component.html#L3
- If you completely comment out the
paper-textarea
component from the HTML it works without issue. So the TS reference@ViewChild('messageInput')
has no influence on it. when we commented out@ViewChild
the same issue persisted. Ony when commenting out the HTML code the app started to work again.
For easy testing purposes we created the following iOS native app project: https://github.com/kmyllyvi/WKWebViewTester you can just clone & run it.
Which is just a WKWebView project. How to test:
- Clone and install the minimal origami project
- Clone and install the WKWebView project
- Start angular with ng serve
- Start the ios app project on an iPhone simulator and navigate to http://localhost:3000 (you can enter the URL in the actual app)
Maybe you see something @hotforfeature that I have missed?
from origami.
The issue can also be reproduced if you just generate a brand new angular project and add origami to it and then add the HTML line <paper-textarea label="test"></paper-textarea>
from origami.
Issue only is with paper-textarea. paper-input works perfectly
from origami.
Thanks for the details @BorntraegerMarc, I'll test it out as soon as I can
from origami.
Thx
from origami.
The prognosis does not look good. I tried stripping everything (including Origami and polyfills) from the demo app. The only thing I couldn't take out was the reflect shim and zone.js.
The Problem
Adding the <paper-textarea>
to index.html
was fine, but the DefaultDomRenderer2
could not create it without throwing the error "A newly constructed custom element must not have attributes".
This is the cause for things breaking. While document.createElement()
lets you continue, the element it returns is actually an HTMLUnknownElement
, and so naturally it doesn't open its Shadow DOM from extending Polymer.Element
.
Raw vs Programmatic Element Creation
There are two ways to "create" an element: raw HTML and programatically. A Polymer project goes through raw HTML. It provides it directly to the browser to render.
Angular does things programmatically and calls document.createElement()
. This is why you can do weird things like <paper-item class$="[[binding]]">
in Polymer but not Angular. class$
is not a valid attribute and throws an error when calling element.setAttribute('class$', '[[binding]]')
.
Not Just Angular!
So far, all the tests have just been isolated on <paper-textarea>
. I'm testing with both this element and <paper-input>
, since they're similar. <paper-input>
is perfectly chill with document.createElement()
.
I've ruled out Origami as the problem, so I thought maybe something with zone.js or the reflect shim was adding attributes at element creation. I decided to turn to pure Polymer and take both of these and any other weird Angular shenanigans out of the picture.
This is the demo file that we should navigate to within the WKWebView. It'll load up just fine and <paper-textarea>
works. Inspect the console and run the following:
window.onerror = function(err) { debugger; console.log('error', err) };
var ele = document.createElement('paper-textarea');
console.log(ele instanceof HTMLUnknownElement);
console.log(ele instanceof customElements.get('paper-textarea'));
Output:
[Log] error – "NotSupportedError (DOM Exception 9): A newly constructed custom element must not have attributes"
[Error] NotSupportedError (DOM Exception 9): A newly constructed custom element must not have attributes
createElement
Console Evaluation (Console Evaluation 4:3)
evaluateWithScopeExtension
_evaluateOn
_evaluateAndWrap
evaluate
[Log] true
[Log] false
Thoughts
So, good news and bad news. This isn't a bug with Origami or Angular (hooray!). Bad news is this may be some sort of bug with WKWebView. Neither Safari nor Chrome report these attribute errors, nor do I see anything in <paper-textarea>
that is doing something wrong.
I'm curious if this is a problem with the word "textarea". Maybe WKWebView sees that and is adding some textarea-specific attributes when it shouldn't be. I would take the next steps:
- Copy and paste paper-textarea's source and give it a new selector without the word "textarea" in it. See if that's the cause of pain.
- Create a new Polymer element that wraps paper-textarea. Since that Polymer element is "raw HTML", it can bypass
document.createElement()
.
One of those two solutions may get paper-textarea working for you on WKWebView. If not, well you can always file a bug with Apple.. but good luck there :(
from origami.
Thanks for looking at this @hotforfeature. I'm gonna close the issue since it is not an issue with origami. But will update this issue as soon as we have tried out your suggestions.
from origami.
@hotforfeature OK, so I've tried renaming the element to paper-marci
and the exact same error is happening. Here the code: https://github.com/BorntraegerMarc/paper-input
So your first suggestion
Copy and paste paper-textarea's source and give it a new selector without the word "textarea" in it. See if that's the cause of pain.
And couldn't even move to the second suggestion. My next step would be to file a bug with apple. Unless you got any more insights from my test?
from origami.
When I'm talking about wrapping, I mean to create a small element such as this:
<dom-module id="paper-wrapped">
<template>
<paper-textarea value="{{value}}"></paper-textarea>
</template>
<script>
Polymer({
is: 'paper-wrapped',
properties: {
value: {
type: String,
notify: true
}
}
});
</script>
</dom-module>
Then try using <paper-wrapped>
in Angular instead of <paper-textarea>
. If it works, then you'll need to add additional input properties that you need to bind from Angular to the wrapped textarea.
The reason this might work is because the wrapper element's template (and <paper-textarea>
element) is consumed all at once by the document instead of programmatically created by Angular.
from origami.
Heck, that did it @hotforfeature It fully works now
means, it is a weird WKWebView / angular bug?
from origami.
@hotforfeature FYI: if you wrap the component with all attributes, it still does not work. The property autocorrect
seems to be causing the problem. Only if you remove that one property in the wrapped component it seems to work. (you don't even need to use the attribute in your element. It's already enough to provoke the crash if autocorrect
is defined as an attribute)
from origami.
Related Issues (20)
- Failed to compile entry-point @codebakery/origami/styles (module as esm5) due to compilation errors HOT 2
- paper-input-container attach causes "Cannot read property 'addEventListener' of null" HOT 1
- Angular 13 @angular/common Could not resolve dependency HOT 3
- PolymerChanges doesn't exist HOT 1
- Allow project root, app root, and .bowerrc directories for polymer-webpack-loader HOT 9
- Support for embedded media in Polymer elements ? HOT 2
- Unit Tests HOT 3
- Any way to run this with Angular 6? HOT 5
- Instead of `path-cli`, couldn't we use `ng eject` istead? HOT 4
- Docs: Zone.js doesn't play nice with webcomponents HOT 3
- How to use two-way databinding with vaadin-grid-filter for vaadin-grid? HOT 7
- Polyfill utilities throws "TypeError: Cannot read property 'toLowerCase' of undefined" HOT 7
- Dynamic/defer importing the AppModule makes the app failed to compile HOT 4
- IncludeStylesModule expects RouterModule to be imported. HOT 3
- Update for Angular 7 support HOT 5
- @IncludeStyles does not work on non-root component HOT 13
- Latest version 3.1.1 causes ERROR ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor HOT 4
- routerLink within <template> HOT 1
- Origami prepare command throwing error with Polymer v3.3.1 HOT 2
- Angular 9 and ivy HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from origami.