Chapters
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
¡Bienvenido al fabuloso día 4! Ya estamos creando módulos JavaScript... un término elegante que significa que estamos escribiendo declaraciones import y declaraciones export. Y lo estamos haciendo completamente sin un sistema de compilación. ¡Es hora de bailar felices!
¿Pero qué pasa con los paquetes de terceros? Dirígete a https://npmjs.com y busca un paquete muy importante llamado js-confetti
. Este paquete trata sobre la celebración, que... ¡es exactamente lo que estamos haciendo durante estos 30 días! En el README dice que utilices Yarn para instalarlo. No vamos a hacerlo. En lugar de eso, ve directamente al ejemplo de uso. Cópialo, dirígete a nuestro app.js
... y pégalo:
Show Lines
|
// ... lines 1 - 8 |
import JSConfetti from 'js-confetti'; | |
const jsConfetti = new JSConfetti(); | |
jsConfetti.addConfetti(); | |
Show Lines
|
// ... lines 13 - 15 |
Nota al margen: las declaraciones import
siempre van al principio de tu archivo. Si no lo haces -si haces algo raro como esto-, bueno, puedes hacerlo, pero tu navegador lo subirá al principio cuando ejecute el código de todos modos. Así que evitaremos dar problemas.
Error de módulo JavaScript ausente
Vale: ¿funcionará esto? Probablemente no, porque no hemos instalado nada. ¡Pero vivamos imprudentemente e intentémoslo de todos modos! ¡Error! Un error muy importante:
Error al resolver el especificador de módulo
js-confetti
. Las referencias relativas deben empezar con/
,./
o../
.
Lo que esto está diciendo es que tu navegador encontró una declaración import
... y no tiene ni idea de cómo cargar ese archivo. Si una sentencia import empieza por ./
o ../
, tu navegador sabe cómo manejarlo: busca un archivo relativo a este archivo. Fácil.
Pero si no hay ./
o ../
, se llama módulo desnudo. En ese caso, tu navegador busca una coincidencia en el mapa de importación. Ahora mismo, nuestro mapa de importación tiene el mismo aspecto que antes. En particular, no tenemos una clave js-confetti
. Y por eso obtenemos este error.
Éste es uno de los errores más importantes que verás al codificar con módulos. Y tendrá un aspecto un poco diferente según el navegador que estés utilizando. Firefox, por ejemplo, enuncia este error de forma diferente.
Pero independientemente de la redacción, este error casi siempre significa lo mismo: estás intentando utilizar un paquete de terceros, pero no está instalado.
Instalar paquetes con importmap:require
¿Cómo lo instalamos? ¡Me alegro de que preguntes! Copia el nombre del paquete, gíralo y ejecútalo:
php bin/console importmap:require js-confetti
¡Ya está! Vuelve a girar y... ¡celebración! ¡Funciona! ¡Refrescante locura!
¿Cómo funciona? ¿Karma? Bueno, como es lógico, si ves el código fuente de la página, tenemos una nueva entrada dentro de nuestro importmap
con una clave js-confetti
. Y apunta a un archivo en un directorio assets/vendor/
. Interesante.
Cuando ejecutamos ese comando, en realidad sólo hizo una cosa. Actualizó nuestro archivoimportmap.php
. Añadió esta entrada de aquí:
Show Lines
|
// ... lines 1 - 15 |
return [ | |
Show Lines
|
// ... lines 17 - 20 |
'js-confetti' => [ | |
'version' => '0.11.0', | |
], | |
]; |
Entre bastidores, buscó la última versión y la puso aquí. Y como tenemos un elemento js-confetti
en importmap.php
, significa que vamos a tener una clave js-confetti
correspondiente dentro del mapa de importación de la página.
El directorio assets/vendor/
¿Dónde vive realmente ese archivo? Aquí arriba, en un nuevo directorio assets/vendor/
. Si indagas, aquí está el archivo real que se está cargando.
Dos detalles jugosos sobre este directorio vendor/
. El primero es: se ignora desde Git: puedes ver /assets/vendor/
:
Show Lines
|
// ... lines 1 - 11 |
###> symfony/asset-mapper ### | |
Show Lines
|
// ... line 13 |
/assets/vendor | |
###< symfony/asset-mapper ### |
Al igual que el directorio vendor/
de Composer, no es algo que debas confirmar en tu repositorio.
La segunda es más bien una pregunta: ¿cómo obtengo estos archivos si clono o actualizo un proyecto y faltan algunos o todos los archivos?
Para averiguarlo, vuélvete loco y destruye ese directorio. Muwahahaha. Y ahora, para aumentar nuestra racha temeraria, intenta actualizar la página. ¡Error! ¡Impresionante error!
Falta el activo de vendedor
js-confetti
: prueba a ejecutar el comandoimportmap:install
.
¡Buena idea! Gira e inténtalo:
php bin/console importmap:install
Igual que composer install
, que descarga lo que necesites enassets/vendor/
... y ahora simplemente funciona.
¡Ya está! Al cuarto día, ¡ya hemos resuelto los paquetes de terceros! ¡Ni siquiera necesitamos un directorio node_modules/
gigante! Voy a tener que encontrar otra forma de llenar mi disco duro. ¿Tal vez, más contenedores Docker?
Vale, para la aventura de mañana, vamos a animar nuestro sitio con algo de CSS. ¡Permanece atento!
16 Comments
Hi,
I had the same problem. I resolved it by including js files via CDN and not via importmap :
import { Calendar } from 'https://cdn.skypack.dev/@fullcalendar/core@6.1.10';
David
Hey Brandon and David!
Using the url is a great workaround - it’s so cool that you always have this as an option :).
But, of course, that shouldn’t be needed. I don’t know fullcalendar, but the first thing that looks funny is your import statement. My guess it it should look like what @dbo did, except replace the CDN url with the package name: import { Calendar } from '@fullcalendar/core';
. And so also, install this with importmap:require @fullcalendar/core
Let me know if that helps! And I’m happy to offer any more explanation into what’s going on.
Cheers!
Hi!
Firstly, thanks for the answer and all your effort in this lovely course, but for me don't solve the problem. The only way to solve it is to use the CDN URL.
If I try as you describe:
import { Calendar } from '@fullcalendar/core';
import DayGridPlugin from '@fullcalendar/daygrid/index.js';
document.addEventListener('DOMContentLoaded', function() {
const calendarEl = document.getElementById('calendar')
const calendar = new Calendar(calendarEl, {
plugins: [DayGridPlugin],
initialView: 'dayGridMonth'
})
calendar.render()
})
I have this error in the browser console:
Uncaught TypeError: class constructors must be invoked with 'new'
render https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
Preact 23
handleRenderRequest https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
Pe https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
handleRenderRequest https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
drained https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
tryDrain https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
request https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
render https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
<anonymous> https://localhost/assets/app-f58212e6a0b7bdb970ebb9053d580fdd.js:18
EventListener.handleEvent* https://localhost/assets/app-f58212e6a0b7bdb970ebb9053d580fdd.js:12
core.index-57623a7e3dad789a4c3310e6d9285762.js:7:41883
render https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
Preact 23
handleRenderRequest https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
Pe https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
handleRenderRequest https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
drained https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
tryDrain https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
request https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
render https://localhost/assets/vendor/@fullcalendar/core/core.index-57623a7e3dad789a4c3310e6d9285762.js:7
<anonymous> https://localhost/assets/app-f58212e6a0b7bdb970ebb9053d580fdd.js:18
(Async: EventListener.handleEvent)
<anonymous> https://localhost/assets/app-f58212e6a0b7bdb970ebb9053d580fdd.js:12
In other case, when I use it with the CDN way
import { Calendar } from 'https://cdn.skypack.dev/@fullcalendar/core@6.1.11';
import DayGridPlugin from 'https://cdn.skypack.dev/@fullcalendar/daygrid@6.1.11';
Fix the problem, but I think that this workaround don't be needed if we have the local files.
I don't understand why not works using this local files instead of CDN URL files.
I found that there are some related issues in this GitHub repos, but I'm not sure if is the same problem because is more related to ESM and jsdelivr
https://github.com/fullcalendar/fullcalendar/issues/7474
https://github.com/tattali/CalendarBundle/issues/70
Thanks!
Hi,
Have you tried to importmap:require @fullcalendar/daygrid
and use it as import dayGridPlugin from '@fullcalendar/daygrid'
?
Cheers!
Yes I try it but shows me the same error
Uncaught TypeError: class constructors must be invoked with 'new'
ok... looks not good, in reality this issue blocks this library from asset mapper usage, I tried lot of different ways of connecting it, even with bundle installing, and also using external import link and everything stucks with this error.. the problem is inside the jsDelivr it brake the package internal linking that's why it doesn't work.
Hi
I used asset mapper in my newest project and I have some confusion.
For example my template uses AOS:
I installed it with :
bin/console importmap:require aos
which resulted in a vendor/aos/aos.index.js
For AOS to work properly, I still had to include the aos.css in the header of my template:
<link href="{{ asset('styles/vendors/aos.css') }}" rel="stylesheet">
Is this the way or am I doing something wrong?
Thx for clarification. <3
Seem it is the way to go: https://symfonycasts.com/screencast/asset-mapper/vendor-css
Good catch! I hope this helps you
Cheers!
Guess I should watch the whole course ;)
@weaverryan explains it here on the example of tom-select: https://symfonycasts.com/screencast/last-stack/ux-packages
php bin/console importmap:require tom-select/dist/css/tom-select.default.css
Hey Blanx,
Haha, that's a good idea ;)
Thanks for sharing a better solution with others!
Cheers!
It turns out for me after adding js confetti javascript and the required library installed with importmap:require, one more php bin/console asset-map:compile was required for app.js (on browser side) to be loaded at last version...
Hey @Leonard_Bira!
Weird! Hmm. Well, asset-map:compile
should only need to be run when you're deploying to production. In dev mode, if your browser makes a request to /assets/app-abcd1234.js
, that physical file doesn't exist. Instead, the request is handled by Symfony and it returns the file.
However, if you DO run asset-map:compile
on your local machine, then, definitely, if you make any changes to your source files, those won't be seen. The public/assets
directory is kind of "stuck" with the old code. If this was the case for you, you can delete public/assets/
entirely and allow Symfony to serve the files, which should then always contain the latest versions of the code :).
Cheers!
Hello, Thanks for the nice tutorials. I'm trying to get Asset-mapper implemented in my own project instead of WebPack, but for something as simple as fontawesome I'm stumped for some raison. I can import a fortawesome third-party package and I see JS and CSS included, but they themselves point to a webfont that I put in the /assets folder aswell, but they arn't visible on my Dev when running the site. getting 404's on the webfonts.
Any help or hints on how to achieve this seemingly simple task?
Thanks !
Hey @Mathias-VdB!
Let's get you unlocked so you can enjoy AssetMapper!
Ok, so I assume you ran something like importmap:require @fortawesome/fontawesome-free/css/fontawesome.min.css
and now have an entry like this in your importmap.php
file? If so, remove that, and try this instead:
php bin/console importmap:require @fortawesome/fontawesome-free/css/all.css
Let me know if that works (it should, I just tried it). Tbh, I love FontAwesome, but their install has always confused me. I don't know what this fontawesome.min.css
file is exactly: it's the CSS, but it lacks the FontFace that the all.css
has:
@font-face {
/* ... */
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
AssetMapper is pretty cool in this regard. When you require all.css
, it sees the url()
inside this file and actually downloads the font files! So with this, you'll notice (in assets/vendor/...
), that you have a webfonts
folder with these items.
Also, FontAwesome recommends you install them by including a "kit" - which is just a bit of JavaScript and then you can control what icons go in there. That's what I've been doing lately anyway.
Let me know if this helps!
Cheers!
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "4.x-dev", // 4.x-dev
"doctrine/doctrine-bundle": "^2.10", // 2.12.x-dev
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.4.x-dev
"doctrine/orm": "^2.16", // 2.18.x-dev
"knplabs/knp-time-bundle": "dev-main", // dev-main
"pagerfanta/doctrine-orm-adapter": "4.x-dev", // 4.x-dev
"pagerfanta/twig": "4.x-dev", // 4.x-dev
"symfony/asset": "6.4.*", // 6.4.x-dev
"symfony/asset-mapper": "6.4.*", // 6.4.x-dev
"symfony/console": "6.4.x-dev", // 6.4.x-dev
"symfony/dotenv": "6.4.x-dev", // 6.4.x-dev
"symfony/flex": "^2", // 2.x-dev
"symfony/form": "6.4.x-dev", // 6.4.x-dev
"symfony/framework-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/monolog-bundle": "^3.0", // dev-master
"symfony/runtime": "6.4.x-dev", // 6.4.x-dev
"symfony/security-csrf": "6.4.x-dev", // 6.4.x-dev
"symfony/stimulus-bundle": "2.x-dev", // 2.x-dev
"symfony/twig-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/ux-autocomplete": "2.x-dev", // 2.x-dev
"symfony/ux-live-component": "2.x-dev", // 2.x-dev
"symfony/ux-turbo": "2.x-dev", // 2.x-dev
"symfony/ux-twig-component": "2.x-dev", // 2.x-dev
"symfony/validator": "6.4.x-dev", // 6.4.x-dev
"symfony/web-link": "6.4.*", // 6.4.x-dev
"symfony/yaml": "6.4.x-dev", // 6.4.x-dev
"symfonycasts/dynamic-forms": "dev-main", // dev-main
"symfonycasts/tailwind-bundle": "dev-main", // dev-main
"tales-from-a-dev/flowbite-bundle": "dev-main", // dev-main
"twig/extra-bundle": "^2.12|^3.0", // 3.x-dev
"twig/twig": "^2.12|^3.0" // 3.x-dev
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.6.x-dev
"phpunit/phpunit": "^9.5", // 9.6.x-dev
"symfony/browser-kit": "6.4.*", // 6.4.x-dev
"symfony/css-selector": "6.4.*", // 6.4.x-dev
"symfony/debug-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/maker-bundle": "^1.51", // dev-main
"symfony/panther": "^2.1", // v2.1.1
"symfony/phpunit-bridge": "7.1.x-dev", // 7.1.x-dev
"symfony/stopwatch": "6.4.x-dev", // 6.4.x-dev
"symfony/web-profiler-bundle": "6.4.x-dev", // 6.4.x-dev
"zenstruck/browser": "1.x-dev", // 1.x-dev
"zenstruck/foundry": "^1.36" // 1.x-dev
}
}
Hello,
I'm trying to get FullCalendar to work on my site. I too am switching from WebPack to Asset-Mapper, but I'm struggling to see where I import Full Calendar and how with its plugins. In bootstrap.js I have:
import { Calendar } from "./vendor/@fullcalendar/core/index.js";
app.register('calendar', Calendar)
And then in my Stimulus controller I have
import { Calendar } from '@fullcalendar/core/index.js';
import dayGridPlugin from '@fullcalendar/daygrid/index.js';
const calendarEl = document.getElementById('calendar');
But I get the error:
TypeError: class constructors must be invoked with 'new'
Which I've determined is from me not getting my imports correct, because all this was working when I was using WebPack, nothing else has changed. I don't see a lot of documentation on FullCalendar and Asset-Mapper.
I've installed FullCalendar by running ./bin/console importmap:require fullcalendar
And it seems to have installed everything I need:
13 new items (fullcalendar, @fullcalendar/core/index.js, @fullcalendar/interaction/index.js,
Any help is much appreciated, thank you!