Feature #97652

f:asset.css and f:asset.script should be able to render CSS and JS from referenced files as block inline

Added by Jan Loderhose 3 months ago. Updated about 1 month ago.

Status:
New
Priority:
Should have
Assignee:
-
Category:
Fluid
Target version:
-
Start date:
2022-05-18
Due date:
% Done:

0%

Estimated time:
PHP Version:
Tags:
Complexity:
Sprint Focus:

Description

One essential aspect of professional SEO for high availability and high-performance online solutions is a fine-grained CSS and JS devilery tailored to the respective situation and persona of every single page view. The inline integration of critical CSS and JS is an indispensable measure for the optimal coordination of payload, round trips, render time etc. Offloading this optimization to HTTP/2 only does not even come close to the optimal solution. f:asset.css and f:asset.script contribute to this scaleability to a large extend by adding assets to the source only when the corresponding component is rendered! thumbs up

But it is currently not possible to integrate files with the ViewHelpers f:asset.css and f:asset.js and have their content output inline. Since both ViewHelpers are set to replace the integration of CSS and JS with TypoScript at some point (at least that is what I've read so far), this option must be created.

I know that it is possible to place CSS and JS as content directly within the ViewHelpers enclosing tags. But that is not an option for the development and maintenance of seriously meant projects. The strength of TYPO3 is its granularity and therefore the flexibility to compose dev teams of specialist for each aspect of the project. To keep this strength the freedom to leverage modern FE development concepts is essential. To copy and paste e.g. CSS resulting from a development pipeline into to a fluid template to have it rendered inline is not a modern development concept.

I therefore suggest giving the ViewHelpers f:asset.css and f:asset.js additional attributes to allow the following:

  • Include CSS files to render them inline as individual style blocks: critical="true"
  • Include CSS files to render them inline and concatenated as a single combined style block: critical="true" concatenate="true"
  • Include JS files to render them inline as individual script block: inline="true"
  • Include JS files to render them inline and concatenated as a single combined script block: inline="true" concatenate="true"

Since these features are essential to contemporary, professional FE development they should be part of the core rather than community extensions.


Files

f_asset-css-inline-and-external-poc.html (1.37 KB) f_asset-css-inline-and-external-poc.html Refer to multiple CSS files stored locally and external. Jan Loderhose, 2022-05-20 09:10
f_asset-css-single-inline-only-poc.html (1.23 KB) f_asset-css-single-inline-only-poc.html Refer to a CSS file and have its content rendern inline in the <head> one by one. Jan Loderhose, 2022-05-20 09:10
f_asset-css-concatenated-and-single-inline-only-poc.html (1.99 KB) f_asset-css-concatenated-and-single-inline-only-poc.html Refer to multiple CSS files and have their content rendered inline in the <head> combined to a single style block. Jan Loderhose, 2022-05-20 09:10
f_asset-js-concatenated-and-single-inline-only-poc.html (681 Bytes) f_asset-js-concatenated-and-single-inline-only-poc.html Refer to multiple JS files and have their content rendered inline combined to a single script block. Jan Loderhose, 2022-05-20 09:20
f_asset-js-single-inline-poc.html (697 Bytes) f_asset-js-single-inline-poc.html Refer to multiple js files and have their content rendered inline in the <head> combined to a single script block. Jan Loderhose, 2022-05-20 09:20
f_asset-js-inplace.html (858 Bytes) f_asset-js-inplace.html Include js and have it rendered at the position it is included wihtin the fluid template. Jan Loderhose, 2022-05-20 10:02
#1

Updated by Georg Ringer 3 months ago

thanks for creating the issue. Would it be possible for you to provide a proof of concept HTML output?

#2

Updated by Jan Loderhose 3 months ago

Hi Georg,

thank you for your quick reply! Sorry, my late. ;-)

I've prepared some poc files and attached them to this comment. That was a lucky request on your side because creating these examples revealed it least one further implication. Maybe it's best to have a look at the files first and afterwards continue with the

Priority conondrum

