Repository: livewire/livewire (php)

Issue:
Livewire not working with mix.browserSync
### Description

Okay, so I first don't know if Livewire is supposed to work with mix.browserSync, so please let me know if it's just plain not supported. I see that there have been issues #996 and #1130 touching this topic and in #996 it seems that the issue author got it working by updating Livewire to 1.2.0. I'm using Livewire version 2.3.15.

I tried to start using Livewire in our Laravel 8 application that is in development and followed the quick start guide to implement the example counter. I had this error:

_Livewire encountered corrupt data when trying to hydrate the [counter] component. Ensure that the [name, id, data] of the Livewire component wasn't tampered with between requests._ 

After some investigation I found out that Livewire works with the url https://projectname.valet.test but not with the Browsersync proxy url: https://localhost:3000

To make debugging easier I installed a fresh Laravel 8 instance in url https://laravel-8.valet.test with just livewire/livewire package, configured Browsersync like this: `mix.browserSync('https://laravel-8.valet.test');` and followed the counter functionality in the [quick start guide](https://laravel-livewire.com/docs/2.x/quickstart). That gave me the very same result:

 _Livewire encountered corrupt data when trying to hydrate the [counter] component. Ensure that the [name, id, data] of the Livewire component wasn't tampered with between requests._ 

So I assumed that Livewire checks the APP_URL and compares it with the request domain and changed APP_URL to match https://localhost:3000, but still had the same issue.

Is this a bug? Is there something I should do to get this working? Or is Livewire just not compatible with mix.browserSync?

### Exact steps to reproduce

