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

Behavior of blocking attribute on a preload link #7896

Closed
noamr opened this issue May 6, 2022 · 7 comments · Fixed by #7935
Closed

Behavior of blocking attribute on a preload link #7896

noamr opened this issue May 6, 2022 · 7 comments · Fixed by #7935

Comments

@noamr
Copy link
Contributor

noamr commented May 6, 2022

According to the spec, a <link rel=preload blocking=render /> would block rendering until the resource is fetched.
This behavior seems a bit off, or in other words I have doubts about it.

If taken as specified, this could lead to a FOUC - as the time between the response arrives and the font is loaded / style is parsed / script is executed is not render-blocked.

It can create strange situations, e.g. with <link rel=preload render=blocking as=script /> and a corresponding <script> without a blocking keyword. Should it or should it not block? Should it block while fetching the preload but not while executing the script? If it blocks until the script is executed, what if it's not executed at all?

OTOH, when evaluating scripts/styles, their subresources (imported scripts/styles) are already implicitly render-blocking. So re-defining them as render-blocking in the preload is redundant.

I suggest that preloads should not be render-blocking at all, and instead to allow render-blocking on particular type of resources that cannot currently do that, like fonts. Maybe:

@font-face {
  font-family: "Some external font";
  blocking: render;
}

This would also make the render-blocking part of the style's content, rather than an external side-effect of one of its headers, which would require web developers to juggle between CSS authoring and backend configuration of HTTP headers.

If we want this to affect the fetch priority, it could be something like:

<link rel=preload as=script href=script.js fetchpriority="render-blocking" />
<script blocking=render src="script.js">

Specify the blocking for the preload as a priority, but not block the rendering indefinitely if the resource is loaded but not used.

WDYT? @xiaochengh @yoavweiss

@xiaochengh
Copy link
Contributor

If taken as specified, this could lead to a FOUC - as the time between the response arrives and the font is loaded / style is parsed / script is executed is not render-blocked.

For font, I don't fully understand this. What's the different between "the response arrives" and "the font is loaded"?

For style / script, this is not true if it's in the document head, because the document is always render-blocked before body is inserted (and can be blocked for longer after that). And if it's in the document body, then it's pretty much the same as having an inline style / script in the document body -- a flash/shift/... should be expected.

I agree that it may seem a bit redundant to use it on style/script resources. But I don't see a reason why we should ban them. Render-blocking preloads are mostly motivated by resources that are by default non-render-blocking.

I've also proposed adding render-blocking a @font-face before (w3c/csswg-drafts#5924) and it was discouraged, while an explicitly preload seems more desireable (@tabatkins)

... but not block the rendering indefinitely if the resource is loaded but not used.

This won't happen. For preloads, rendering is unblocked when the resource is loaded, not when it's used.

@noamr
Copy link
Contributor Author

noamr commented May 7, 2022

If taken as specified, this could lead to a FOUC - as the time between the response arrives and the font is loaded / style is parsed / script is executed is not render-blocked.

For font, I don't fully understand this. What's the different between "the response arrives" and "the font is loaded"?

The time where the response is processed and turned into an actual font can happen after the response arrived, not necessarily synchronously.

For style / script, this is not true if it's in the document head, because the document is always render-blocked before body is inserted (and can be blocked for longer after that). And if it's in the document body, then it's pretty much the same as having an inline style / script in the document body -- a flash/shift/... should be expected.

OK, but in this case, how did render-blocking the preload helped? It had no effect... if the script is anyway render-blocking it remains render-blocking and vice versa. The only thing the blocking-preload would do is shift the FOUC around to a different point in time, potentially shorter.

I agree that it may seem a bit redundant to use it on style/script resources. But I don't see a reason why we should ban them. Render-blocking preloads are mostly motivated by resources that are by default non-render-blocking.

I've also proposed adding render-blocking a @font-face before (w3c/csswg-drafts#5924) and it was discouraged, while an explicitly preload seems more desireable (@tabatkins)

I'll read and comment on that one, thanks for the pointer.
I believe that render-blocking as a network-layer feature is a strange decision and can lead to those gaps between fetching and rendering where the developer would think that there should be a render-block but the behavior would be not so explicit.

... but not block the rendering indefinitely if the resource is loaded but not used.

This won't happen. For preloads, rendering is unblocked when the resource is loaded, not when it's used.

Right, hence there would be a potential FOUC gap.
If the resource is used early - it should state it is render blocking and preload doesn't add any new information. (Provided styles/fonts/images/scripts can provide that information)

If the resource is used late - and you unblock on response -
the time between the response and the consumption is a FOUC gap.

The logic here is that rendering is not a direct result of the loading chain, but rather an effect that may happen later, potentially asynchronously. So tying something render-related to the fetching process is racy.

