pwa-bundle icon indicating copy to clipboard operation
pwa-bundle copied to clipboard

Turbo and Offline

Open Spomky opened this issue 4 months ago • 5 comments

Version(s) affected

1.x

Description

When Symfony UX Turbo and the Offline feature are used together, there is a conflict with the fetch hook as their strategies are different.

How to reproduce

Enable both features on a brand new application

Possible Solution

Hook Symofny UX Turbo and prevent the use of the Online Only strategy

Additional Context

No response

Spomky avatar Aug 24 '25 09:08 Spomky

Closing as cache can be globally disable on client side. <meta name="turbo-cache-control" content="no-cache" /> is fine.

See https://turbo.hotwired.dev/handbook/building#opting-out-of-caching

Spomky avatar Aug 27 '25 06:08 Spomky

The issue still exists...

Spomky avatar Aug 27 '25 08:08 Spomky

@Spomky did you see this conference about how to turn Turbo offline with Service Workers? hope it helps you

davidromani avatar Nov 02 '25 17:11 davidromani

Hi @davidromani,

No, I haven’t watched it yet. I will! Thank you for the resource.

TBH, I have a fix that should work, but I haven’t taken the time to verify it. The idea is to exclude requests with Turbo Stream / Turbo Frame headers from being cached by the navigate callback. This way, there should be no interaction between Turbo and this bundle.

Spomky avatar Nov 02 '25 18:11 Spomky

Minimal patch

diff --git a/src/MatchCallbackHandler/NavigationMatchCallbackHandler.php b/src/MatchCallbackHandler/NavigationMatchCallbackHandler.php
index 11c8bcc..bbb6b07 100644
--- a/src/MatchCallbackHandler/NavigationMatchCallbackHandler.php
+++ b/src/MatchCallbackHandler/NavigationMatchCallbackHandler.php
@@ -28,7 +28,22 @@ final class NavigationMatchCallbackHandler implements MatchCallbackHandlerInterf
             'match_callback' => $matchCallback,
         ]);
 
-        return "({request}) => request.mode === 'navigate'";
+        return <<<'JS'
+({request}) => {
+    if (request.mode !== 'navigate') {
+        return false;
+    }
+    const acceptHeader = request.headers.get('Accept') || '';
+    if (acceptHeader.includes('text/vnd.turbo-stream.html')) {
+        return false;
+    }
+    if (request.headers.get('Turbo-Frame')) {
+        return false;
+    }
+
+    return true;
+}
+JS;
     }
 
     public function setLogger(LoggerInterface $logger): void

Spomky avatar Nov 03 '25 09:11 Spomky