importmap:require - Libs JS de terceros
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeEn nuestro código, podemos utilizar declaraciones import con rutas relativas, clases ES6: todo a lo que estamos acostumbrados. Es lo de siempre. Excepto, ¿cómo podemos utilizar paquetes de terceros?
Como vimos antes, podemos importar cosas a través de una URL completa, como import _ from, y yo pegaré la URL CDN que usamos antes. Hecho esto, el resto es normal: añade _.camelCase() al registro.
| // ... line 1 | |
| import _ from 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm'; | |
| // ... lines 3 - 4 | |
| console.log(_.camelCase(mix.describe())); |
Si refrescamos y comprobamos la consola... funciona. Pero no me gusta! No quiero tener que incluir esta URL loca en todas partes donde utilice lodash. ¿Y qué pasa si actualizamos Lodash... y tengo que cambiar la URL en 10 archivos diferentes? ¡Qué pena!
importmap:require para obtener paquetes de nodos
Si utilizáramos un sistema de compilación, como Webpack, podríamos simplemente decir
yarn add lodash
o
npm install lodash
No estamos utilizando yarn ni npm, pero podemos hacer casi lo mismo. En el terminal, abre una nueva pestaña y ejecutaphp bin/console importmap:require seguido del nombre del paquete NPM que queremos: lodash:
php bin/console importmap:require lodash
¡Listo! Ha añadido lodash a importmap.php y nos dice que podemos utilizar el paquete como de costumbre. Esto significa que podemos decir import _ from 'lodash'... y todo funcionará correctamente.
| // ... line 1 | |
| import _ from 'lodash'; | |
| // ... lines 3 - 6 |
¿Cómo? Cuando ejecutamos el comando, hizo un pequeño cambio: añadió esta sección a importmap.php. Y aunque esto sea genial, no es magia. Entre bastidores, el comando fue a la CDN de JSDelivr, encontró la última versión de lodash, y luego añadió el conjunto de claves lodash a esa URL.
Si te acercas y miras la fuente de la página... ¡no hay sorpresa! ¡Tenemos una nueva entrada lodashdentro de la importmap! Cuando nuestro navegador ve import _ from 'lodash', busca lodash dentro de importmap, encuentra esta URL y la descarga desde allí. ¡Nuestro navegador es el héroe!
Informar a tu editor sobre los paquetes
Una pega es que no tenemos autocompletado en nuestro editor. Dice "Módulo no instalado". Y si digo _.... en realidad no funciona. Autocompleta camelCase... pero sólo porque lo estoy usando aquí abajo.
Espero que PhpStorm lo soporte mejor pronto. Hay una solución, pero es un poco manual. Copia el paquete, entra en base.html.twig y añade una etiqueta temporal<script> que apunte a esto. Pulsa "alt" + "enter" y selecciona "Descargar biblioteca". Esto lo descarga en la sección "Bibliotecas externas" de aquí abajo: /lodash.
Vale, elimina la etiqueta script. De nuevo en app.js, seguirá subrayando la importación como si no supiera lo que es, pero autocompleta cuando usamos _. algo. Por ejemplo, tail() es de lodash.
Actualizar paquetes
¿Qué pasa con la actualización de las versiones de los paquetes dentro de importmap? Vaya, ¡hay un comando para eso!
php bin/console importmap:update
Eso hará un bucle a través de cada paquete y actualizará su URL a la última versión. Ésta ya es la última versión... pero si la cambiamos a .19... y luego ejecutamos el comando update... retrocede hasta .21. El comando podría ser más flexible -como permitirte actualizar sólo un paquete, o tener algunas restricciones de versión- y esas cosas podrían añadirse en el futuro.
| // ... lines 1 - 15 | |
| return [ | |
| // ... lines 17 - 20 | |
| 'lodash' => [ | |
| 'url' => 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm', | |
| ], | |
| ]; |
Descargar paquetes localmente
Por último, si no quieres depender de la CDN, no tienes por qué hacerlo. Para evitarlo, cuando necesites el paquete -o en cualquier momento posterior- pasa la opción --download:
php bin/console importmap:require lodash --download
En importmap.php, esto sigue mostrando la URL de origen a la CDN, pero descarga ese archivo en un directorio assets/vendor/. Este downloaded_to apunta a la ruta lógica de ese archivo.
| // ... lines 1 - 15 | |
| return [ | |
| // ... lines 17 - 20 | |
| 'lodash' => [ | |
| 'downloaded_to' => 'vendor/lodash.js', | |
| // ... line 23 | |
| ], | |
| ]; |
¿Cuál es el resultado? Cuando vamos y actualizamos .... y "Vemos la fuente de la página"... ¡el importmapapunta ahora al archivo local! Ya no dependemos de la CDN.
Pero... ¿y ahora qué? ¿Confirmamos este archivo vendor/lodash.js? La respuesta es... sí. Al menos en este momento, esa es la única forma de versionar ese archivo y mantenerlo en tu repositorio.
Así que, incluso sin npm ni yarn, podemos utilizar cualquier paquete npm que queramos. Pero a veces, en lugar de importar un paquete entero, puede que sólo queramos importar un archivo concreto. Hablemos de cómo podemos hacerlo a continuación.
19 Comments
Any idea how to use FosJsRouting ?
Hey @ahmedbhs!
It doesn't look like there's documentation yet but it looks like this could work?
And how to replace the encore_entry_link_tag() if your entry pooint is mapped to sass file?
I would like to add a typescript Library with php bin/console importmap:require zod
It adds a zod.index.js file in vendo/zod, but no type declarations at all...
Is there any solution to this?
Hey CR,
Hm, sorry, I don't use TypeScript so it's difficult to suggest you something in this case. Does that zod package provide any type of declaration in sources? IIRC it should be a file with
.d.tsextension, right? Probably you need to add it directly with theimportmap:requirecommand as well. Otherwise, probably you need to install it with NPM so that you have it in your project.Also, please, take a look at the official docs: https://symfony.com/doc/current/frontend/asset_mapper.html#using-typescript - I see there should be a separate
sensiolabs/typescript-bundlethat will help with TypeScript integration. Please, read their docs too: https://symfony.com/bundles/AssetMapperTypeScriptBundle/current/index.htmlI hope this helps.
Cheers!
So this is the first time I am using AssetMapper instead of WebpackEncore and the idea and implementation sounds great. Using public npm packages like bootstrap works without any problem.
But how can I use a private npm package?
I yarn-added the private package, so that it is in the node_modules directory, but obviously - as expected - I can still not use it in the app,js.
If I try to do so, I get the error in my console:
To get rid of that, I would have to add something like this to my importmap.php:
But that would only work if the directory would be inside asstes/vendor, but it is inside node_modules and I can not point to node_modules, or can i somehow?
Do I still need webpack encore for my usecase, or is there a way to use private npm packages with AssetMapper?
Edit:
What I do right now, as a workaround is that I added a postinstall one-liner in the package.json that copies from node_modules into assetss/vendor (for that specific package):
But I guess there might be a more elegant solution?
Hey TristanoMilano,
That's an interesting workaround, thanks for sharing it with others. I personally didn't have experience working with private npm packages, your solution seems valid to me. Actually, you said:
But actually I suppose it should work, no? You just need to add that new path to the configuration, see https://symfony.com/doc/current/frontend/asset_mapper.html#framework-asset-mapper-paths - probably something that worth to try.
I hope that helps!
Cheers!
Dear SymfonyCast-friends,
I love the Symfony's assetMapper. Thank you for the videos! I do have some issues with a package called Mermaid and wanted to ask you for your ideas:
This is what I do have currently in my
app.js-file (and is working wonderful):The disadvantage of this style is that you need to have on production a connection to the cdn-server. But you are not hosting the packages in your own environment. This is why is tried in terminal this
./bin/console importmap:require mermaid(which loads also a lot of dependencies) and updated theapp.js-file to this:Problem: Mermaid is now not working anymore.
Question: Am I using the AssetMapper wrong or is this just not possible with this package?
Thanks for any support!
Cheers
Tim
Hey @Tim-K friend :)
Yay!
What you did with Mermaid looks good to me. There are some edge-case packages that, for one reason or another (e.g. some small mistake in how they package themselves) don't work as easily as we'd want with AssetMapper. So, when you try to import
mermaidlocally and it doesn't work, is there an error? Or just nothing?Btw, this is the raw file that we're grabbing for
mermaid- https://cdn.jsdelivr.net/npm/mermaid@10.7.0/ esm - notice how, on top, it says it's built frommermaid.core.mjs. That is not quite the file you were using before. Why are there 2 files in that package -mermaid.core.mjsvsmermaid.esm.min.mjs? I have no idea - maybe you will :). Anyway, to get the exact file you were using before, you can browser for it here - https://www.jsdelivr.com/package/npm/mermaid?tab=filesIt should be:
Then use:
I'm not sure if it's right or wrong, but the
mermaidpackage advertises themermaid.core.mjsas the main "module" file, which is why that's what you get when youimportmap:requirethe package.Let me know if that helps! Cheers!
Hey Ryan-friend :-)
Since you asked,
I tried to understand what is happening and compare the different cases (see below).
mermaid (only)
(download of a lot of dependencies)
app.js
Error in browser
mermaid/dist/mermaid.esm.min.mjs
(no download of dependencies)
app.js
Error in browser
You can find
flowDiagram-v2-7efa11b6.jsin the files under files.mermaid/dist/mermaid.min.mjs
(no download of dependencies)
app.js
Error in browser
Maybe this is the edge case you mentioned above with "how they pack themselves" and AssetMapper is not yet ready to deal with that and I should just stick to the CDN-download "on the fly" for the moment?
Btw: all other external imports that i am using are working fine ... it is just this making trouble.
Let me know if you have another idea!
Tim
Hey @Tim-K!
I looked into this more deeply and ... you found a bug! https://github.com/symfony/symfony/issues/53145 A rare case where we're not properly dealing with an import format in a specific library. In this case, it's because Mermaid is using dynamic imports, which is allowed, but we're not handling yet. For normal imports to paths inside the same package, jsdelivr just combines them all together, which makes life simpler: just one file for us to download. For dynamic imports, they can't do this. What we're going to need to do is parse out those dynamic imports and download these files. There is a precedent for this already in AssetMapper with CSS files that reference images and fonts, so it's just a "thing" we need to get done.
For now, stick with your CDN solution. You could also download the missing files, put them into
assets/vendor/mermaid/dist/...and commit them. That's not a super solution... and you'll want to make sure have all the files you need, but if you really need to avoid the CDN, that's a workaround.Cheers!
Exciting :-)
I will follow the progress on github and will stick with the CDN-version in the meantime.
Thanks for the support.
Cheers and my regard to Grand Rapids ;-)
Tim
Hello,
Thanks for the course.
I want to add fontawesome-free, I installed the js and the css (fontawesome-free/js/all.min.js and fontawesome-free/css/all.min.css). 1.0.4 version is installed instead of the latest 6.5.1 and the icons displayed as a special caracters. Can you help me to resolve the problem.
Thanks.
Hey Mouloud,
Hm, difficult to say for sure, but I will try to give you some ideas you could debug.
Please, make sure you're trying to use free icons from Font Awesome, even if you have access to the paid ones - it's easier to debug with free icons first. Also, double-check the docs that you're using the correct CSS classes for the icons. And last but not least, load the page in the browser that uses your icons, and check that the fronts are included in the source code. You can also follow the included links to make sure they are not 404 and lead to real files.
I hope that helps!
Cheers!
Hello Victor,
Thanks for your replay and for the debug steps. I resolved my problem by using "@fortawesome/fontawesome-free/..." instead of "fontawesome-free/..." to import my packages with a latest version. I think that in the second case I imported a wrong library !?.
Have a nice day :)
Hey Mouloud,
Thanks for sharing your solution with others! I'm glad you were able to fix it yourself :)
Oh yeah, that's a totally different library. https://www.npmjs.com/package/@fortawesome/fontawesome-free this one is what you need I suppose, make sure it's popular and lead to the source repo of the project on GitHub
Cheers!
Thanks for the video, I am building a project:
First I have run:
php bin/console importmap:require wowjs --download
php bin/console importmap:require swiper --download
it has added files under vendor and I can see them on page source code
I am importing:
import WOW from 'wowjs';
import Swiper from 'swiper';
but giving error:
Uncaught SyntaxError: ambiguous indirect export: WOW
Am I missing something? Thanks
Hey @Farab!
Hmm. I just checked it,
wowjsis the first library I've seen that doesn't seem to support being used as a module. They don't export any values... and it doesn't look like you can use it in the "normal" way either (where it sets a globalWOWvariable). That library's last release was in 2016... so I think it's just too old. You can still probably point to its CDN URL manually frombase.html.twigand rely on the global variable... but it might be better to find something newer.Cheers!
Thanks @weaverryan ,
I end up using the older way but thought to validate if I am missing something, Thanks again :)
You & your team is Awesome!
"Houston: no signs of life"
Start the conversation!