@xiaochengh
Copy link
Contributor

Thanks for finding out this issue.

I've discussed this issue within the Chrome team, and we agreed that render-blocking preload is a problematic idea. We've decided to:

  • Remove blocking=render from <link rel=preload>
  • Keep blocking=render as is on <script>, <style> and <link rel=stylesheet>
  • Propose something in CSS to turn a web font render-blocking
  • Propose a general JS API to block & unblock rendering, so that we can support e.g. images (which typically appear in body and hence shouldn't have blocking=render)

Question: How about <link rel=modulepreload>? It doesn't seem to have issues pointed out here, so I think we also keep it as is?

@noamr
Copy link
Contributor Author

noamr commented May 12, 2022

Thanks for finding out this issue.

I've discussed this issue within the Chrome team, and we agreed that render-blocking preload is a problematic idea. We've decided to:

  • Remove blocking=render from <link rel=preload>
  • Keep blocking=render as is on <script>, <style> and <link rel=stylesheet>
  • Propose something in CSS to turn a web font render-blocking
  • Propose a general JS API to block & unblock rendering, so that we can support e.g. images (which typically appear in body and hence shouldn't have blocking=render)

I think those are good moves! Thank you.

Question: How about <link rel=modulepreload>? It doesn't seem to have issues pointed out here, so I think we also keep it as is?

I think it has the same issues as <link rel=preload as=script>. There could be a gap after preloading the module and depednencies, and before the module is imported and evaluated.

@xiaochengh
Copy link
Contributor

xiaochengh commented May 13, 2022

Is there any procedure needed to remove blocking=render from preloads? Or do I just upload a PR?

cc @domenic

@noamr
Copy link
Contributor Author

noamr commented May 14, 2022

Is there any procedure needed to remove blocking=render from preloads? Or do I just upload a PR?

cc @domenic

Mainly upload an HTML PR and make sure the WPTs are up to date.

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 16, 2022
…oad links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 19, 2022
…oad links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
aarongable pushed a commit to chromium/chromium that referenced this issue May 19, 2022
…oad links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3648301
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1005447}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 19, 2022
…oad links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3648301
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1005447}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue May 19, 2022
…oad links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3648301
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1005447}
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue May 24, 2022
…` from preload and modulepreload links, a=testonly

Automatic update from web-platform-tests
[renderblocking] Remove `blocking=render` from preload and modulepreload links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3648301
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1005447}

--

wpt-commits: 5f3c4872a168e983f9310845ce739ef8e356584f
wpt-pr: 34083
jamienicol pushed a commit to jamienicol/gecko that referenced this issue May 25, 2022
…` from preload and modulepreload links, a=testonly

Automatic update from web-platform-tests
[renderblocking] Remove `blocking=render` from preload and modulepreload links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3648301
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1005447}

--

wpt-commits: 5f3c4872a168e983f9310845ce739ef8e356584f
wpt-pr: 34083
mfreed7 pushed a commit to mfreed7/html that referenced this issue Jun 3, 2022
mjfroman pushed a commit to mjfroman/moz-libwebrtc-third-party that referenced this issue Oct 14, 2022
…oad links

... following the discussion in whatwg/html#7896

Bug: 1271296
Change-Id: I2ac45f4697810350170d217a7b8d16880e6b89a9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3648301
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
Auto-Submit: Xiaocheng Hu <xiaochengh@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1005447}
NOKEYCHECK=True
GitOrigin-RevId: 1372f2379a46b86177b5537b5be77a00c83c6bda
@bakura10
Copy link

Hi,

I would like to re-open this, as I think render blocking on preload can be useful. When using declarative shadow DOM, loading a stylesheet currently have two different behaviors:

  • It is blocking on Chrome
  • It is non-blocking on Safari

I'm waiting to check Firefox implementation. I have raised this issue here: #9232 and it seems that Chrome might be the incorrect implementation.

I would prefer for stylesheet to be blocking, as otherwise the following will cause FOUC, which in my opinion defeat the purpose of declarative shadow DOM:

<template shadowrootmode="open">
  <link rel="stylesheet" href="stylesheet.css">
</template>

If the spec is clarified and Safari behavior is adopted, this means we need to have a way to block the rendering in this context, so we would need to have this and this to be blocking:

<link rel="preload" render="blocking" href="stylesheet.css" as="stylesheet">

<template shadowrootmode="open">
  <link rel="stylesheet" href="stylesheet.css">
</template>

In this context we cannot remove the preload as otherwise the styles would leak into the main document and no longer be scoped to the Shadow DOM (while the preload allows to ensure it is just downloaded but not executed).

Honestly, I would prefer the declarative shadow dom spec to be clarified and be blocking, but I wanted to raise this use case as I feel it is an important one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

3 participants