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!
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 SubscribeIn our code, we get to use import
statements with relative paths, ES6 classes: everything we're used to. It's business as usual. Except, how can we use third-party packages?
As we saw earlier, we could import things via a full URL, like import _ from
, and I'll paste in the CDN URL that we used earlier. With that done, the rest is normal: add _.camelCase()
to the log.
Show Lines
|
// ... line 1 |
import _ from 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm'; | |
Show Lines
|
// ... lines 3 - 4 |
console.log(_.camelCase(mix.describe())); |
If we refresh and check the console... that works. But I don't like it! I don't want to have to include this crazy URL everywhere I use lodash
. And what happens if we upgrade lodash... and I need to change the URL in 10 different files? Lame!
importmap:require to Fetch Node Packages
If we were using a build system, like Webpack, we could just say:
yarn add lodash
or
npm install lodash
We're not using yarn
or npm
, but we can do nearly the same thing. Over in the terminal, open a new tab, and run php bin/console importmap:require
followed by the name of the NPM package we want: lodash
:
php bin/console importmap:require lodash
Done! It added lodash
to importmap.php
and tells us we can use the package as usual. This means we can say import _ from 'lodash'
... and everything will work fine.
Show Lines
|
// ... line 1 |
import _ from 'lodash'; | |
Show Lines
|
// ... lines 3 - 6 |
How? When we ran the command, it made one tiny change: it added this section to importmap.php
. And as cool as this is, it's not magic. Behind the scenes, the command went to the JSDelivr CDN, found the latest version of lodash
, then added the lodash
key set to that URL.
If you head over and look at the page source... no surprise! We have a new lodash
entry inside the importmap
! When our browser sees import _ from 'lodash'
, it looks inside the importmap
for lodash
, finds this URL, and downloads it from there. Our browser is the hero!
Telling your Editor about the Packages
One bummer is that we don't get autocompletion in our editor. It says "Module not installed". And if I say _.
... it doesn't really work. It's autocompleting camelCase
... but only because I'm using that down here.
I hope this will be better-supported in PhpStorm soon. There is a workaround, but it's a bit manual. Copy the package, go into base.html.twig
and add a temporary <script>
tag that points to this. Hit "alt" + "enter" and select "Download library". This downloads that into the "External Libraries" section down here: /lodash
.
Ok, remove that script
tag. Back in app.js
, it's still going to underline the import as if it doesn't know what it is, but it does autocomplete when we use _.
something. For example, tail()
is from lodash
.
Updating Packages
What about updating the versions of packages inside importmap
? Whelp, there's a command for that!
php bin/console importmap:update
That will loop through every package and update its URL to the latest version. This is already the latest version... but if we change it to .19
... then run the update
command... it moves back up to .21
. The command could be more flexible - like by allowing you to update just one package, or by having some version constraints - and those things may be added in the future.
Show Lines
|
// ... lines 1 - 15 |
return [ | |
Show Lines
|
// ... lines 17 - 20 |
'lodash' => [ | |
'url' => 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm', | |
], | |
]; |
Downloading Packages Locally
Finally, if you don't want to rely on the CDN, you don't have to. To avoid it, when you require the package - or any time later - pass the --download
option:
php bin/console importmap:require lodash --download
In importmap.php
, this still shows the source URL to the CDN, but it downloaded that file into an assets/vendor/
directory. This downloaded_to
points to the logical path for that file.
Show Lines
|
// ... lines 1 - 15 |
return [ | |
Show Lines
|
// ... lines 17 - 20 |
'lodash' => [ | |
'downloaded_to' => 'vendor/lodash.js', | |
Show Lines
|
// ... line 23 |
], | |
]; |
The result? When we go over and refresh.... and "View Page Source"... the importmap
now points to the local file! We're no longer relying on the CDN.
But... now what? Do we commit this vendor/lodash.js
file? The answer is... yes. At least at this moment, that's the only way to version that file and keep it in your repository.
So even without npm or yarn, we can use any npm package we want. Woo! But sometimes, instead of importing an entire package, we may only want to import a specific file. Let's talk about how we can do that next.
19 Comments
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.ts
extension, right? Probably you need to add it directly with the importmap:require
command 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-bundle
that will help with TypeScript integration. Please, read their docs too: https://symfony.com/bundles/AssetMapperTypeScriptBundle/current/index.html
I 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:
Uncaught TypeError: The specifier “@nameOfOrganization/bootstrap-theme-app-backend/dist/assets/plugins/global/plugins.bundle.css” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.
To get rid of that, I would have to add something like this to my importmap.php:
'@nameOfOrganization/bootstrap-theme-app-backend/dist/assets/plugins/global/plugins.bundle.css' => [
'path' => './assets/vendor/@nameOfOrganization/bootstrap-theme-app-backend/dist/assets/plugins/global/plugins.bundle.css',
'type' => 'css',
],
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):
"postinstall": "cp -R node_modules/@nameOfOrganization assets/vendor/@nameOfOrganization"
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 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?
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):
// Mermaid (https://mermaid.js.org/)
console.log('AssetMapper: Importing `mermaid` ...');
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
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 the app.js
-file to this:
// Mermaid (https://mermaid.js.org/)
console.log('AssetMapper: Importing `mermaid` ...');
import mermaid from 'mermaid';
mermaid.initialize({ startOnLoad: true });
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 :)
I love the Symfony's assetMapper
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 mermaid
locally 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 from mermaid.core.mjs
. That is not quite the file you were using before. Why are there 2 files in that package - mermaid.core.mjs
vs mermaid.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=files
It should be:
php bin/console importmap:require mermaid/dist/mermaid.esm.min.mjs
Then use:
import mermaid from 'mermaid/dist/mermaid.esm.min.mjs';
I'm not sure if it's right or wrong, but the mermaid
package advertises the mermaid.core.mjs
as the main "module" file, which is why that's what you get when you importmap:require
the package.
Let me know if that helps! Cheers!


Hey Ryan-friend :-)
Since you asked,
So, when you try to import mermaid locally and it doesn't work, is there an error? Or just nothing?
I tried to understand what is happening and compare the different cases (see below).
mermaid (only)
(download of a lot of dependencies)
$ ./bin/console importmap:require mermaid
app.js
import mermaid from 'mermaid';
Error in browser
GET https://127.0.0.1:8000/npm/mermaid@10.7.0/dist/flowDiagram-v2-d21afba7.js/+esm
mermaid/dist/mermaid.esm.min.mjs
(no download of dependencies)
$ ./bin/console importmap:require mermaid/dist/mermaid.esm.min.mjs
app.js
import mermaid from 'mermaid/dist/mermaid.esm.min.mjs';
Error in browser
GET https://127.0.0.1:8000/npm/mermaid@10.7.0/dist/flowDiagram-v2-7efa11b6.js/+esm
You can find flowDiagram-v2-7efa11b6.js
in the files under files.
mermaid/dist/mermaid.min.mjs
(no download of dependencies)
$ ./bin/console importmap:require mermaid/dist/mermaid.min.mjs
app.js
import mermaid from 'mermaid/dist/mermaid.min.mjs';
Error in browser
Uncaught SyntaxError: ambiguous indirect export: mermaid app-503f2378f269ac781809a16ef96a4492.js:53:9
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, wowjs
is 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 global WOW
variable). 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 from base.html.twig
and 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!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "^4.0", // v4.2.0
"doctrine/doctrine-bundle": "^2.7", // 2.10.0
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.4
"doctrine/orm": "^2.12", // 2.15.2
"knplabs/knp-time-bundle": "^1.18", // v1.20.0
"pagerfanta/doctrine-orm-adapter": "^4.0", // v4.1.0
"pagerfanta/twig": "^4.0", // v4.1.0
"stof/doctrine-extensions-bundle": "^1.7", // v1.7.1
"symfony/asset": "6.3.*", // v6.3.0
"symfony/asset-mapper": "6.3.*", // v6.3.0
"symfony/console": "6.3.*", // v6.3.0
"symfony/dotenv": "6.3.*", // v6.3.0
"symfony/flex": "^2", // v2.3.1
"symfony/framework-bundle": "6.3.*", // v6.3.0
"symfony/http-client": "6.3.*", // v6.3.0
"symfony/monolog-bundle": "^3.0", // v3.8.0
"symfony/proxy-manager-bridge": "6.3.*", // v6.3.0
"symfony/runtime": "6.3.*", // v6.3.0
"symfony/stimulus-bundle": "^2.9", // v2.9.1
"symfony/twig-bundle": "6.3.*", // v6.3.0
"symfony/ux-turbo": "^2.9", // v2.9.1
"symfony/web-link": "6.3.*", // v6.3.0
"symfony/yaml": "6.3.*", // v6.3.0
"twig/extra-bundle": "^2.12|^3.0", // v3.6.1
"twig/twig": "^2.12|^3.0" // v3.6.1
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.4
"symfony/debug-bundle": "6.3.*", // v6.3.0
"symfony/maker-bundle": "^1.41", // v1.49.0
"symfony/stopwatch": "6.3.*", // v6.3.0
"symfony/web-profiler-bundle": "6.3.*", // v6.3.0
"zenstruck/foundry": "^1.21" // v1.33.0
}
}
Any idea how to use FosJsRouting ?