I have a Laravel project in which I have livewire, I tried to update them (Laravel from 10 to 11 and livewire from 2 to 3) following the guides for Laravel and for livewire.
After updating every packages and configs I started my project with laragon and vite as usual but got this error: Uncaught SyntaxError: expected expression, got ‘<‘, and no js works on any pages!
After 2 days of searching on the internet and trying stuff in my project I found out that the error happened because of @livewireScripts()/@livewireStyles() in my layout, after removing them I didn’t have the error but my js scripts would not work after that (which is normal I guess)
So could someone please help me on this, I really don’t understand this.
Here are some files. I know it is a lot and I am sorry, I don’t even know if those are relevant enough, I am just lost.
app.js before:
import '@fortawesome/fontawesome-free/js/all.js';
import Alpine from 'alpinejs';
import './bootstrap';
import './alpine';
import './data';
import './doc';
import './filter';
import { popoverinit } from './popover';
import '../sass/app.scss';
let colors;
window.Alpine = Alpine;
Alpine.start();
app.js after (deleted alpine start as it comes automatically with livewire 3 as said in the docs):
import '@fortawesome/fontawesome-free/js/all.js';
import './bootstrap';
import './data';
import './doc';
import './filter';
import { popoverinit } from './popover';
import '../sass/app.scss';
import { livewire_hot_reload } from 'virtual:livewire-hot-reload';
livewire_hot_reload();
vite.config.mjs:
import { fileURLToPath, URL } from 'url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import laravel from 'laravel-vite-plugin';
import livewire from '@defstudio/vite-livewire-plugin';
export default defineConfig({
build: {
sourcemap: false,
minify: false,
},
plugins: [
laravel({
input: ['resources/js/app.js', 'resources/js/update_product.js', 'resources/sass/app.scss', 'resources/js/Vue/main.js', 'resources/js/charts/product.js'],
refresh: true,
}),
vue(),
livewire({
refresh: ['resources/sass/app.scss'],
}),
],
resolve: {
alias: [
{ find: '@composition', replacement: fileURLToPath(new URL('./resources/js/Vue/composition', import.meta.url)) },
{ find: '@node_modules', replacement: fileURLToPath(new URL('./node_modules', import.meta.url)) },
],
},
});
config/livewire.php:
<?php
return[
'class_namespace' => 'App\Http\Livewire',
'view_path' => resource_path('views/livewire'),
'layout' => 'layouts.app',
'asset_url' => env('APP_URL', 'http://localhost'),
// new ones that came with livewire 3
'legacy_model_binding' => false,
'inject_assets' => true,
'inject_morph_markers' => true,
'navigate' => [
'show_progress_bar' => true,
'progress_bar_color' => '#22dd99',
],
];
layouts/app-livewire.blade.php before:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}" />
<title>My site</title>
<link rel="icon" type="image/png" sizes="96x96" href="{{ asset('favicons/favicon-96x96.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicons/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicons/favicon-16x16.png') }}">
@vite(['resources/js/app.js', 'resources/sass/app.scss'])
<!-- Resources -->
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<script src="//cdn.amcharts.com/lib/5/locales/fr_FR.js"></script>
<script src="https://cdn.amcharts.com/lib/5/percent.js"></script>
@livewireStyles()
@stack('styles')
<style>
.swal2-container {
z-index: 2100;
margin-top: 4em;
}
</style>
</head>
<body>
@include('partials.header')
<div class="leftpanel">
@include('partials.sidebar')
</div>
<div class="rightpanel">
<div class="d-flex flex-column">
@yield('header')
<div class="content">
@yield('content')
</div>
@include('partials.footer')
</div>
</div>
@livewireScripts()
@include('partials.scripts')
@include('partials.messages')
@stack('scripts')
</body>
</html>
layouts/app-livewire.blade.php after:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}" />
<title>My site</title>
<link rel="icon" type="image/png" sizes="96x96" href="{{ asset('favicons/favicon-96x96.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicons/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicons/favicon-16x16.png') }}">
@vite(['resources/js/app.js', 'resources/sass/app.scss'])
<!-- Resources -->
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<script src="//cdn.amcharts.com/lib/5/locales/fr_FR.js"></script>
<script src="https://cdn.amcharts.com/lib/5/percent.js"></script>
@stack('styles')
</head>
<body>
@include('partials.header')
<div class="leftpanel">
@include('partials.sidebar')
</div>
<div class="rightpanel">
<div class="d-flex flex-column">
@yield('header')
<div class="content">
@yield('content')
</div>
@include('partials.footer')
</div>
</div>
@include('partials.scripts')
@include('partials.messages')
@stack('scripts')
</body>
</html>
view.blade.php (scripts part) before:
<div>
... my view
@push('scripts')
<script type="module">
const regex = /[éèêëïçùô]/i;
$(document).on('input', '#newName, #editName', function() {
if (regex.test($(this).val())) {
$(this).css('border', '1px solid red');
$(this).css('box-shadow', '0 0 0 0.25rem rgba(220, 53, 69, 0.25)');
} else {
$(this).css('border', '1px solid #86b7fe');
$(this).css('box-shadow', '0 0 0 0.25rem rgba(13, 110, 253, 0.25)');
}
});
$(document).on('show.bs.modal', '#modal', function(e) {
const btn = e.relatedTarget;
if (btn.id === 'editBtn') {
$('.modal-title').text('Modifier personnel');
$('#newName').hide();
const editNameInput = $('#editName');
editNameInput.show();
editNameInput.val(btn.getAttribute('pName'));
editNameInput.attr('pId', btn.getAttribute('pId'));
} else {
$('.modal-title').text('Nouveau personnel');
$('#editName').hide();
const newNameInput = $('#newName');
newNameInput.show();
newNameInput.val('');
}
});
$(document).on('shown.bs.modal', '#modal', function(e) {
const btn = e.relatedTarget;
if (btn.id === 'editBtn') {
$('#editName').trigger('focus');
} else {
$('#newName').trigger('focus');
}
});
$(document).on('keyup', '#newName, #editName', function(e) {
if (e.key === 'Enter') {
if (regex.test($(this).val())) {
Swal.fire({
icon: 'error',
toast: true,
text: 'Les caractères spéciaux ne sont pas autorisés',
position: 'top-right',
showConfirmButton: false,
timer: 3000
})
return;
}
const modal = bootstrap.Modal.getInstance(document.getElementById('modal'));
modal.hide();
if ($(this).attr('id') === 'newName') {
@this.addPersonnel($(this).val());
} else {
@this.editPersonnel($(this).attr('pId'), $(this).val());
}
}
});
$(document).on('click', '#deleteBtn', function() {
if (confirm(`Voulez-vous vraiment supprimer ce personnel: ${$(this).attr('pName')}? `)) {
@this.deletePersonnel($(this).attr('pId'));
}
});
</script>
@endpush
</div>
view.blade.php (scripts part) after:
<div>
...my view
</div>
@script
<script type="module">
const regex = /[éèêëïçùô]/i;
$(document).on('input', '#newName, #editName', function() {
if (regex.test($(this).val())) {
$(this).css('border', '1px solid red');
$(this).css('box-shadow', '0 0 0 0.25rem rgba(220, 53, 69, 0.25)');
} else {
$(this).css('border', '1px solid #86b7fe');
$(this).css('box-shadow', '0 0 0 0.25rem rgba(13, 110, 253, 0.25)');
}
});
$(document).on('show.bs.modal', '#modal', function(e) {
const btn = e.relatedTarget;
if (btn.id === 'editBtn') {
$('.modal-title').text('Modifier personnel');
$('#newName').hide();
const editNameInput = $('#editName');
editNameInput.show();
editNameInput.val(btn.getAttribute('pName'));
editNameInput.attr('pId', btn.getAttribute('pId'));
} else {
$('.modal-title').text('Nouveau personnel');
$('#editName').hide();
const newNameInput = $('#newName');
newNameInput.show();
newNameInput.val('');
}
});
$(document).on('shown.bs.modal', '#modal', function(e) {
const btn = e.relatedTarget;
if (btn.id === 'editBtn') {
$('#editName').trigger('focus');
} else {
$('#newName').trigger('focus');
}
});
$(document).on('keyup', '#newName, #editName', function(e) {
if (e.key === 'Enter') {
if (regex.test($(this).val())) {
Swal.fire({
icon: 'error',
toast: true,
text: 'Les caractères spéciaux ne sont pas autorisés',
position: 'top-right',
showConfirmButton: false,
timer: 3000
})
return;
}
const modal = bootstrap.Modal.getInstance(document.getElementById('modal'));
modal.hide();
if ($(this).attr('id') === 'newName') {
$wire.addPersonnel($(this).val());
} else {
$wire.editPersonnel($(this).attr('pId'), $(this).val());
}
}
});
$(document).on('click', '#deleteBtn', function() {
if (confirm(`Voulez-vous vraiment supprimer ce personnel: ${$(this).attr('pName')}? `)) {
$wire.deletePersonnel($(this).attr('pId'));
}
});
</script>
@endscript
controller.php (just to show the render method) before:
public function render()
{
return view('livewire.view')->extends('layouts.app-livewire');
}
controller.php after:
#[Layout('layouts.app-livewire')]
public function render()
{
return view('livewire.view');
}