symfony/asset-mapper
Symfony AssetMapper exposes asset directories, copies them to a public folder with digested/versioned filenames, and can generate an importmap so you can use modern JavaScript modules without a build step.
Install the package via Composer:
composer require symfony/asset-mapper
For Laravel 10+, use the Symfony AssetMapperBundle (if available) or manually integrate the component.
Configure config/asset_mapper.php (create if missing):
return [
'source_dirs' => [
resource_path('assets'), // Your source assets (e.g., `resources/assets`)
],
'public_dir' => public_path('build'), // Output directory (e.g., `public/build`)
'version_strategy' => 'hash', // Use 'hash' for cache-busting filenames
'import_map' => [
'entrypoints' => [
'app' => [
'main.js', // Entry point for importmap
],
],
],
];
Run the mapper via Artisan:
php artisan asset-map:dump
This generates versioned assets (e.g., main.[hash].js) in public/build and an importmap.json.
Use in Blade/Twig:
<!-- Option 1: Directly reference versioned assets -->
<script type="module" src="{{ asset('build/main.[hash].js') }}"></script>
<!-- Option 2: Use importmap (modern JS) -->
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@18",
"lodash": "/build/lodash.[hash].js"
}
}
</script>
First Use Case:
?v=1.2 versioning with auto-generated hashes.config/asset_mapper.php: Customize source directories, output paths, and versioning strategies.asset-map:dump: Generate versioned assets and importmap.asset-map:watch: Auto-rebuild on file changes (dev only).public/build/importmap.json: Auto-generated importmap for ES modules.resources/assets/js/app.js).php artisan asset-map:dump.<script type="module" src="{{ asset('build/app.[hash].js') }}"></script>
version_strategy: 'hash' for cache-busting filenames (e.g., styles.[hash].css).config/asset_mapper.php:
'version_strategy' => 'hash', // or 'timestamp' for dev
mix-manifest.json with the auto-generated importmap.json for ES modules.// app/Helpers/AssetMapperHelper.php
function versioned_asset($path) {
$mapper = app(\Symfony\Component\AssetMapper\AssetMapper::class);
return $mapper->getUrl($path);
}
Usage:
<link rel="stylesheet" href="{{ versioned_asset('css/app.css') }}">
config/asset_mapper.php:
'import_map' => [
'entrypoints' => [
'app' => ['js/app.js'],
'admin' => ['js/admin.js'],
],
'imports' => [
'react' => 'https://esm.sh/react@18',
'lodash' => '/build/lodash.[hash].js',
],
],
asset-map:dump command to regenerate importmap.json after changes.@asset_mapper_importmap
(Requires a custom Blade directive or Twig extension.)imports.| Environment | Strategy | Configuration |
|---|---|---|
| Development | version_strategy: 'timestamp' |
Faster iteration, no cache-busting. |
| Production | version_strategy: 'hash' |
Cache-busting, long-term caching. |
| Hot Reload | asset-map:watch |
Run in dev: php artisan asset-map:watch. |
AssetMapper to add pre-processing (e.g., minification, compression).AssetMapper class:
// app/Services/CustomAssetMapper.php
namespace App\Services;
use Symfony\Component\AssetMapper\AssetMapper;
use Symfony\Component\AssetMapper\AssetMapperInterface;
class CustomAssetMapper extends AssetMapper implements AssetMapperInterface {
public function getUrl(string $path): string {
// Add custom logic (e.g., minify CSS/JS)
$url = parent::getUrl($path);
return str_replace('.css', '.min.css', $url);
}
}
AppServiceProvider:
public function register() {
$this->app->bind(\Symfony\Component\AssetMapper\AssetMapperInterface::class, \App\Services\CustomAssetMapper::class);
}
importmap.json as a replacement for mix-manifest.json for ES modules.
// vite.config.js
export default {
build: {
manifest: false, // Disable Vite's manifest if using importmap
},
};
// app/Providers/BladeServiceProvider.php
Blade::directive('asset_mapper_importmap', function () {
return "<?php echo file_get_contents(public_path('build/importmap.json')); ?>";
});
Usage:
<script type="importmap">
@asset_mapper_importmap
</script>
resources/assets).
'source_dirs' => [
resource_path('assets/css'),
resource_path('assets/js'),
resource_path('assets/images'),
],
<!-- CSS -->
<link rel="stylesheet" href="{{ asset('build/styles.[hash].css') }}">
<!-- Images -->
<img src="{{ asset('build/logo.[hash].png') }}" alt="Logo">
| Issue | Solution |
|---|---|
| Assets not updating | Clear public/build and run php artisan asset-map:dump --force. |
| Importmap missing entries | Ensure entrypoints in config/asset_mapper.php match your JS files. |
| 404 errors for assets | Verify public_dir in config points to a writable directory. |
| Hash collisions | Use version_strategy: 'timestamp' in dev to debug. |
| Circular imports | Update config/asset_mapper.php to include all dependencies in imports. |
| Blade cache conflicts | Clear Blade cache: php artisan view:clear. |
cat public/build/importmap.json
php artisan asset-map:dump --verbose
ls -la public/build/
asset-map:watch in development to catch issues early.source_dirs:
resource_path() or public_path())..assetmapignore (similar to .gitignore).How can I help you explore Laravel packages today?