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

[fix] hydration improvements #6449

Merged
merged 12 commits into from
Jul 21, 2021
Merged

Conversation

hbirler
Copy link
Contributor

@hbirler hbirler commented Jun 25, 2021

This PR tries to address some issues that were not addressed by #6395 and issues pointed out by @benmccann and @ankitstarski

  • An img element's src value should only be set if it is not the expected value. This check existed, but failed to account for relative paths which were returned as absolute paths when checking img.src.
  • Existing nodes under <head> that are not claimed but also not detached should be ignored by init_hydrate. These nodes have node.claim_order === undefined
  • The function claim_html_tag should also set claim_order.

Edit:

  • Add a fast path to init_hydrate for when most of the nodes are on the longest increasing subsequence.
  • Improve claims for text nodes: There are many cases where we try to only claim a prefix of the text node. In these cases, we can use splitText to actually only claim the prefix. (Merging text siblings might help further Optimise parsed AST #3766)

Edit2:

Potential issues:

  • Is it possible that location is overwritten at a local scope by the compiler? This would cause URL normalization to break.

@hbirler
Copy link
Contributor Author

hbirler commented Jun 25, 2021

@benmccann Does this fix the image flickering issue that you encountered by any chance? This time, I tried to normalize both sides of the equality.

@benmccann
Copy link
Member

It didn't help. I can't figure out what's causing it. It stops both if I turn off hydration and if I remove my global stylesheet. I can't find a line of code that's clearly causing it though, so I guess we should just ignore it for now. I'll let you know if I find anything else. I think you could probably revert the double URL normalization from 243c562 since it didn't help because it seems like extra code and CPU time without benefit

@hbirler
Copy link
Contributor Author

hbirler commented Jun 25, 2021

I added the double URL normalization because I couldn't find a proper spec that clearly mentions that reading the .src attribute should always return the full absolute URL. (Maybe I missed it)

I saw a mention here https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement
but not here https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/src
and also not here https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-src

@benmccann
Copy link
Member

Makes sense. I suppose I could see it working differently in different browsers in that case

@hbirler hbirler force-pushed the better-hydration-src branch 3 times, most recently from 73c5145 to 4521989 Compare June 27, 2021 05:56
@benmccann benmccann changed the title Fix & improve hydration [fix] hydration improvements Jun 30, 2021
@dummdidumm
Copy link
Member

Is it possible to add tests that would fail without these fixes?

@hbirler
Copy link
Contributor Author

hbirler commented Jul 1, 2021

@dummdidumm I believe hydration/head-meta-hydrate-duplicate as it is here fails in master and passes with this pull request. My modifying that test in #6395 was erroneous (I had assumed that the order of those nodes in head would not matter). This pull request reverts that test to how it was earlier.

@benmccann benmccann linked an issue Jul 7, 2021 that may be closed by this pull request
@benmccann
Copy link
Member

benmccann commented Jul 7, 2021

I tested that this fixes #6506, which reordered body content

@hbirler
Copy link
Contributor Author

hbirler commented Jul 7, 2021

@benmccann Interesting, but I don't understand how this PR would solve a body reordering issue. Does it involve claim_html_tag? (I likely won't have time to fully investigate on my own for the next couple of days.)

@benmccann
Copy link
Member

benmccann commented Jul 7, 2021

Ohh nevermind. I must have messed something up when testing earlier. That one appears to still be broken. Would you be able to take a look at it?

@benmccann benmccann removed a link to an issue Jul 7, 2021
Normalize src values before checking equality
Set `claim_order` in claim_html_tag
Normalize both sides of the equality to be sure
Do not create array from children if not needed
Split an existing text node if we match the prefix
@benmccann
Copy link
Member

@hbirler it looks like this PR will need to be rebased

@Conduitry
Copy link
Member

I'm a little concerned about using the URL API. Are there other places in Svelte itself (not in SvelteKit or Sapper) where we're using things that would need to be polyfilled on IE11? (Note that I'm specifically wondering about things that need to be polyfilled, and not things that need to be transpiled.)

Is there another way we could do this, like with a shared anchor element outside of the DOM that we set and check the href of?

@hbirler
Copy link
Contributor Author

hbirler commented Jul 8, 2021

@Conduitry do you mean something like the following:

const relative_to_absolute = (function() {
    var anchor = document.createElement('a');
    return function(url) {
        anchor.href = url;
        return anchor.href;
    }
})();

I used the URL API since I assumed it would be faster but I did not actually check whether it is.

@hbirler
Copy link
Contributor Author

hbirler commented Jul 8, 2021

Additionally Array.from seems to not be supported in IE11 and it is used in many places in the code. So it would need to be polyfilled.

@benmccann
Copy link
Member

I'm a bit concerned about the potential performance impact of mutating a DOM element everytime we want to do this check. It might be better to just manually construct the string using window.location in the case that we want to avoid using URL

@hbirler
Copy link
Contributor Author

hbirler commented Jul 8, 2021

@benmccann
Copy link
Member

But, as far as I'm aware, we don't need to fully canonicalize a URL. We just need to prepend the hostname when comparing to an a.href

@hbirler
Copy link
Contributor Author

hbirler commented Jul 8, 2021

Is it not possible that the relative URL looks like ../../image.png?

@benmccann
Copy link
Member

That still seems doable to handle. Another option might be to just remove that particular optimization if it's getting too complicated. I doubt that setting img.src is any more expensive than setting a.href to calculate if the URLs are the same. It didn't seem to be causing a second network request for the image. Or was it also causing the whole img tag and/or subsequent/previous tags to be reinserted?

@hbirler
Copy link
Contributor Author

hbirler commented Jul 8, 2021

I believe it was causing a visual flicker.

@hbirler
Copy link
Contributor Author

hbirler commented Jul 8, 2021

In a surprising turn of events, using the anchor seems to actually be faster https://jsbench.me/stkqvbw6qj/2

Use an anchor element's href attribute to convert relative paths to absolute paths
@benmccann
Copy link
Member

benmccann commented Jul 8, 2021

I can't argue with that!

@hbirler

This comment has been minimized.

@dominikg
Copy link
Member

dominikg commented Jul 9, 2021

@Conduitry do you mean something like the following:

const relative_to_absolute = (function() {
    var anchor = document.createElement('a');
    return function(url) {
        anchor.href = url;
        return anchor.href;
    }
})();

I used the URL API since I assumed it would be faster but I did not actually check whether it is.

Has this actually been tested in IE11 ? I remember some weird bug that assigning href with a relative path would not turn it into an absolute url. You had to explicitly assign it again like a.href = a.href before returning it.

@benmccann
Copy link
Member

There's not a huge impact if this doesn't work in IE11. They simply won't get the optimization. I don't think anyone would even notice. So I probably wouldn't let it hold up this PR

@hbirler
Copy link
Contributor Author

hbirler commented Jul 9, 2021

@dominikg The polyfill library seems to not need the trick you described for IE8+ https://github.com/Financial-Times/polyfill-library/blob/master/polyfills/URL/polyfill.js#L344
Maybe you would need that for IE6?

@dominikg
Copy link
Member

dominikg commented Jul 9, 2021

Maybe you would need that for IE6?

maybe. I remember it because it was a very strange thing way back when . Can't find references to it now and as Ben said if the worst thing that happens is IE users missing out on an optimization...

@Conduitry Conduitry merged commit ecbd96a into sveltejs:master Jul 21, 2021
@Conduitry
Copy link
Member

These have been released in 3.40.0 - thank you!

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

Successfully merging this pull request may close these issues.

None yet

5 participants