(After migrating to Vite) Some stacked scripts are executed before they should? - laravel

so I just migrated to Vite, and almost everything works, except... In a Blade component I'm adding a script to my scripts stack :
#push('scripts')
<script>
myfoo();
</script>
#endpush
In app.js I have defined
window.myfoo = () => {
console.log(111);
}
And I get an error Uncaught ReferenceError: myfoo is not defined. It worked before with Webpack. If I call myfoo() in the console it works. If I setTimeout the call a bit it works.
Of course in my layout they're in the correct order :
#vite('resources/js/app.js') {{-- Previously <script src="{{ mix('js/app.js') }}"></script> --}}
#stack('scripts')
I can force the call to wait for DOMContentLoaded but honestly I just don't understand the issue. Thanks ahead.

So it's because the script is tagged as type="module", its execution seems to be delayed. The solution is to makr the depending script as type="module" too.
#push('scripts')
<script type="module">
myfoo();
</script>
#endpush

Related

Laravel - Prevent duplicate script tags when using partials/modals

I have a few update forms that exist on multiple pages. To reduce workload, I have built these forms as partials/modals that can be #included when needed. Some of the forms utilize a mask.js so I also include an #parent for 'scripts' to include the tag.
It works, but I think I may be attempting to load external JS multiple times if two of the forms use the mask.js and are included in the same view blade.
For example:
Main Page
#include('partials.newdate')
#include('partials.olddate')
partials/newdate.blade.php
#section('scripts')
#parent
<script src="/js/jquery.mask.min.js"></script>
#stop
partials/olddate.blade.php
#section('scripts')
#parent
<script src="/js/jquery.mask.min.js"></script>
#stop
both of the partials need this script, but I also would like to avoid loading it on all pages to reduce load times.
Is there something I can do to "check" for jquery.mask.min.js before laravel adds it to the script section?
You could use the once directive
https://laravel.com/docs/9.x/blade#the-once-directive
#once
#push('scripts')
<script>
// Your custom JavaScript...
</script>
#endpush
#endonce

Laravel 9 vite - internal script is executed before JS bundled via vite

I've created 'test.js' file in 'resources/js/' and added console.log(first) to it
In the welcome.blade.php I have something like that:
<body>
#vite(['resources/js/test.js'])
<script type='text/javascript'>
console.log(second)
</script>
</body>
What I expect is to execute those scipts in order from top to bottom, however it returns output:
second
first
I guess #vite(['resources/js/test.js']) is executed asynchronously by default, but I want to change it.
Is there any better way to do this than to put all the internal JS in DOMContentLoaded?
Changing type from 'text/javascript' to 'module' helped.
<script type='module'>
console.log(second)
</script>

Laravel Blade: What is best practice for adding javascript in blade files?

I inherited a Laravel project that has many blade files with javascript inside tags within the blade file. The issue is that there is a lot of repetitive JS logic so I'd like to extract the JS and create JS files to include in the blade? Example: <script src="{{ asset('js/components/file.js')}}"></script>
Is this the best practice for blade files or is it expected to be have the JS within the actual file?
First you have to assign where yo want to push scripts in your layout. for example, say layout.blade.php is your main layout file and you want to inject codes after footer. So add
#stack('scripts')
after footer.
Now in your blade file, use #push to inject your code.
#push('scripts')
<script>
// your code
</script>
#endpush
check blade stack for further detail.
I recommend you to maintain a specific section for page-specific javascript.
Please refer the following examples..
Example template.blade.php
<body>
#yield('content')
#include('_partial.scripts')
#yield('page-script')
#include('_partial.footer')
</body>
then
#section('page-script')
<script type="text/javascript">
// your custom script
</script>
#stop
Just wanted to bring some additionnal information, you can also use the defer attribute.
And here with Laravel 8, in webpack.mix.js
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/my-super-amazing-script.js', 'public/js')
And in your main my-layout.blade.php :
...
#yield('javascript')
</body>
Then, in in your specific page :
#extend('my-layout.blade.php')
...
#section('javascript')
<script src="{{ mix('js/my-super-amazing-script.js') }}" defer></script>
#endsection

cycle is not a function

I have the following page http://link.org/ (tested and is valid W3 HTML), where I am using the jquery cycle slideshow function (old version).
But even though the cycle function file is definitely being called, I am still getting an error: $(...).cycle is not a function
Would someone be able to look and see what the issue might be?
Thanks!
For some weird reason jQuery tools are invoking ready event before page is completely loaded, change order of scripts from:
<script type="text/javascript" src="includes/jquery.cycle.all.min.js"></script>
<script type="text/javascript" src="includes/jquery.tools.min.js"></script>
to
<script type="text/javascript" src="includes/jquery.tools.min.js"></script>
<script type="text/javascript" src="includes/jquery.cycle.all.min.js"></script>
and your error will be gone.

jQuery Datepicker in Fancybox not working

I have a very strange behavior with a datepicker loaded with data-type="ajax" inside the fancybox.
It is not possible to change month and year in the datepicker.
If I open datepicker and close the fancybox not by using the close "x", the datepicker still remains, but then with working select boxes for month and year
Here's my code from the calling script:
<html>
<head>
<title>test fancybox with datepicker</title>
<script language="javascript" type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.2.5/jquery.fancybox.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.2.5/jquery.fancybox.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" />
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script></head>
<body>
<a data-fancybox data-type="ajax" href="testfancy-call.php">
Load Fancybox Content
</a>
</body>
</html>
And this is the very simple code from testfancy-call.php:
<html>
<head>
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$("#date").datepicker({
changeMonth: true,
changeYear: true,
});
});
</script>
</head>
<body>
<h1>Datepicker</h1>
<input type="text" name="date" value="" id="date">
</body>
</html>
I tried to use data-type="iframe". Here I get the datepicker working, but I have to include all external script inside "testfancy-call.php". This is not a proper solution for me, because the used software's architecture doesn't allow this. So I need to find a way using data-type="ajax".
EDIT
The behavior is only when loading with data-type="ajax". If I place the code stuff from the ajax-loaded file testfancy-call.php directly inside the calling script like in https://codepen.io/fancyapps/pen/QqLXaz it works!
EDIT 2
After some research I found that it's a crossbrowser problem for issue 1. In Firefox the selectboxes for month and year so not work. Internet Explorer and Chrome work like exspected. Is there a way to get Firefox working?
All three testet browsers have the problem that is described in issue 2.
EDIT 3
I've uploaded a demo: http://marcox.square7.ch/testfancy.html
Try disabling touch events using touch: false, because fancyBox catches touch events by default to enable swiping gestures.

Resources