Export PageRenderer#305
Conversation
|
Please do look at turning that monkey patch into more direct flexibility. @domchristie was just mentioning this in #290. |
|
FYI, I've tackled this issue in chaskiq.io (intercom-like embed) by wrapping the embed div in a turbo-permanent. That will persist their state between navigation. |
|
@dhh Thanks for the merge! I've already tried wrapping the node with I came across the following issues that describe the problem (or similar/related problems):
Being able to intercept the rendering operation as described in #290 might be a viable solution to the problem if it'd allow you to switch the rendering target from @dhh just an idea, but perhaps being able to specify a different rendering target by simply adding an optional attribute (i.e. Example Layout HTML diff Example PageRenderer diff I haven't tried the above yet, but this is essentially what I had in mind. The default behavior stays the same (render into |
|
@mrrooijen Can you explain more the issue you're trying to solve? Why isn't data-turbo-permanent working for you? What's breaking and could we fix it? It is an interesting idea to basically invert data-turbo-permanent, such that everything NOT marked is permanent. But I'm not sure why we're able to make that work but not specifically marking something as data-turbo-permanent? Is it about detaching and attaching the nodes that trigger something? |
|
@dhh correct. When you detach an element containing an iframe, and then re-attach it, it'll cause the iframe to reload. This behavior is intended and there's no way around it as far as I know. See: https://bugs.webkit.org/show_bug.cgi?id=13574#c14 There apparently used to be a "magic iframe" that could work around this issue, but it's been removed due to security implications. Third party nodes and iframes (Stripe, HelpScout, etc) are commonly injected just before the closing Therefore, the only way that I currently know of that resolves this issue is to, rather than render your content into
Just to clarify, the solution that I proposed (the diffs) doesn't involve the use of |
|
I don't have a deep knowledge of the rendering process, but my feeling is that it won't be straightforward to just change the target render element, and that this might cause future maintenance issues. (It could become a reimplementation of Turbo frames :/) Given the uncertainty around how this might be used, my preference would be for a "canary" API using the pausable render feature. For example something like: |
|
Our use case will require something similar. We are embedding Twilio Flex inside of an iframe in our CRM. The iframe reload during the visit causes state loss and breaks WebRTC connections which results in dropped calls. I made a fork that did exactly what @mrrooijen suggested with Something like what @domchristie suggests would definitely work for our use case. |
I have spiked an idea for this here: main...domchristie:custom_rendering Not tried it, but might be worth testing it out. |
|
Thanks @domchristie! Your spike does allow rendering to a child element instead of body without monkey patching PageRenderer. Unfortunately you lose the permanent element preservation and script activation that are handled by PageRenderer. For this particular use case, being able to configure the function that assigns the new body would be preferable: I'm not sure if that's much better than monkey patching PageRenderer, though. Another option would be to extract those features from PageRenderer and allow people to use them in their custom renderers. That allows a high amount of flexibility without sacrificing some of turbo's great features in the process. Either way the problem with restoration visits still exists, but it looks like @tbo already discovered the cause of that. See #218 (comment) re: snapshotting mechanism. I would love to see that one line merged, it would allow us to switch off our fork. |
I suppose that if you were using a DOM diffing library like morphdom then you'd likely handle permanent elements yourself? Perhaps there's a way to implement both e.g. |
|
I'm not a morphdom expert, but I imagine there may be cases where you have some state that you would like to keep even though the server is returning a new body that contains some default state. I don't know if morphdom has its own way to express that.
Letting people provide their own PageRenderer is a potential solution. Instead of letting people monkey-patch it, you could write your own or extend the one that Turbo exports. Example: |
I think this is possible with the
I think I'm generally against this approach, as the entire |
That looks straightforward to me. I like the idea. Far better than making For our use case extra weight of morphdom isn't an issue, I'll give it a go with your branch and see if I can get script activation working as well. Thanks! |
|
Not tested extensively, but what you had there more or less worked, and adding Turbo-compatible script activation was easy as well. In case anybody is curious: While adopting morphdom and copying some turbo functionality can work for us, I can see value in also having an official Turbo solution using @mrrooijen's suggestion of specifying a target for body assignment with something like In other words, I like both |
|
With PageRenderer now being exportable, the following works for me. Page restorations appear to work for me because I'm not caching pages. Otherwise, as @internets pointed out, it will break. |
If you'd like to continue caching, you can eliminate the pause before cloning the snapshot. Here's the monkey patch: I'm not 100% sure yet, but I believe the |
|
Thanks for exporting this, this works great! |
|
For those coming across this issue, who might be looking for a more limited patch that still allows for caching to function as expected, I went about it by actually adding The order of execution without adding
By adding I believe the reason this isn't an issue if you replace all of |
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in #305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
|
For anyone that takes inspiration from #305 (comment) please be aware that the code provided fixes the cache visits issue, but for non-cache visits, if the new body and old body contain |
|
@agrobbin @scottnicolson I'd like to point that implementing #305 (comment) causes |
I think these are the minimal changes to make |
While most of the time, replacing `<body>` makes perfect sense, when working with 3rd party integrations (i.e. Stripe), there are elements injected just before the closing `</body>` tag that should not be removed between page visits. There is more detail on this issue, particularly with injected `<iframe>` elements in hotwired/turbo#305 (comment). Now, if someone wants to customize the element that is replaced by Drive, they can add `data-turbo-drive-body` to an element, and only that element will be replaced between visits.
There are situations where you don't want the entire body to be replaced. One of the reasons would be when you're using 3rd party libraries that inject code (i.e. an iframe) such as Intercom or HelpScout, as this would result in the removal- and state-loss of their UI component every time you navigate using turbo drive.
Looking through previous issues it seems that there's no desire to add the ability to select a different node to render turbo drive responses into. So instead, it would be nice to be able to monkey-patch this functionality in so we can opt-out of this constraint. However, in order to do this we'll need access to PageRenderer, which currently isn't exported. This PR exports it.