-
Notifications
You must be signed in to change notification settings - Fork 352
Allow turbo-cable-stream-source
to be compatible with data-turbo-permanent
#756
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
base: main
Are you sure you want to change the base?
Allow turbo-cable-stream-source
to be compatible with data-turbo-permanent
#756
Conversation
disconnectedCallback() { | ||
async disconnectedCallback() { | ||
this.disconnecting = true; | ||
await new Promise(resolve => setTimeout(resolve, 0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turbo relies on a variety of "timing" utilities internally, I wonder if any of them could be accessed here:
export function nextRepaint() {
if (document.visibilityState === "hidden") {
return nextEventLoopTick()
} else {
return nextAnimationFrame()
}
}
export function nextAnimationFrame() {
return new Promise((resolve) => requestAnimationFrame(() => resolve()))
}
export function nextEventLoopTick() {
return new Promise((resolve) => setTimeout(() => resolve(), 0))
}
export function nextMicrotask() {
return Promise.resolve()
}
nextEventLoopTick
is the obvious candidate, though I wonder if any of the others would be more appropriate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏻 I'll take a look at what I can import.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like none of the timing utilities are exported by Turbo. In the latest revision, I copied a named method called nextEventLoopTick
. Not my favorite, but open to feedback (for example, I could add another file with like util.js
).
This is a really interesting idea! The introduction of Element.moveBefore and the connectedMoveCallback could be extremely valuable (for both morphing and |
I'll look at that test failure. Looks like it's relevant. I appreciate the interest in beforeMove. The CanIUse on it looks pretty bleak right now unfortunately: https://caniuse.com/mdn-api_customelementregistry_define_connectedmovecallback_lifecycle_callback |
d56108d
to
b6faa7c
Compare
@seanpdoyle I pushed up a fix for the failing test. I didn't notice that |
Thinking aloud, I'm wondering how we can make the lifecycle more resilient. Waiting for the nextTick works currently, but is dependent on all of the turbo permanent dom operations being synchronous, which maybe isn't a good future-forward expectation. I think we could potentially track using turbo render events. As the order of events seems to be:
I'll take a swing at that, and now that I'm a bit more familiar with the test suite, I'll see if I can lock those in too. This turned out to be more fun and interesting than expected 😉 |
b6faa7c
to
37b8b64
Compare
When the element is disconnected from the DOM, wait a until after Turbo Render to allow any potential DOM re-connect to occur. Prevents unnecessary unsubscribe/subscribe cycles when preserved with data-turbo-permanent.
37b8b64
to
2cb3434
Compare
@seanpdoyle I just pushed up that change to hook into |
let removedOnce = false; | ||
el.reconnectedObserver = new MutationObserver((mutations) => { | ||
mutations.forEach((m) => { | ||
const isConnected = el.hasAttribute("connected"); | ||
if (m.oldValue === "" && !isConnected) { | ||
removedOnce = true; | ||
el.setAttribute("disconnected", ""); | ||
} | ||
if (removedOnce && m.oldValue == null && isConnected) { | ||
el.setAttribute("reconnected", ""); | ||
} | ||
}); | ||
}); | ||
el.reconnectedObserver.observe(el, { attributes: true, attributeOldValue: true, attributeFilter: ["connected"] }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting this observer would be unnecessary if there was something like this: #498 (comment)
...as we could more simply add a listener to the page for a subscription-connected/subscription-disconnected event rather than have to set up a mutation observer.
When the
turbo-cable-stream-source
element is disconnected from the DOM,wait a tickwait until the Turbo Render operation finishes to allow any potential DOM re-connect to occur. This prevents unnecessary channel unsubscribe/subscribe cycles when disconnected and then immediately reconnected withdata-turbo-permanent
and Turbo Drive.This is possible because all of the Turbo Permanent / bardo.js operations are synchronous.
Related issues:
<turbo-stream-source>
does not work as permanent turbo#868