-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
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: don't duplicate styles with dynamic import (fix #9967) #9970
Conversation
@patak-dev This is ready for review :) |
I don't think we should modify the way paths work when the base is not relative. You can think about it as an optimization, and there may already be plugins that expect a certain pattern for Vite preload paths. The bug only appears for relative base, so let's fix it for it. |
@patak-dev ready for next round :)
|
@Tal500 @patak-dev I added test from this PR on top of Tal500's work here https://github.com/bgoscinski/vite/tree/preload-on-system-format-with-9967-test. Unfortunately the test fails :( |
Hi! As I said in my comment on you code review, I know that my code isn't perfect (intentionally, because of failing CI) on avoiding duplicated CSS. The review I sent you was not related to the fact I fail to avoid some duplication. |
@Tal500 Ahhhh I see! I assumed that your PR is a "superset" of mine and it fixes the bug. That's why I ported my test to your PR :) In this case I'll borrow the trick with the CSS selector :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
@patak-dev ready for next pass :) I don't know why CI failed on MacOS but I think this is some kind of a flakiness issue. Changes summary:
Addressed. Please see
As I pointed out here and demonstrated here
I run my project with Vite built from this branch and bug is gone so I think we're good. |
Don't you think that the best, simple thing is to always compare their absolute URLs, no matter what the configuration is? |
That's what I initially implemented but @patak-dev suggested to postpone it at least until Vite 4 |
@@ -75,10 +83,17 @@ function preload( | |||
seen[dep] = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just an idea but maybe we could simplify the logic if we use new URL(dep, document.baseURI).href
. If the SSR markup used an absolute path, I guess the current approach won't work. (it didn't work from before though)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that was what I missed! To supply the base url!
Earlier I used new URL(dep).href
that didn't make sense when dep is relative, just understand it now, according to MDN about the constructor signature new URL(url, base)
:
If
url
is a relative URL,base
is required, and will be used as the base URL. Ifurl
is an absolute URL, a givenbase
will be ignored.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just an idea but maybe we could simplify the logic if we use
new URL(dep, document.baseURI).href
. If the SSR markup used an absolute path, I guess the current approach won't work. (it didn't work from before though)
NOOOOOOO! BaseURI isn't supported on IE11!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just an idea but maybe we could simplify the logic if we use
new URL(dep, document.baseURI).href
. If the SSR markup used an absolute path, I guess the current approach won't work. (it didn't work from before though)NOOOOOOO! BaseURI isn't supported on IE11!
OK, since this PR doesn't introduce legacy support, I think it's fine to use BaseURI.
It seems that a correct place to handle this issue is at my PR #9920, since right now the preload function isn't called for legacy browsers.
Therefore, @bgoscinski, you may ignore the rest of this comment, I'll handle with it after in my PR.
The full solution was introduced in sapper legacy support, on PR sveltejs/sapper#1562.
I'll explain briefly the logic of this sapper PR, how it handle the situation when document.baseURI
isn't available:
We could have used the document.URL
which is supported by IE11. Sadly, due to the reasons in this stackoverflow answer, if there is some <base>
element in the DOM, it changes the base path, ignoring the current URL(demo is included in the stackoverflow answer). Luckily, by the specifications, there could be only one at most such <base>
element, so we just need to grab the one we see, and take this to be the baseURI. If no such tag were found, we can simply take document.URL
instead.
@sapphi-red Ready for next round. I fixed the bug with Aaaand macos build&test failed again... Do you have an idea what might be the cause? /cc @patak-dev @Tal500 |
BTW: Too bad you always squash&force-push the commits to the PR branch. I think it's better for history and the conversation to not do this. Don't worry, when the Vite team merge the PR, it will be squashed, as you can see in the contributing guidelines:
|
const isBaseRelative = !!importerUrl | ||
|
||
// check if the file is already preloaded by SSR markup | ||
if (isBaseRelative) { | ||
// When isBaseRelative is true then we have `importerUrl` and `dep` is | ||
// already converted to an absolute URL by the `assetsURL` function | ||
for (let i = links.length - 1; i >= 0; i--) { | ||
const link = links[i] | ||
// The `links[i].href` is an absolute URL thanks to browser doing the work | ||
// for us. See https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:idl-domstring-5 | ||
if (link.href === dep && (!isCss || link.rel === 'stylesheet')) { | ||
return | ||
} | ||
} | ||
} else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe @sapphi-red suggestion here was to do my initial thought, just in a way that actually fix my issue?
As far as I can tell, it omits the if (isBaseRelative)
, and the suggestion is to do this:
const isBaseRelative = !!importerUrl | |
// check if the file is already preloaded by SSR markup | |
if (isBaseRelative) { | |
// When isBaseRelative is true then we have `importerUrl` and `dep` is | |
// already converted to an absolute URL by the `assetsURL` function | |
for (let i = links.length - 1; i >= 0; i--) { | |
const link = links[i] | |
// The `links[i].href` is an absolute URL thanks to browser doing the work | |
// for us. See https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:idl-domstring-5 | |
if (link.href === dep && (!isCss || link.rel === 'stylesheet')) { | |
return | |
} | |
} | |
} else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) { | |
return | |
} | |
const absoluteDep = new URL(dep, document.baseURI).href; | |
for (let i = links.length - 1; i >= 0; i--) { | |
const link = links[i] | |
// The `links[i].href` is an absolute URL thanks to browser doing the work | |
// for us. See https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes:idl-domstring-5 | |
if (link.href === absoluteDep && (!isCss || link.rel === 'stylesheet')) { | |
return | |
} | |
} |
I figured that out some time ago . |
Thanks!
When an HTML rendered by server used an absolute path for CSS, the CSS will be duplicated. For example, when <html>
<head>
<link rel="stylesheet" href="https://example.com/assets/foo.hash.css">
<script type="module" src="https://example.com/assets/index.hash.js"></script>
</head>
</html>
My idea is basically same to #9970 (comment). (I guess we could use
It's a related to the original bug, but this one isn't a bug caused by this PR. So this could be fixed in a different PR. It's not blocking this PR. |
@sapphi-red Thanks for clarifying! What else is needed from my side to get this PR ready to merge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! LGTM
The reason is that it's already fixed by vitejs#9970, and we want to make this PR independent.
Description
Fixes #9967 by normalizing asset URLs to full absolute URLs with origin and comparing them to
link.href
properties of all links in the document to find duplicates.Additional context
What is the purpose of this pull request?
Before submitting the PR, please make sure you do the following
fixes #123
).