1.) Install fresh laravel/laravel 8.5.9
2.) Install Livewire 2.3.15
3.) Add `mix.browserSync('https://yordomain.test');` into your webpack.mix.js
4.) Run npm i && npm run watch
5.) Start implementing the [counter functionality](https://laravel-livewire.com/docs/2.x/quickstart).

**Context**
- Livewire version: 2.3.15
- Laravel version: 8.5.9 (laravel/framework 8.26.1)
- Alpine version: none
- Browser: Firefox Developer Edition


Pull request description:
Fix browserSync and rending components on POST request
This PR fixes #2453 and #2461

Rather than storing and referencing the full URL in the component fingerprint for re-playing persistent middleware (which breaks the route lookup when using browser-sync), we are only storing the "path" (after the root domain of the url) which will be "root" agnostic and allow browser-sync to work properly..

In addition, we are also now storing the original request method in the fingerprint in cases where applications return Livewire views from POST requests.

Patch:
diff --git a/src/Controllers/HttpConnectionHandler.php b/src/Controllers/HttpConnectionHandler.php
index e39864b2..7bb5fccc 100644
--- a/src/Controllers/HttpConnectionHandler.php
+++ b/src/Controllers/HttpConnectionHandler.php
@@ -27,12 +27,14 @@ class HttpConnectionHandler extends ConnectionHandler
     public function applyPersistentMiddleware()
     {
         try {
-            $request = $this->makeRequestFromUrl(
-                Livewire::originalUrl()
+            $request = $this->makeRequestFromUrlAndMethod(
+                Livewire::originalUrl(),
+                Livewire::originalMethod()
             );
         } catch (NotFoundHttpException $e) {
-            $request = $this->makeRequestFromUrl(
-                Str::replaceFirst(Livewire::originalUrl(), request('fingerprint')['locale'].'/', '')
+            $request = $this->makeRequestFromUrlAndMethod(
+                Str::replaceFirst(Livewire::originalUrl(), request('fingerprint')['locale'].'/', ''),
+                Livewire::originalMethod()
             );
         }
 
@@ -58,9 +60,9 @@ class HttpConnectionHandler extends ConnectionHandler
             });
     }
 
-    protected function makeRequestFromUrl($url)
+    protected function makeRequestFromUrlAndMethod($url, $method = 'GET')
     {
-        $request = Request::create($url, 'GET');
+        $request = Request::create($url, $method);
 
         if ($session = request()->getSession()) {
             $request->setLaravelSession($session);
diff --git a/src/LifecycleManager.php b/src/LifecycleManager.php
index 9e31f669..35252e1c 100644
--- a/src/LifecycleManager.php
+++ b/src/LifecycleManager.php
@@ -28,7 +28,13 @@ class LifecycleManager
         return tap(new static, function ($instance) use ($name, $id) {
             $instance->instance = app('livewire')->getInstance($name, $id);
             $instance->request = new Request([
-                'fingerprint' => ['id' => $id, 'name' => $name, 'locale' => app()->getLocale(), 'url' => Livewire::originalUrl()],
+                'fingerprint' => [
+                    'id' => $id,
+                    'name' => $name,
+                    'locale' => app()->getLocale(),
+                    'path' => Livewire::originalPath(),
+                    'method' => Livewire::originalMethod(),
+                ],
                 'updates' => [],
                 'serverMemo' => [],
             ]);
@@ -42,7 +48,13 @@ class LifecycleManager
         return tap(new static, function ($instance) use ($component,  $name) {
             $instance->instance = $component;
             $instance->request = new Request([
-                'fingerprint' => ['id' => $component->id, 'name' => $name, 'locale' => app()->getLocale(), 'url' => Livewire::originalUrl()],
+                'fingerprint' => [
+                    'id' => $component->id,
+                    'name' => $name,
+                    'locale' => app()->getLocale(),
+                    'path' => Livewire::originalPath(),
+                    'method' => Livewire::originalMethod(),
+                ],
                 'updates' => [],
                 'serverMemo' => [],
             ]);
diff --git a/src/LivewireManager.php b/src/LivewireManager.php
index f39cfe96..2513c30e 100644
--- a/src/LivewireManager.php
+++ b/src/LivewireManager.php
@@ -310,12 +310,46 @@ HTML;
     public function originalUrl()
     {
         if ($this->isDefinitelyLivewireRequest()) {
-            return request('fingerprint')['url'];
+            return url()->to($this->originalPath());
         }
 
         return url()->current();
     }
 
+    public function originalPath()
+    {
+        if ($this->isDefinitelyLivewireRequest()) {
+            // @depricted: "url" usage was removed in v2.3.17
+            // This can be removed after a period of time
+            // as users will have refreshed all pages
+            // that still used "url".
+            if (isset(request('fingerprint')['url'])) {
+                return str(request('fingerprint')['url'])->after(request()->root());
+            }
+
+            return request('fingerprint')['path'];
+        }
+
+        return request()->path();
+    }
+
+    public function originalMethod()
+    {
+        if ($this->isDefinitelyLivewireRequest()) {
+            // @depricted: "url" usage was removed in v2.3.17
+            // This can be removed after a period of time
+            // as users will have refreshed all pages
+            // that still used "url".
+            if (isset(request('fingerprint')['url'])) {
+                return 'GET';
+            }
+
+            return request('fingerprint')['method'];
+        }
+
+        return request()->method();
+    }
+
     public function getRootElementTagName($dom)
     {
         preg_match('/<([a-zA-Z0-9\-]*)/', $dom, $matches, PREG_OFFSET_CAPTURE);
diff --git a/src/RenameMe/SupportBrowserHistory.php b/src/RenameMe/SupportBrowserHistory.php
index 5bd41bdf..5c732462 100644
--- a/src/RenameMe/SupportBrowserHistory.php
+++ b/src/RenameMe/SupportBrowserHistory.php
@@ -71,7 +71,7 @@ class SupportBrowserHistory
         try {
             // See if we can get the route from the referer.
             return app('router')->getRoutes()->match(
-                Request::create($referer, 'GET')
+                Request::create($referer, Livewire::originalMethod())
             );
         } catch (NotFoundHttpException $e) {
             // If not, use the current route.


Test patch:
diff --git a/tests/Browser/Security/Component.php b/tests/Browser/Security/Component.php
index 192c39a5..cb8bb57d 100644
--- a/tests/Browser/Security/Component.php
+++ b/tests/Browser/Security/Component.php
@@ -23,7 +23,7 @@ class Component extends BaseComponent
         return <<<'HTML'
 <div>
     <span dusk="middleware">@json($middleware)</span>
-    <span dusk="url">{{ \Livewire\Livewire::isDefinitelyLivewireRequest() ? request('fingerprint')['url'] : '' }}</span>
+    <span dusk="path">{{ \Livewire\Livewire::isDefinitelyLivewireRequest() ? request('fingerprint')['path'] : '' }}</span>
 
     <button wire:click="$refresh" dusk="refresh">Refresh</button>
     <button wire:click="showNestedComponent" dusk="showNested">Show Nested</button>
diff --git a/tests/Browser/Security/NestedComponent.php b/tests/Browser/Security/NestedComponent.php
index 3059acf6..8716655b 100644
--- a/tests/Browser/Security/NestedComponent.php
+++ b/tests/Browser/Security/NestedComponent.php
@@ -15,7 +15,7 @@ class NestedComponent extends BaseComponent
         return <<<'HTML'
 <div>
     <span dusk="nested-middleware">@json($middleware)</span>
-    <span dusk="nested-url">{{ \Livewire\Livewire::isDefinitelyLivewireRequest() ? request('fingerprint')['url'] : '' }}</span>
+    <span dusk="nested-path">{{ \Livewire\Livewire::isDefinitelyLivewireRequest() ? request('fingerprint')['path'] : '' }}</span>
 
     <button wire:click="$refresh" dusk="refreshNested">Refresh</button>
 </div>
diff --git a/tests/Browser/Security/Test.php b/tests/Browser/Security/Test.php
index 8dd67b3e..ddc8822a 100644
--- a/tests/Browser/Security/Test.php
+++ b/tests/Browser/Security/Test.php
@@ -14,29 +14,29 @@ class Test extends TestCase
             Livewire::visit($browser, Component::class)
                 // See allow-listed middleware from original request.
                 ->assertSeeIn('@middleware', '["Tests\\\\Browser\\\\AllowListedMiddleware","Tests\\\\Browser\\\\BlockListedMiddleware"]')
-                ->assertDontSeeIn('@url', 'http://127.0.0.1:8001/livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
+                ->assertDontSeeIn('@path', 'livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
 
                 ->waitForLivewire()->click('@refresh')
 
                 // See that the original request middleware was re-applied.
                 ->assertSeeIn('@middleware', '["Tests\\\\Browser\\\\AllowListedMiddleware"]')
-                ->assertSeeIn('@url', 'http://127.0.0.1:8001/livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
+                ->assertSeeIn('@path', 'livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
 
                 ->waitForLivewire()->click('@showNested')
 
                 // Even to nested components shown AFTER the first load.
                 ->assertSeeIn('@middleware', '["Tests\\\\Browser\\\\AllowListedMiddleware"]')
-                ->assertSeeIn('@url', 'http://127.0.0.1:8001/livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
+                ->assertSeeIn('@path', 'livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
                 ->assertSeeIn('@nested-middleware', '["Tests\\\\Browser\\\\AllowListedMiddleware"]')
-                ->assertSeeIn('@nested-url', 'http://127.0.0.1:8001/livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
+                ->assertSeeIn('@path', 'livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
 
                 ->waitForLivewire()->click('@refreshNested')
 
                 // Make sure they are still applied when stand-alone requests are made to that component.
                 ->assertSeeIn('@middleware', '["Tests\\\\Browser\\\\AllowListedMiddleware"]')
-                ->assertSeeIn('@url', 'http://127.0.0.1:8001/livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
+                ->assertSeeIn('@path', 'livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
                 ->assertSeeIn('@nested-middleware', '["Tests\\\\Browser\\\\AllowListedMiddleware"]')
-                ->assertSeeIn('@nested-url', 'http://127.0.0.1:8001/livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
+                ->assertSeeIn('@path', 'livewire-dusk/Tests%5CBrowser%5CSecurity%5CComponent')
             ;
         });
     }