- 🇬🇧United Kingdom catch
@gapple we'd need to add a new interface with a new method, update the existing implementations to support both versions as well as the new system asset controllers.
- 🇬🇧United Kingdom catch
I was wondering what happens with this and big pipe.
The answer is that big pipe relies on the AJAX system, and the AJAX system does:
add_css(ajax, response, status) { if (typeof response.data === 'string') { Drupal.deprecationError({ message: 'Passing a string to the Drupal.ajax.add_css() method is deprecated in 10.1.0 and is removed from drupal:11.0.0. See https://www. drupal.org/node/3154948.', }); $('head').prepend(response.data); return; }
I wonder if we actually need to add the CSS to the HEAD of the document now that it can appear in the body? But also wonder what this means for FOUC, presumably we'd still want the new CSS file to be downloaded before the new HTML is rendered.
This makes me think about this solution in general. If we add js-style header and footer to library definitions, then this allows libraries to determine where they're loaded, but I don't think it's possible for the module to know what's going to be appropriate.
Instead maybe we want everything to work a bit more like BigPipe does:
For CSS that is specific to certain page elements, if it's always loaded via #attached or single directory components, then BigPipe kind of handles it because those CSS files will not be in the aggregates when the page is initially loaded, allowing the page to render faster not just because it's being streamed but because placeholdered content will load the CSS later too.
Then I looked at Renderer::renderPlaceholder(), and I think it might be possible to change that (or add a new placeholder strategy) that works similar to BigPipe - i.e. collect the assets from the placeholder, build any CSS aggregates right there and render them just before the markup, leave the JS handling as-is.
It would then be up to themes to rely on #attached to add CSS as much as possible to take advantage of this.
But this way:
- CSS for non-placeholdered elements and in the theme's .info.yml 'libraries' key goes in the head as now.
- CSS for placeholdered elements - rendered when the placeholder is. - 🇬🇧United Kingdom catch
To make #15 work we would need to track during the request which libraries have had their CSS rendered already, and then remove them from the libraries to render at the end of the request only for the CSS renderer. This would be a bit like ajaxPageState but it would have to be tracked separately because the JS still wants to be all together at the end of the page. Would need to happen in HtmlResponseAttachmentsProcessor::processAssetLibraries()
- 🇧🇪Belgium wim leers Ghent 🇧🇪🇪🇺
+1 for this.
#15 is already how BigPipe has always worked for no-JS BigPipe clients! 😄
This would be a bit like ajaxPageState but it would have to be tracked separately because the JS still wants to be all together at the end of the page.
Why would it be different for CSS than for JS?
- 🇬🇧United Kingdom catch
For js for anything that's not in the header, we already load it in the footer so that it's non-blocking. If we started progressively rendering (not sure what to call it, but using this instead of 'inline') JavaScript assets it would then block rendering again - so we should keep it in the footer as it currently is.
For CSS it is blocking and we currently render all of it in the header, so by progressively rendering some CSS as we go, we're making it less blocking.
My first idea here was to add the 'header/footer' concept to CSS, but I think adding the assets 'progressively' with the placeholders they're attached to is the way to avoid FOUC.
So for JavaScript header + footer is good, but for CSS header + progressive is good.
I haven't tried to make this work yet, but I think it might be able to look something like this:
All the fun is in HtmlResponseAttachmentsProcessor::processAttachments() and the rest of that class.
Before rendering placeholders, get the current set of libraries. This gets us all of the page-level CSS that needs to be in the header (even if it's also attached via a placeholder).
When we render placeholders, we get $assets from the rendered placeholder.
For CSS, we then prepend the CSS link tags to the markup, but we need to exclude the following:
1. ajax_page_state
2. Page-level libraries
3. Any other libraries already prepended to a different placeholder.Then when we render the page level CSS (in the place we already do that), we can just use what we got in the first place. For JavaScript we'll need to maintain an extra assets array, and this one gets all the placeholder libraries added to it as it currently does.
- 🇬🇧United Kingdom catch
I've just realised you might have meant essentially the opposite with #17.
We could send non-footer JS that's attached to a placeholder in the same way as CSS - that would then get it out of the header too, that would give us header + progressive + bottom JavaScript then.
- 🇬🇧United Kingdom catch
Just took me 10+ minutes to find this issue again, trying to make it a bit more searchable.