In file f_asset-css-concatenated-and-single-inline-only-poc.html I show how 4 CSS files are included. Three of them are concatenated. One of them has the priority attribute set to true. The result is that the three files are ordered by the order of their ViewHelper instances within the fluid template and the priority attribute and then their contents are concatenated and rendered in a single style block in the resulting order. A fourth file is not concatenated and therefore is simply rendered in a separate style block which is placed after the concatenated block.

What if the fourth file was included with priority="true", too?

We have a style block with the content of concatenated CSS files, one with priority="true". The priority brings the files rendered within one style block into the right order.
And we have a style block with the content of a single CSS file. Priority="true" currently means that it must be rendered first. But the concatenated style block contains prioritized CSS that should be first, too.

Well I did not find a plausible solution to that. In the comments within in the files I write that one goal should be to allow for the maximum possible flexibility. But to be true, I don't see a reason why multiple inline style blocks should be needed other than someone is not able to handle CSS properly. So maybe concatenation of critical (and therefore inline) CSS should simply be the default. Sort all critical CSS files according to their order and priority and put their contents in a single style blick. Voila. If one needs a separate inline style block, let this be done by an explicit concatenate="false" and let the developer see how he/she handles avoidable conflicts then. (My examples use explizit concatenate="true" but this topic is still subject to discussion so I think that's fine for now.)

A second aspect to have in mind is that people like to include external libraries just as they are delivered. Usually libraries are included first. This seems to make perfect sense but we are talking about inlining CSS because it is critical and is therefore needed asap to allow the browser to start the render process without the need to wait for additional requests for assets to complete. I show this in file f_asset-css-inline-and-external-poc.html. An external library that is needed to start the render process also needs to be inlined. Otherwise the whole concept does not make sense. But, what if an external CSS src is not available when it is requested. Waiting for seconds for a reply is no real option. After all, we are talking about speed an efficiency here. Maybe the critical attribute should not be available for the inclusion of external libraries.

So, always have the inline (cricital) CSS block render first. Every additional CSS inclusion comes after that. Libraries and what ever linked CSS.

Regarding JS: The thoughts concerning the priority and the need to have multiple script blocks are essentially the same. That's why I suggest to
  • collect all JS for the header and for the end of the body tag separately
  • per collection: order it by the order of inclusion and priority
  • per collection: render all inlined js in a single script block and all references to files afterwards.
But it is also valid to place inline script blocks anywhere in the HTML document. As far as I know that is not yet considered by f:asset.script. So ether leave it as it is and place JS in the head or before the closing body tag or add a further attribute like "inplace" which triggers rendering of the referenced JS right where it is placed within the fluid template. inplace can be used for
  • included external files,
  • inline JS which is written inline and
  • inlined content of js files.

If such an attribute will be added it should not be possible to combine it with the concatenate attribute (or it should implicitly set concatenate="false" if it will be true by default).

I suppose, if f:asset.css and f:asset.script would take all the above annotations into account they would provide an even better support for asset handling as TypoScript ever did. ;-)

What do you think? Does this make sense or did I miss something?

#3

Updated by Georg Ringer 3 months ago

thanks for the very detailed feedback! I am really not too much into the frontend process tbh but forge is not the right place to discuss things. what about using slack for that?

we can change everything, so just as an idea: if this is currently allowed to have external resources inlined we can throw an exception there because it doesn't make sense

#4

Updated by Jan Loderhose 3 months ago

yeah, let's switch to slack. which channel? We can also use DMs. My name on slack is the same as here.

#5

Updated by Frank Naegler about 1 month ago

I think the purpose of this ViewHelper is different from your use case.
The VH does not produce direct output, for this reason the VH does not need to be wrapped in an escaping node.
Also, the $escapeChildren is set to false, a possible security issue if the ViewHelper works in the described way.

The purpose is to collect inline code to get the body free of style and script tags.
Both are relevant scenarios for using the "content security policy" header in a helpfull way.

Changing the behavior of this ViewHelper is maybe not the best idea.
I can't see the benefits, but I would opt for a dedicated ViewHelper if this feature will be accepted.

Also available in: Atom PDF