Skip to content

Commit 691c6d0

Browse files
authored
Add support for Livewire v4 (#46)
## Changes The `<script>` tag is now rendered via `Blade::render()` and added to the json response returned by the `/embed` route. On the client side, `injectLivewire()` consumes this tag and injects the script into the page. Since the script is delivered through the embed payload, the helpers `getLivewireAssetUri()` and `getLivewireUpdateUri()` become obsolete from my point of view.
1 parent d7ca599 commit 691c6d0

6 files changed

Lines changed: 40 additions & 33 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
vendor
22
.idea
33
.DS_Store
4+
composer.lock

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "Embed your Livewire components anywhere.",
44
"require": {
55
"php": "^8.1",
6-
"livewire/livewire": "^v3.4.7"
6+
"livewire/livewire": "^3.4.7|^4.0"
77
},
88
"license": "MIT",
99
"autoload": {
@@ -26,4 +26,4 @@
2626
},
2727
"minimum-stability": "dev",
2828
"prefer-stable": true
29-
}
29+
}

js/wire-extender.js

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ let componentAssets;
33
let currentScript = document.currentScript;
44
let livewireStarted = false;
55

6-
function getUri(append = '')
7-
{
6+
function getUri(append = '') {
87
let uri = document.querySelector('[data-uri]')?.getAttribute('data-uri');
98

109
if (!uri) {
@@ -18,26 +17,14 @@ function getUri(append = '')
1817
return uri + append;
1918
}
2019

21-
function getLivewireAssetUri()
22-
{
23-
return document.querySelector('[data-livewire-asset-uri]')?.getAttribute('data-livewire-asset-uri') ?? getUri('livewire/livewire.min.js');
24-
}
25-
26-
function getLivewireUpdateUri()
27-
{
28-
return document.querySelector('[data-update-uri]')?.getAttribute('data-update-uri') ?? getUri('livewire/update');
29-
}
30-
31-
function getEmbedUri()
32-
{
20+
function getEmbedUri() {
3321
const base = document.querySelector('[data-embed-uri]')?.getAttribute('data-embed-uri') ?? getUri('livewire/embed');
3422
const queryString = window.location.search;
3523

3624
return base + queryString;
3725
}
3826

39-
function injectLivewire()
40-
{
27+
function injectLivewire(script) {
4128
if (window.Livewire || livewireStarted) {
4229
return;
4330
}
@@ -46,10 +33,20 @@ function injectLivewire()
4633
style.innerHTML = '[wire\\:loading][wire\\:loading], [wire\\:loading\\.delay][wire\\:loading\\.delay], [wire\\:loading\\.inline-block][wire\\:loading\\.inline-block], [wire\\:loading\\.inline][wire\\:loading\\.inline], [wire\\:loading\\.block][wire\\:loading\\.block], [wire\\:loading\\.flex][wire\\:loading\\.flex], [wire\\:loading\\.table][wire\\:loading\\.table], [wire\\:loading\\.grid][wire\\:loading\\.grid], [wire\\:loading\\.inline-flex][wire\\:loading\\.inline-flex] {display: none;}[wire\\:loading\\.delay\\.none][wire\\:loading\\.delay\\.none], [wire\\:loading\\.delay\\.shortest][wire\\:loading\\.delay\\.shortest], [wire\\:loading\\.delay\\.shorter][wire\\:loading\\.delay\\.shorter], [wire\\:loading\\.delay\\.short][wire\\:loading\\.delay\\.short], [wire\\:loading\\.delay\\.default][wire\\:loading\\.delay\\.default], [wire\\:loading\\.delay\\.long][wire\\:loading\\.delay\\.long], [wire\\:loading\\.delay\\.longer][wire\\:loading\\.delay\\.longer], [wire\\:loading\\.delay\\.longest][wire\\:loading\\.delay\\.longest] {display: none;}[wire\\:offline][wire\\:offline] {display: none;}[wire\\:dirty]:not(textarea):not(input):not(select) {display: none;}:root {--livewire-progress-bar-color: #2299dd;}[x-cloak] {display: none !important;}';
4734
document.head.appendChild(style);
4835

36+
const temp = document.createElement('div');
37+
temp.innerHTML = script.trim();
38+
39+
const scriptEl = temp.querySelector('script');
40+
4941
livewireScript = document.createElement('script');
50-
livewireScript.src = getLivewireAssetUri();
51-
livewireScript.dataset.csrf = '';
52-
livewireScript.dataset.updateUri = getLivewireUpdateUri();
42+
livewireScript.src = scriptEl.src;
43+
44+
for (let attr of scriptEl.attributes) {
45+
if (attr.name.startsWith('data-')) {
46+
livewireScript.setAttribute(attr.name, attr.value);
47+
}
48+
}
49+
5350
document.body.appendChild(livewireScript);
5451
}
5552

@@ -58,7 +55,7 @@ function waitForLivewireAndStart() {
5855
return;
5956
}
6057

61-
if(window.Livewire) {
58+
if (window.Livewire) {
6259
startLivewire();
6360
}
6461
livewireScript.onload = async function () {
@@ -68,20 +65,16 @@ function waitForLivewireAndStart() {
6865
livewireStarted = true;
6966
}
7067

71-
async function startLivewire(assets)
72-
{
68+
async function startLivewire(assets) {
7369
Livewire.hook('request', ({ options }) => {
7470
options.headers['X-Wire-Extender'] = '';
7571
options.credentials = 'include';
7672
})
77-
await Livewire.triggerAsync('payload.intercept', {assets: componentAssets});
73+
await Livewire.triggerAsync('payload.intercept', { assets: componentAssets });
7874
Livewire.start();
7975
}
8076

81-
function renderComponents(components)
82-
{
83-
injectLivewire();
84-
77+
function renderComponents(components) {
8578
fetch(getEmbedUri(), {
8679
method: 'POST',
8780
headers: {
@@ -90,7 +83,7 @@ function renderComponents(components)
9083
body: JSON.stringify({
9184
components: components
9285
}),
93-
'credentials': 'include'
86+
'credentials': 'include'
9487
})
9588
.then(response => response.json())
9689
.then(data => {
@@ -100,11 +93,13 @@ function renderComponents(components)
10093
}
10194

10295
componentAssets = data.assets;
96+
97+
injectLivewire(data.script);
10398
waitForLivewireAndStart();
10499
});
105100
}
106101

107-
document.addEventListener('DOMContentLoaded', function() {
102+
document.addEventListener('DOMContentLoaded', function () {
108103
let components = [];
109104

110105
document.querySelectorAll('livewire').forEach((el) => {

routes/api.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

33
use WireElements\WireExtender\Http\Controllers\EmbedController;
4+
use WireElements\WireExtender\Http\Controllers\InjectController;
45

5-
Route::any('livewire/embed', EmbedController::class);
6+
Route::any('livewire/embed', EmbedController::class);

src/Http/Controllers/EmbedController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public function __invoke(Request $request)
3333
return [
3434
'components' => $components,
3535
'assets' => SupportScriptsAndAssets::getAssets(),
36+
'script' => Blade::render('@livewireScripts'),
3637
];
3738
}
3839

src/WireExtender.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class WireExtender
1212
public static function isEmbeddable($component): bool
1313
{
1414
try {
15-
$reflectionClass = new ReflectionClass(app(ComponentRegistry::class)->new($component));
15+
$reflectionClass = new ReflectionClass($this->resolveComponentClass($component));
1616
$embedAttribute = $reflectionClass->getAttributes(Embeddable::class)[0] ?? null;
1717

1818
return is_null($embedAttribute) === false;
@@ -22,4 +22,13 @@ public static function isEmbeddable($component): bool
2222

2323
return true;
2424
}
25+
26+
protected function resolveComponentClass(string $component): string
27+
{
28+
if (class_exists(ComponentRegistry::class)) {
29+
return app(ComponentRegistry::class)->getClass($component);
30+
}
31+
32+
return app('livewire.finder')->resolveClassComponentClassName($component);
33+
}
2534
}

0 commit comments

Comments
 (0)