Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Asset Laravel Package

symfony/asset

Symfony Asset Component handles generating URLs for web assets (CSS, JS, images) and managing versioning for cache busting. Works with different base paths/hosts and package setups to produce consistent, deploy-friendly asset links.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

  1. Install the package:
    composer require symfony/asset
    
  2. Register the service (Laravel 8+ auto-discovers, but explicit binding is recommended):
    // app/Providers/AppServiceProvider.php
    use Symfony\Component\Asset\Packages;
    use Symfony\Component\Asset\PathPackage;
    
    public function register()
    {
        $this->app->singleton(Packages::class, function () {
            return new Packages([
                new PathPackage(public_path(), true), // Enable fingerprinting
            ]);
        });
    }
    
  3. First use case: Replace hardcoded asset paths in Blade:
    @inject('asset', 'Symfony\Component\Asset\Packages')
    <link href="{{ $asset->getUrl('css/app.css') }}" rel="stylesheet">
    
    Output (with fingerprinting): /css/app.abc123.css

Where to Look First

  • Symfony Docs (official guide)
  • PathPackage (for static assets) and JsonManifestPackage (for Laravel Mix/Vite)
  • Packages class (combines multiple strategies)
  • Version strategies: StaticVersionStrategy (no versioning), FingerprintVersionStrategy (file hashing), JsonManifestVersionStrategy (Mix/Vite manifests)

Implementation Patterns

Core Workflows

1. Basic Asset URL Generation

// In a controller or service
$assetPackage = app(Packages::class);
$url = $assetPackage->getUrl('css/app.css'); // /css/app.abc123.css

2. Laravel Mix/Vite Integration

use Symfony\Component\Asset\JsonManifestPackage;

$manifestPackage = new JsonManifestPackage(
    public_path('mix-manifest.json'),
    'app',
    true // Enable fingerprinting
);
$assetPackage = new Packages([$manifestPackage]);

3. CDN or Custom Base URLs

$package = new PathPackage(public_path(), false, [
    'base_urls' => ['https://cdn.example.com'],
]);
$assetPackage = new Packages([$package]);
// Output: https://cdn.example.com/css/app.css

4. Dynamic Paths (Multi-Tenant/SaaS)

$tenantId = 'tenant1';
$package = new PathPackage(public_path("tenants/{$tenantId}"), true);
$assetPackage = new Packages([$package]);
// Output: /tenants/tenant1/css/app.abc123.css

Integration Tips

  • Blade Directives: Create a custom Blade directive for cleaner syntax:

    // app/Providers/BladeServiceProvider.php
    Blade::directive('asset', function ($expression) {
        return "<?php echo app('Symfony\Component\Asset\Packages')->getUrl({$expression}); ?>";
    });
    

    Usage:

    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    
  • Middleware for Environment-Specific Behavior:

    // app/Http/Middleware/AssetVersioning.php
    public function handle($request, Closure $next)
    {
        if (app()->environment('production')) {
            $this->app->singleton(Packages::class, fn() =>
                new Packages([new PathPackage(public_path(), true)])
            );
        } else {
            $this->app->singleton(Packages::class, fn() =>
                new Packages([new PathPackage(public_path(), false)])
            );
        }
        return $next($request);
    }
    
  • Caching Packages: Cache the Packages instance in Laravel’s cache:

    $this->app->singleton(Packages::class, function () {
        return Cache::remember('asset.packages', now()->addHours(1), function () {
            return new Packages([new PathPackage(public_path(), true)]);
        });
    });
    

Gotchas and Tips

Pitfalls

  1. Fingerprinting Overhead:

    • Enabling true in PathPackage triggers file hashing, which adds ~10-20ms per request during generation (but caches after first use).
    • Fix: Disable in dev environments or use JsonManifestPackage for pre-hashed assets.
  2. Manifest File Missing:

    • JsonManifestPackage throws exceptions if mix-manifest.json is missing.
    • Fix: Use non_strict: true in the constructor or handle the exception:
      try {
          $package = new JsonManifestPackage(public_path('mix-manifest.json'), 'app', true);
      } catch (JsonException $e) {
          $package = new PathPackage(public_path('js'), false);
      }
      
  3. Base URL Conflicts:

    • Mixing base_urls with absolute paths can cause double-encoding (e.g., https://cdn.example.com//css/app.css).
    • Fix: Ensure base_urls are absolute and end with /:
      'base_urls' => ['https://cdn.example.com/'],
      
  4. Case Sensitivity:

    • Fingerprinting generates lowercase hashes (e.g., app.abc123.css), which may break case-sensitive filesystems (e.g., Docker on Linux).
    • Fix: Normalize paths before hashing or use JsonManifestPackage for consistency.

Debugging Tips

  • Verify Fingerprinting:

    $package = new PathPackage(public_path(), true);
    $url = $package->getUrl('css/app.css');
    var_dump($package->getVersionStrategy()->getVersion('css/app.css')); // Check hash
    
  • Inspect Packages:

    $assetPackage = app(Packages::class);
    var_dump($assetPackage->getPackages()); // List all registered packages
    
  • Disable Versioning Temporarily:

    $package = new PathPackage(public_path(), false); // Disable fingerprinting
    

Extension Points

  1. Custom Version Strategies:

    use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface;
    
    class CustomVersionStrategy implements VersionStrategyInterface
    {
        public function getVersion(string $path): string
        {
            return 'v' . config('app.version');
        }
    }
    

    Usage:

    $package = new PathPackage(public_path(), false, [], new CustomVersionStrategy());
    
  2. Dynamic Package Registration:

    $this->app->singleton(Packages::class, function () {
        $packages = [];
        foreach (config('asset.packages') as $config) {
            $packages[] = new PathPackage($config['path'], $config['fingerprint']);
        }
        return new Packages($packages);
    });
    

    Config:

    'asset' => [
        'packages' => [
            ['path' => public_path(), 'fingerprint' => true],
            ['path' => public_path('vendor'), 'fingerprint' => false],
        ],
    ],
    
  3. Event-Driven Asset Updates: Listen for file changes and invalidate caches:

    Storage::disk('public')->delete('css/app.css');
    Cache::forget('asset.packages'); // Clear cached Packages instance
    

Laravel-Specific Quirks

  • Asset Helper Conflict: Laravel’s built-in asset() helper ignores the Symfony package. Solution: Override the helper in AppServiceProvider:

    if (!function_exists('asset')) {
        function asset($path)
        {
            return app('Symfony\Component\Asset\Packages')->getUrl($path);
        }
    }
    
  • Vite/Laravel Mix: Ensure mix-manifest.json is generated and placed in public/. For Vite, use @vite('resources/css/app.css') in Blade and let the Symfony package handle the manifest.

  • Storage Links: If using php artisan storage:link, ensure the public/storage symlink is included in your PathPackage:

    $package = new PathPackage(public_path(), true, [], null, ['public/storage']);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata