Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Exception in Safari mobile and desktop versions #92

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

Closed
yuretz opened this issue Jun 4, 2020 · 11 comments
Closed

Exception in Safari mobile and desktop versions #92

yuretz opened this issue Jun 4, 2020 · 11 comments

Comments

@yuretz
Copy link

yuretz commented Jun 4, 2020

I've got a weird exception that I'm only able to reproduce on Safari, both mobile on iPhone XS iOS 13, and desktop version on MacOS Catalina Safari 13.1

I originally discovered this issue on lighterhtml version is 2.1.0, but can also reproduce it on the latest 3.1.3

Unfortunately I don't have any minimal example code to show, because I'm still working on isolating it and figuring out what's going on, but I'll definitely try create an example, once I learn more about the issue.

What I know now is that exception is provoked by client-side navigation action (navigation between different pages of my app). Here is the stack trace

NotFoundError: The object cannot be found here

	insertBefore
	append (utils.js:23)
	domdiff (index.js:80)
	anyContent (tagger.js:267:83)
	(anonymous function) (index.js:119)
	unroll (index.js:162)
	retrieve (index.js:124)
	unrollArray (index.js:182)
	unroll (index.js:154)
	unrollArray (index.js:172)
	unroll (index.js:154)
	unrollArray (index.js:172)
	unroll (index.js:154)
	unrollArray (index.js:172)
	unroll (index.js:154)
	retrieve (index.js:124)
	render (index.js:63)
	dispatch (redux.js:230)
	(anonymous function) (redux-logger.js:1:7723)
	_loop (router.service.ts:563)
	process (router.service.ts:573)
	process
	goTo (router.service.ts:471)
	next (section-content.view.ts:182)

I'm also attaching a screenshot of Safari debugger stopped on the exception, just in case it could be useful.
safari_src

I would be very grateful for any help/hints/suggestions regarding how to solve this issue.

@yuretz
Copy link
Author

yuretz commented Jun 6, 2020

OK, I have now invested significant time hunting this problem down and know much more about it.

First of all, it's not Safari-specific, Safari is just the quickest to fail. I have been able to reproduce the same issue on Chrome, with the message DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node. and a very similar stacktrace.

Second, I have found the most likely culprit, and this is a component that looks something like

const list = (items) => html`${items.map(item)}`;

where item() is a list item component. So, what happens is that sometimes, when the whole list() is being replaced by another component, as a part of normal render(), not all item() elements are removed from the DOM, and that's what's causing problems.
The workaround that works for me looks like

const list = (items) => html`<div>${items.map(item)}</div>`;

and I don't know enough about lighterhtml internals to come with a good explanation about why it works, might have something to do with diffing algorithm.

Third, extracting a minimal reproduction example proved to be more complicated than I expected. Though I have managed to reduce the failing code area to the bare minimum, I still cannot make analogous code fail like this on jsfiddle/codepen. I was even suspecting babel transpilation issues being the problem, but it doesn't seem so. Well, maybe I'll use more time on it some time later and remove the rest of business-sensitive parts from the app, so that I'm able to share it in its original form. Though I'm not sure @WebReflection will be willing to look at it at all, since it's in TypeScript. ¯\_(ツ)_/¯

@WebReflection
Copy link
Owner

sorry I've not payed enough attention to this yet, and yes, the fact you have .ts files in the stack didn't really make me pay attention ... you think it's Babel, I wouldn't be surprised if it's a TS shenanigan.

There's no logical difference (or there shouldn't be) between html<div>${items.map(item)}</div> and html${items.map(item)}, both populate based on a comment in a node.

What you could try though, is to use a keyed approach, via html.for(reference[, id]) either in the outer html call, or within the item callback.

@yuretz
Copy link
Author

yuretz commented Jun 6, 2020

Of course! Now I've got it outside my app!

