-
Notifications
You must be signed in to change notification settings - Fork 111
Methods for inserting HTML should be exposed on OD_Template_Optimization_Context
for before or after all tags have been visited
#1931
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
Comments
@westonruter Thanks for opening this, and for the detailed description. I like having methods for specific use-cases rather than allowing any HTML. Not only does this prevent problematic usage, but it also encourages extensions to use these new methods where possible, rather than continuing to use the tag visitor context's tag processor's broader (but therefore also more complicated-to-use) HTML insertion methods. Some additional thoughts and questions:
Curious to get your thoughts. |
Thinking about this some more, I think we can actually be a bit more opinionated about where the HTML is inserted. For example, For example, when inserting a script module, it should always be appended to the
There's no need to be able to specify performance/plugins/image-prioritizer/class-image-prioritizer-video-tag-visitor.php Line 244 in 26442b9
Line 237 in 26442b9
And there aren't any needs so far to insert a non-module script, so perhaps we just not consider these for now. For
But we can just go with the first for now.
That said, there is the
Yeah, that makes sense to me.
Yes, this is what I was getting at with what I quoted above from #1546. The one hiccup here is that in the context of the tag visitor, all of the methods on
However, none of these should be exposed on So I think we'd continue to provide
What
Or these methods could be defined right on
I think the above handles all the cases currently identified for extensions. Optimization Detective itself would need to be able to insert raw HTML, of course, to be able to insert the |
As part of this, the optimization loop should directly have access to <meta data-od-replaced-content="optimization-detective 0.0.0" name="generator" content="optimization-detective 0.0.0; url_metric_groups={0: empty, 480: empty, 600: empty, 782: empty}"> When it should instead output: <meta name="generator" content="optimization-detective 0.0.0; url_metric_groups={0: empty, 480: empty, 600: empty, 782: empty}"> The OD meta attributes are intended for tag visitors to show what changes they made on the document. |
I like that idea, let's start with being opinionated and only supporting script modules, not regular scripts. We could always add support for the latter later, if there proves to be a need.
+1, I think the keyframes requirement is too specific to consider for now. Also, AMP requiring it doesn't necessarily make a compelling argument for supporting it here, since it's neither officially supported by Core nor a standard of some kind.
Wouldn't that only allow for external stylesheets? In any case, even if we use
I was thinking that the new class would only be responsible for writing/adding stuff to the HTML output, not reading. I think (at least for now), the tag visitor context could maintain access to the
Per what I answered above, I think this is worth thinking about, but I think as part of this issue we should limit the scope to focusing on the write interactions only via the new class.
See my previous reply, that's roughly what I meant for the new class to have as scope.
👍 |
That's right, it would just be for external stylesheets. But considering that one performance pattern is to put stylesheets in the footer (e.g. if they are intended to not be blocking) then this doesn't really fit with
If they had access to the |
Sounds good.
Sounds good. So basically we would introduce two new classes:
Other question to discuss: Would both the template context and the tag visitor context expose both? Or would only the template context expose the write interface, but both expose the read interface? And what about template context start vs template context finish? What are your thoughts there? I know we discussed this before, but it would be great if we could more clearly define the responsibilities of what tag visitors should do vs what the two hook callbacks for the entire template should do. |
Actually I think we'd just be introducing one new class which is the OD extension's interface for accessing the underlying tag processor and other relevant methods we expose for writing specific HTML. We could call it
For methods that are purely pass-through, yes, we could indeed use
Yes, I mention
Yeah, here location is more relevant. It could be:
However, there aren't any tag visitors that need this yet. So comments could be considered later.
Oh, now that you say this, I am reminded that it doesn't make sense for the So this conflicts with what I had said in #1931 (comment):
So, all of this to say, yes, I think you're right that there should be two new classes:
😅 |
What do you think about the trade-off between
Why wouldn't the latter apply to inline styles? Of course they don't need to load a file, but isn't processing the CSS still render-blocking? From that perspective, I don't see a fundamental difference in why inline CSS would never need to be at the end of the
How about for now we go with an implementation that doesn't allow specifying the location at all? We could simply go with the defaults that make the most sense for most cases. If later we come across needs to make it configurable, we can introduce location flags after all - but it seems this right now isn't crucial and is yet another point to figure out. I don't think there is any problem with BC in that regard, since a future location parameter could just be optional, and by default it would use the same behavior we define today. So:
For the latter, I think there is enough of an established need to add HTML comments from the get-go, e.g. how caching plugins do it. Putting that after the HTML makes most sense to me and is what I'm most commonly seeing. After all, the location of this truly does not matter, and putting it at the very end has, in principle, the least potential to get in the way (although of course you can hardly call an HTML comment render-blocking 😆).
For the most part, this sounds good to me. I'm pretty sure we discussed it before, but why again does the writer need to be accessible in all three places? Why would an extension want to use a tag visitor to write vs one of the template hooks to write? |
I don't have a strong opinion either way right now. We can try both when implementing to see what works better.
Yes, inline styles are render-blocking but since there is no network request to fetch them, the time would be drastically reduced. (This is something else to investigate re: Core-63018.) The vast majority of the time inline stylesheets should be put in the
Agreed.
SGTM.
Yes, we discussed before in #1919 (comment) and #1919 (comment) (and others). To quote the second comment, "there are three scenarios for inserting markup:
|
@westonruter SGTM, except I'm still questioning the following:
|
A benefit for allowing markup insertion in a tag visitor is it allows for a simplified code architecture. See #1919 (comment). While Embed Optimizer can inject cleaner stylesheets if it waits until
A tag visitor doesn't just read from the HTML, however. It also can write, such as making changes to tag attributes.
The HTML writer can indeed handle this de-duplication, but it could involve more work to do so. For example, when adding an inline script module, if the HTML writer were relied on only to de-duplicate, then it would need to iterate over all existing queued inline script modules to see if it already was added, and if so, abort. Granted, this will be fast, but it's slower than checking a boolean flag. |
WFM 👍
Good point raising that. So those more specific writes (let's call it updates rather than adding actual HTML) would still happen via regular tag processor methods, correct? Only any kind of additions of HTML / new DOM elements would be prevented and only allowed via our own writer, correct?
I don't think this would be substantially complex or slow to add. We could simply add a map to look up keys via
|
Originally discussed in #1919 (comment) and in other comments on that PR.
The
OD_HTML_Tag_Processor
class includes two methods:::append_head_html()
and::append_body_html()
. TheOD_HTML_Tag_Processor
instance is exposed on anOD_Tag_Visitor_Context
instance passed to the tag visitors, but it is not yet exposed on theOD_Template_Optimization_Context
class which is passed to theod_start_template_optimization
andod_finish_template_optimization
actions which run before and after the document has been iterated over by tag visitors, respectively.The current use cases for
::append_head_html()
are:LINK
HTML markup returned byOD_Link_Collection::get_html()
.STYLE
tag via a tag visitor to add a style for lazy loaded background images.STYLE
tag via a tag visitor to reduce layout shifts.STYLE
tag via a tag visitor for CV styles.The current use cases for
::append_body_html()
are:detect.js
script to the page.SCRIPT
to the end of theBODY
when there is a lazy-loaded embed on the page.SCRIPT
tag via a tag visitor to lazy load background images.SCRIPT
tag via a tag visitor to lazy load videos.Allowing insertion of HTML once via the
od_finish_template_optimization
avoids the need for tag visitors to keep track of whether they inserted or not. They can use the tag visitor callbacks to get a "lay of the land" by looking at all of the tags, and then at theod_finish_template_optimization
action they can finalize what they need to insert in theHEAD
or theBODY
.This could, for example, allow tag visitors to better optimize stylesheets they insert into the document. Instead of Embed Optimizer inserting a separate
STYLE
for each embed to reserve space to reduce layout shifts, it could instead insert a singleSTYLE
atod_finish_template_optimization
which combines all the style rules in one stylesheet. For example, this would allow Embed Optimizer to better group styles by media query instead of having to output@media (width <= 480px) {}
for each embed on the page. Currently for each embed it inserts aSTYLE
like:With the
od_finish_template_optimization
action, it could just print the@media
at-rules once for each viewport group rather than duplicating them, and output them all in a singleSTYLE
tag rather than in three separate ones, for example:See #1923 for a proof of concept for this.
Additionally, for tag visitors that insert scripts at the end of the
BODY
based on whether certain tags are encountered, this could be done via theod_finish_template_optimization
action instead. Otherwise the tag visitor needs to keep track with aadded_lazy_script
class member variable for whether it inserted the script yet, although the difference here is not as great as with the stylesheets in Embed Optimizer. Example: #1922.Being able to insert HTML via these actions would also be useful to a plugin like Optimization Detective Admin UI which needs to insert the current response's URL Metric data for rendering in the admin bar. See westonruter/od-admin-ui#11 for an example of how this could be implemented.
Currently when tag visitors call
::append_head_html()
or::append_body_html()
, they must be sure to pass raw HTML which is valid in theHEAD
andBODY
context respectively. If they don't, then they'll cause a parsing error for the browser (e.g. adding anIMG
in theHEAD
will prematurely open theBODY
).Optimization Detective could continue to use the
::append_head_html()
and::append_body_html()
, but for extensions there would need to be new methods like:::append_head_style()
to append an inline stylesheet::append_head_script()
(but also differentiate between inline vs non-inline?)::append_body_script()
(ditto)We wouldn't need to include an
::append_head_link()
since this is what theOD_Link_Collection
takes care of, but we may need to add support forrel=stylesheet
.Other potential methods that will be useful:
::append_body_stylesheet_link()
(not used yet, but useful for adding non-blocking external stylesheets)::append_head_meta()
to add aMETA
tag::append_body_comment()
to add a comment to the end of theBODY
::append_document_comment()
to add a comment after the closing</html>
tag.Note that we should perhaps not allow script modules to be inserted in the
HEAD
because import map scripts (SCRIPT[type="importmap"]
) are printed in the footer in Classic Themes, and if a script module appears before an import map then it prevents the import map from working.If these methods were exposed on both
OD_Tag_Visitor_Context
andOD_Template_Optimization_Context
then the::append_html_html()
and::append_body_html()
methods could be deprecated and eventually not exposed at all.See also the following from #1546:
The text was updated successfully, but these errors were encountered: