AssetMapper was introduced in Symfony 6.3 as a new & modern way to manage JavaScript & CSS assets with zero build or external dependencies like Node. In Symfony 6.4, we've improved it with a number of features you asked for. The component is now also stable and protected by our BC promise!

Vendor Files Downloaded Locally

Ryan Weaver
Contributed by Ryan Weaver in #51786

In Symfony 6.3, when you used the importmap:require command to "install" a 3rd-party package, the final code referenced that file on the jsDelivr CDN. You could pass a --download option to download the file locally, but it wasn't the default.

In Symfony 6.4, the behavior is simpler: when you run importmap:require, the file is always downloaded locally. Files are downloaded into an assets/vendor/ directory, which is ignored by default in the .gitignore file via the Flex recipe. This is important because it allows the use of a CSP (Content Security Policy) that only allows assets to be loaded from your own domain.

To download the files and populate the directory, run:

1
$ php bin/console importmap:install

This works very-much like composer install.

CSS Support

Ryan Weaver
Contributed by Ryan Weaver in #51543

In Symfony 6.4, you can now import CSS files from JavaScript files:

1
2
// assets/app.js
import './styles/app.css';

In base.html.twig, the {{ importmap() }} function will output a link tag for each CSS file it finds. And the system is smart: crawling every JavaScript file imported by your entrypoint (app.js) looking for CSS imports. Importing CSS isn't normally allowed in JavaScript modules, but AssetMapper makes it possible by adding a "noop" entry to your importmap for each CSS file.

For 3rd party CSS files, you can use the importmap:require command:

1
$ php bin/console importmap:require bootstrap/dist/css/bootstrap.min.css

Then import it:

1
2
// assets/app.js
import 'bootstrap/dist/css/bootstrap.min.css';

Finally, while not technically part of Symfony 6.4, support for Sass and Tailwind were added thanks to symfonycasts/sass-bundle and symfonycasts/tailwind-bundle. You can even try using TypeScript with AssetMapper thanks to sensiolabs/typescript-bundle.

importmap:audit & importmap:outdated

Hubert Lenoir Maelan LE BORGNE
Contributed by Hubert Lenoir and Maelan LE BORGNE in #51650 and #51845

When relying on 3rd-party JavaScript packages, it's important to learn about any potential security vulnerabilities as soon as possible. In Symfony 6.4, the importmap:audit command was added to do this:

1
$ php bin/console importmap:audit

This uses GitHub's advisory database to check for any known security issues in the packages you're using. If any are found, you'll see a clear report and the command will exit with a non-zero exit code.

Additionally, to check which packages have newer versions available, run:

1
$ php bin/console importmap:outdated

This works just like composer outdated. Packages can be updated with:

1
$ php bin/console importmap:update <package-name>

Preloading & Entrypoints

Ryan Weaver
Contributed by Ryan Weaver in #51543

One important part of using JavaScript modules is preloading the files you need so that your browser can download them as soon as possible. In Symfony 6.3, you could add a preload option to any entry in importmap.php to do this.

In Symfony 6.4, the mechanism is simpler and more robust. When calling {{ importmap('app') }}, AssetMapper will find all JavaScript files that app.js imports (recursively) and preload them. This means that every JavaScript file needed to run your code will be preloaded with no extra work.

Ryan Weaver
Contributed by Ryan Weaver in #51829

The <link rel="stylesheet"> tags on your page are "render-blocking resources": they block the rendering of your page until they are downloaded and parsed. So, the sooner we can tell the browser to download them, the better.

In Symfony 6.4, if you install the symfony/web-link component, AssetMapper will automatically add Link headers to your response that tell the browser to preload all CSS files that will eventually be rendered via the {{ importmap() }} function.

Asset Compiling Performance Improvements

Simon André
Contributed by Simon André in #52156

AssetMapper doesn't require a build step, but it does still crawl through your CSS and JavaScript files to find imports. AssetMapper has always had an internal cache to avoid doing this on every request. But in Symfony 6.4, this was greatly improved by avoiding the need to crawl non-CSS and JavaScript files. Images, fonts, etc are now served directly without any overhead during development or while running asset-map:compile.

Published in #Living on the edge