You are absolutely right, it seems to be related to TypeScript transpilation somehow. Here is a failing example with TypeScript transpilation, and here is the same code working fine with Babel. To see the issue just click 'next' three or more times and then 'back' again. Radio button should be visible only on the second view.

I still don't understand how I'm able to have this issue, since I'm using @babel/plugin-transform-typescript, which should be only stripping type annotations and pass the resulting javascript through Babel anyway. Well, I was probably wrong about it, need to figure out how to force it doing it this way anyway.

@yuretz
Copy link
Author

yuretz commented Jun 7, 2020

So, it seems like TypeScript fallback is the source of the problem and difference in the behavior between babel-transpiled and typescript-transpiled code. To prove it, I just took the TS transpilation result that originally fails, and fixed the template literal function to freeze the raw property to fool the TS detection inside lighterhtml, and boom - it now works!

@WebReflection
Copy link
Owner

which version of TS are you using and why on earth TS hasn't fixed its transpilation problems?

I have wasted so much time behind their errors and people keep blaming my libraries for their, non standard, transpilation issues ... this is so annoying!

@WebReflection
Copy link
Owner

and btw, that part of the code is here:
https://github.com/ungap/template-literal

there are also tests in there, maybe we can fix it there so that all libraries using it will fix the issue too.

Closing this one, as there's nothing I should do in here.

P.S. uhtml wouldn't suffer any issue as it doesn't normalize anything, it's "your" responsibility to transpile stuff properly ;-)

@yuretz
Copy link
Author

yuretz commented Jun 8, 2020

which version of TS are you using and why on earth TS hasn't fixed its transpilation problems?

I'm using typescript 3.8.3, which is one version below the latest, meaning fairly fresh, but as I mentioned before, the typescript version should be not too relevant, because the transpilation is done by babel (via typescript transform) and the resulting code looks very much the same to how babel transpiles corresponding ESNext code. At least all template objects are unique and frozen :)
It also seems, that there is a minor difference somewhere, that makes lighterhtml (or ungap/template-literal) use a TS fall back but I haven't had time to investigate the exact reason yet.

there are also tests in there, maybe we can fix it there so that all libraries using it will fix the issue too.

I think that this is a good idea.

To poke it a little more, I have tried one more thing: I've taken the Babel-transpiled code and removed the feezing on template objects, and guess what - it started failing in exactly the same way I observed in TS code. I suspect the forewerCache might be problematic maybe?

Anyways, if you share my opinion that this is a bug worth fixing, I can open a new issue in ungap/template-literal repo. I'm also willing to help you with testing/investigating it, but a bit later (closer to the weekend). What do you say about that?

P.S. uhtml wouldn't suffer any issue as it doesn't normalize anything, it's "your" responsibility to transpile stuff properly ;-)

Well, the current project is already in the late stage and is a bit too critical to change the view-rendering library right now, but I'll definitely consider this possibility in the future. I like minimalistic, unopinionated and close-to-standard solutions very much, that's the primary reason for me to use your libraries after all :) So yes, uhtml is on the radar.

@WebReflection
Copy link
Owner

What do you say about that?

Yes please! I've created the issue ungap/template-literal#10 and my last question would be: which version of Babel are you using? Version 6 had gotchas, but version 7 should be just fine. Maybe it's relevant.

@yuretz
Copy link
Author

yuretz commented Jun 9, 2020

It's 7.10.1 (@babel/core 7.10.1)

@yuretz
Copy link
Author

yuretz commented Jun 13, 2020

I have further simplified my bug reproduction example. Just run it and push 'next' button until you get to the last view. Works fine in Chrome, crashes after second click both in Safari and in Firefox. No transpilers involved.

@WebReflection
Copy link
Owner

As I'm tired of fixing 3rd parts issues, this will get fixed with the next major release of lighterhtml, which is v4 #93

tests need to be done, but I'll leave developers decide what to do with their transpilers, hoping TypeScript will fix their issues at some point.

thanks for helping out reproducing the issue 👋

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

No branches or pull requests

2 participants