Closed deanebarker closed 3 years ago
What if instead of adding a new attribute, we explored making meta
tags work similar to how the title
tag currently works.
So if a page contains:
<html>
<head>
<title>Original Title</title>
<meta name="description" content="Original description">
<meta name="keywords" content="my, key, words">
</head>
And the response contains:
<title>New Title</title>
<meta name="description" content="New description">
<meta name="keywords" content="">
<meta name="author" content="J.D.">
Then the result becomes:
<html>
<head>
<title>New Title</title>
<meta name="description" content="New description">
<meta name="keywords" content="">
<meta name="author" content="J.D.">
</head>
That would be lovely, but there are other page-specific things:
SCRIPT
references (which have to be created, not just copied in, or they don't load)STYLE
tagsLINK
tags (especially the canonical)So, it's not just META
All of those tags can go in the body
, except for "head-only" link tags (including canonical), unfortunately.
https://html.spec.whatwg.org/multipage/links.html#body-ok
Well, now we're talking about adding something to the core of the boosting code in htmx, which is far beyond the scope of an extension.
Thanks @deanebarker for opening this issue up. My opinion is that this should start off as an extension and then potentially be folded into the core of htmx if it is small enough and unobtrusive enough to warrant it. It should look specifically for content in a <head>
tag and update the head tag.
Ideally this would be a merge, like morphdom, in order to minimize the amount of reflow (my understanding is that updating the head tag causes reflows).
Meta tags look pretty easy since name
appears to be unique. Script tags in a head are a bit tricker, but probably not terrible. I would do the dumb thing first (look at the src
attribute or body of the tag and compare w/ existing). I assume all the other possibilities are roughly the same.
As far as where to plug in, I think a new event is needed, hmtx:afterResponseParse
, roughly here:
Additionally, I think we need to include the settleInfo
in the event, because my sense is that we probably want to do at least some of the processing after the DOM has settled.
@deanebarker the way htmx swaps work in general is as follows:
This sounds kind of crazy, but it lets you use CSS transitions without resorting to javascript. Consider the following HTML
<div id="div1">Original Content</div>
if content comes down from the server that looks like this:
<div id="div1" class="red">New Content</div>
It will be inserted into the DOM like this:
<div id="div1">New Content</div>
(note, no class attribute.) And then, after a delay (100ms by default) it will be changed to the complete new value:
<div id="div1" class="red">New Content</div>
That gives you an opportunity to write a CSS transition to, for example, fade the new content to red:
.red {
color: red;
transition: all ease-in 1s ;
}
All in pure HTML.
@deanebarker I can start a new branch feature-head-ext
to work on this with you, if you'd like.
Should you add the new event first? I think we should get that added and merged, because that really stands alone -- it might be used for things beyond this, right? I think it's cleaner if we don't mix that change up with this.
OK, I have a new branch for this work, with the framework for an extension and the new even added:
https://github.com/bigskysoftware/htmx/commit/532681fd028b24ca8a9b02aef800edfe8efc60bc
My prior solution was brute force -- get rid of anything with the attribute in the existing DOM, and add anything with the attribute in the incoming DOM.
Does this still sound like the right plan, except we'll check for existence first, in both directions? So, before we remove, we'll check to see if that same thing is in the incoming DOM, and if it is, we leave it alone (don't remove). And in the other direction, we'll check to see if the element we're about to add is already in the existing DOM, and if it is, we don't add it.
But this is still driven by the attribute, right? No attribute, then we don't anything with it? Or are we just checking everything now?
I think we'll need to do per-tag logic:
We'll probably have to think through each tag. :)
for a meta tag we can just check the name
property
too, sadly. The two attributes are used interchangeably.
Okay, so this where I level with you, @1cg: I'm not very good with JavaScript. I barely fumble through it. I'm not really even a developer anymore (this is me), but my past experience is in C#.
I classically know just enough about JavaScript to hurt myself.
So, I will stumble through this, with the understanding that you're probably going to have to come behind me and make it all not suck. But I can do the rote legwork to hopefully figure out the logic of it.
On the plus side, I'm in the state next door to you.
Great plains, FTW. Go Bobcats.
All good, I wrote htmx to avoid writing javascript, so I get it. :)
Just take a crack at it and me and @bencroker can help out where you have trouble.
The tests are probably the place to start, understanding how they work.
I've been looking through all the permutations of tags in the HEAD
that would contribute to "unique-ness," and it's lot. There are very simple ones like META
and name
or property
, but then there's some weird ones, like the hreflang
attribute on LINK
, etc.
There's a long tail.
I think we're going to need to have some way to specify what to check. If you look back on #245, I had some code like this:
swapTags("meta[name='twitter:title']", doc);
swapTags("meta[name='twitter:image']", doc);
I was specifying the tags I wanted to check. We might need to do something similar -- have the most common ones specified as DOM paths, and perhaps give the user some ability to add to it, if they have something more esoteric they want to check.
What does a wholesale .innerHTML
replacement do?
I have to be honest, my reflow-foo isn't great, so I don't even know how to tell what the implications are.
Given that we're replacing the entire BODY
too, I can't see how also replacing the entire innards of the HEAD
tag is going to have a material impact. We're essentially kicking off the "ultimate reflow operation" anyway...
closing out due to lost interest, we will have an open branch on this if interest revives
Opening from #245, since that issue was resolved and closed.
This issue is concerned with this note from @1cg:
Specifically, I'm interested in an extension/framework to alter the
HEAD
tag when boosting the entire page. When using boosting, theBODY
swaps, but only theTITLE
changes in theHEAD
(if supplied by the response). I would like to create a way to manage elements in theHEAD
that are specific to the new page.As mentioned in #245, this model seems to work:
Any incoming element with an attribute of
data-page-specific
will...I have this running on a product site, and it is working. Some
META
is perpetual from page-to-page, but anything specific to the incoming page likeog:title
gets adata-page-specific
attribute. Those elements will get removed on the next load, and the new page specific elements will be added.(Note: I'll likely change the attribute to something more inline with convention, like
ht-boost-swap
.)One question for @1cg or @bencroker before I start writing something --
Is there any official way to detect a boost reload? I actually had to surround the above code with this...
...otherwise it executed on every htmx request.
Is there a cleaner/more official way for me to determine that this is an entire page reload rather than a partial?