I’ve been modularizing my ‘Create’ and ‘Edit’ Blade views correspondent to a feature of my Laravel app, by splitting their code into different files. I’ve done this as there are different sections for creating or editing a database register for it, with different forms on each one. Also, in one of these sections, I’ve decided to create separated files: one for coding the form itself, and another one for its behaivour, and so manipulating the DOM correspondent to that form.
So then, I’m having this in this file:
‘resources/views/alquileres/create.blade.php’:
...
@if ($seccion == 'generales')
@include('alquileres.partials.create.generales')
@include('alquileres.scripts.create.generales')
@elseif($seccion == 'multimedia')
...
@endif
...
Then, in that last included file, I have something like this:
‘resources/views/alquileres/scripts/create/generales.blade.php’:
<script>
const raizProv="{{route('api.provincias')}}";
const raizDep="{{route('api.departamentos_municipios','departamentos')}}";
const raizMun="{{route('api.departamentos_municipios','municipios')}}";
const raizLoc="{{route('api.localidades')}}";
</script>
<script src="{{ asset('js/geocoding.js') }}"></script>
<script src="{{ asset('js/jquery-3.7.1.min.js') }}"></script>
<script>
console.log('$');
console.log($);
//...
const generarListaProvincias= function(objetoProvincias) {
const option = document.createElement("option");
option.textContent="Seleccione una provincia";
option.value="";
$('#provincia_id').append(option);
objetoProvincias.provincias.forEach(provincia => {
const option = document.createElement("option");
option.value= provincia.id;
option.textContent=normalizar(provincia.nombre);
$('#provincia_id').append(option);
});
};
//...
</script>
That last file it’s using at this moment, two external .js files for working properly:
- ‘public/js/geocoding.js’
- ‘public/js/jquery-3.7.1.min.js’
The first one has in it some functions coded by myself, which are used by the code into the tags on into my Blade file, to work properly.
The second one, is just the jQuery lib file, which I’ve decided to download and store it into my own project folder, instead of reference it by an external URL. I’ve done this to improve the performance, and also to avoid the need of getting that resource from Internet each time that’s needed.
Here’s a little bit of the code I have on ‘geocoding.js’:
‘public/js/geocoding.js’:
function ucwords(str) {
str = str.toLowerCase();
return str.replace(/(?:^|s)([a-zA-ZñÑ])/g, function(firstLetter) {
return firstLetter.toUpperCase();
});
}
function quitarAcentos(texto) {
const mapaAcentos = { á: "a", é: "e", í: "i", ó: "o", ú: "u",
Á: "A", É: "E", Í: "I", Ó: "O", Ú: "U" };
return texto.replace(/[áéíóúÁÉÍÓÚ]/g, function(letra) {
return mapaAcentos[letra];
});
}
function normalizar(texto) {
return ucwords(quitarAcentos(texto));
}
//...
const solicitarDepartamentos = async function(codProvincia) {
const url = raizDep + "?provincia=" + codProvincia + "&orden=nombre&campos=completo&max=1500";
try {
const response = await fetch(url);
if (!response.ok) throw new Error("Error al realizar la solicitud");
const objetoDepartamentos = await response.json();
return objetoDepartamentos;
} catch (error) {
console.log(error);
return error;
}
};
//...
Despite this works, I find that’s a pretty untidy approach to have these both .js files located in the ‘public’ directory of my project, so I’ve tried to achieve the same results I’m having now, but by getting those functions defined in there within the assets bundled with Vite in my project instead.
So then, I’ve previously tried an approach like this:
‘vite.config.js’:
import { defineConfig } from 'vite';
import laravel, { refreshPaths } from 'laravel-vite-plugin';
import postcss from './postcss.config.js';
export default defineConfig({
css: {
postcss,
},
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: [
...refreshPaths,
'app/Livewire/**',
],
}),
],
});
‘resources/js/app.js’:
import resolveConfig from 'tailwindcss/resolveConfig';
import tailwindConfig from '../../tailwind.config.js';
const fullConfig = resolveConfig(tailwindConfig);
import './bootstrap';
import { Livewire, Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm';
Livewire.start();
if (!window.Livewire) window.Livewire = Livewire;
if (!window.Alpine) window.Alpine = Alpine;
‘resources/js/bootstrap.js:
import { numeroALetras, letrasANumero } from './numerosALetras';
window.numeroALetras = numeroALetras;
window.letrasANumero = letrasANumero;
import _ from 'lodash';
window._ = _;
import $ from 'jquery';
window.$ = $;
Despite this approach works fine for Lodash, it just doesn’t works for jQuery, since when I edit my file like this:
‘resources/views/alquileres/scripts/create/generales.blade.php’:
<script src="{{ asset('js/geocoding.js') }}"></script>
- <script src="{{ asset('js/jquery-3.7.1.min.js') }}"></script>
+ {{--<script src="{{ asset('js/jquery-3.7.1.min.js') }}"></script>--}}
<script>
console.log('$');
console.log($);
//...
</script>
I’m getting, at that last ‘console.log’ (for example):
Uncaught ReferenceError: $ is not defined at crear:925:17
And so, all the DOM behaivour I’ve coded with jQuery to handle the correspondent form, it just doesn’t works.
I’ve been reaserching a lot on the web to find a practical solution for this issue. These are the main websites I’ve consulted for finding a practical solution:
- https://dev.to/chmich/setup-jquery-on-vite-598k
- https://laracoding.com/how-to-install-and-use-jquery-with-laravel-vite/#ReferenceError-$-is-not-defined
- https://javascript.info/modules-intro#module-scripts-are-deferred
- https://laravel.com/docs/11.x/vite
- ReferenceError: $ is not defined, Jquery Import with vite
- https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload
- https://laracasts.com/discuss/channels/laravel/jquery-with-vite-jquery-is-not-a-function
- https://www.makbeta.com/blog/configure-and-use-jquery-globally-vite
- https://github.com/vitejs/vite/discussions/3744
After reading that, I’ve tried this:
‘resources/views/alquileres/scripts/create/generales.blade.php’:
<script src="{{ asset('js/geocoding.js') }}"></script>
{{--<script src="{{ asset('js/jquery-3.7.1.min.js') }}"></script>--}}
- <script>
+ <script type="module">
console.log('$');
console.log($);
//...
</script>
Despite with this change, the DOM behaivour at least works, I’m not being able to access the functions defined into the tags in this same file when doing this, and so getting this kind of errors:
Uncaught ReferenceError: establecerDireccion is not defined at :1:1
(‘establecerDireccion’ is a function defined into the tags on ‘generales.blade.php’).
And so, after reading a lot that mentioned documentation and trying a lot of stuff, now the contents of my files are these ones:
‘vite.config.js’:
import { defineConfig } from 'vite';
import laravel, { refreshPaths } from 'laravel-vite-plugin';
import postcss from './postcss.config.js';
import inject from '@rollup/plugin-inject';
//import jQuery from "jquery";
import 'jquery';
export default defineConfig(({ command, mode }) => ({
css: {
postcss,
},
plugins: [
inject({
//$: 'jquery',
jQuery: 'jquery',
}),
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: [
...refreshPaths,
'app/Livewire/**',
],
}),
],
resolve: {
alias: {
//jquery: 'jquery/dist/jquery.min.js',
jquery: 'jquery',
},
},
optimizeDeps: {
include: ['jquery'],
},
build: {
rollupOptions: {
output: {
// expose jQuery as a global variable
globals: {
jquery: 'jQuery'
}
}
}
}
}));
‘resources/js/app.js’:
import resolveConfig from 'tailwindcss/resolveConfig';
import tailwindConfig from '../../tailwind.config.js';
const fullConfig = resolveConfig(tailwindConfig);
import './bootstrap';
import './jquery';
import { Livewire, Alpine } from '../../vendor/livewire/livewire/dist/livewire.esm';
Livewire.start();
if (!window.Livewire) window.Livewire = Livewire;
if (!window.Alpine) window.Alpine = Alpine;
‘resources/js/bootstrap.js’:
import { numeroALetras, letrasANumero } from './numerosALetras';
window.numeroALetras = numeroALetras;
window.letrasANumero = letrasANumero;
import _ from 'lodash';
window._ = _;
‘resources/js/jquery.js’ (with lots of commented lines I’ve previously tried):
//import jQuery from 'jquery';
//Object.assign(window, { $: jQuery, jQuery });
//import $ from 'jquery';
//window.$ = $;
import jQuery from 'jquery';
console.log(jQuery);
console.log(jQuery(window));
window.$ = jQuery;
window.jQuery = jQuery;
//window.$ = window.jQuery = require('jquery');
//Object.assign(window, { $: jQuery, jQuery });
//globalThis.$ = jQuery;
//import 'jquery';
//window.$ = jQuery;
//var jQuery = require("jquery")(window);
//window.$=require('jquery')(window);
//const $ = require("jquery")(window);
//const jQuery = require('jquery');
//window.$=jQuery;
Also, I’ll show you my ‘package.json’ with the all the dependencies I’ve installed, with the purpose of trying stuff just as explained in those websites I’ve consulted:
‘package.json’:
{
"type": "module",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"@rollup/plugin-inject": "^5.0.5",
"@tailwindcss/forms": "^0.5.2",
"@tailwindcss/typography": "^0.5.0",
"@types/jquery": "^3.5.30",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.14",
"tailwindcss": "^3.1.0",
"vite": "^4.5.3"
},
"dependencies": {
"@turf/buffer": "^6.5.0",
"@turf/collect": "^6.5.0",
"jquery": "^3.7.1",
"laravel-vite-plugin": "^0.8.0",
"lodash": "^4.17.21",
"lodash.clonedeep": "^4.5.0",
"path": "^0.12.7",
"vite-plugin-html": "^3.2.2"
}
}
I’ve even also tried a lot of different stuff while attempting to make my code to work as expected, so I’m sharing here just the code that wasn’t deleted after all those attempts.
Of course I always run the ‘npm run build’ command just after every change I make in any of those files, to re-bundle the needed assets and expecting them to work properly in the way I’m attempting to. I wonder why this works fine for Lodash, since it works properly in every I’ve coded, without even set the tag with the “type=module” attribute, but no for jQuery.
Here’s some additional documentation I’ve also read:
- https://www.ozzu.com/questions/610724/how-to-use-bundled-javascript-packages-after-compiling-with-vite
- https://vitejs.dev/guide/api-javascript
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
- https://sentry.io/answers/how-do-i-include-a-javascript-file-in-another-javascript-file/
- https://www.jetbrains.com/help/phpstorm/blade-templates-support.html#debugging-blade-templates
- Could not find a declaration file for module ‘module-name’. ‘/path/to/module-name.js’ implicitly has an ‘any’ type
- Why Laravel Vite Directive Not Working in My Project?
If anyone wants to see the whole code, here’s it at my GitLab repo:
https://gitlab.com/leandrocaplan/trabajo-final-seminario-inspt-utn-infoalquiler/-/tree/dev_sail?ref_type=heads
Here it’s also the code of a previous commit, pushed before I’ve been attempting to do all this:
https://gitlab.com/leandrocaplan/trabajo-final-seminario-inspt-utn-infoalquiler/-/tree/74f5235d9d047793fe8fb6570a2b66833ac000ca
Despite I’ve tried a lot of stuff, based on many different websites I’ve consulted, I’m always getting the same results, and I’m not being able to achieve what I’m attempting to, even after days of trying different things. So at this moment, I’m just using the code I previously had, since despite I find it untidy, at least works.
Does anyone have an idea of what’s going wrong? Or what would be the better way to achieve the results I’m looking for?
If there’s any more information needed, please let me know.
Thanks a lot!
Leandro