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

Web Link Laravel Package

symfony/web-link

Symfony WebLink component helps manage link relationships between resources. Create and serialize HTTP Link headers for preload, prefetch, and resource hints (HTML5/Web standards), enabling better performance via HTTP/2 push and client hints.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require symfony/web-link
    

    No Laravel-specific dependencies—works with vanilla PHP.

  2. First Use Case: Preload a critical CSS file for a route:

    use Symfony\Component\WebLink\GenericLinkProvider;
    use Symfony\Component\WebLink\HttpHeaderSerializer;
    use Symfony\Component\WebLink\Link;
    
    // In a Laravel middleware or controller:
    $linkProvider = (new GenericLinkProvider())
        ->withLink(new Link('preload', '/css/app.css', [
            'as' => 'style',
            'crossorigin' => 'anonymous',
        ]));
    
    return response()
        ->header('Link', (new HttpHeaderSerializer())->serialize($linkProvider->getLinks()));
    
  3. Where to Look First:

    • Symfony’s WebLink Documentation for API reference.
    • Link class constants (e.g., Link::AS_STYLE, Link::AS_SCRIPT) for standardized attributes.
    • HttpHeaderSerializer for header formatting.

Implementation Patterns

Core Workflows

1. Middleware-Based Preloading

Inject Link headers globally for specific routes:

// app/Http/Middleware/PreloadAssets.php
public function handle(Request $request, Closure $next) {
    $response = $next($request);

    $linkProvider = (new GenericLinkProvider())
        ->withLink(new Link('preload', asset('css/main.css'), [
            'as' => 'style',
            'media' => 'print',
        ]));

    return $response->header('Link', (new HttpHeaderSerializer())->serialize($linkProvider->getLinks()));
}

Register in app/Http/Kernel.php:

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\PreloadAssets::class,
        // ...
    ],
];

2. Route-Specific Links

Use Laravel’s Route::middleware() or controller logic:

// routes/web.php
Route::get('/dashboard', function () {
    $linkProvider = (new GenericLinkProvider())
        ->withLink(new Link('preload', asset('js/dashboard.js'), [
            'as' => 'script',
            'fetchpriority' => 'high',
        ]));

    return response()
        ->header('Link', (new HttpHeaderSerializer())->serialize($linkProvider->getLinks()))
        ->view('dashboard');
});

3. Dynamic Links from API Responses

Attach Link headers to API responses (e.g., HATEOAS):

// app/Http/Controllers/Api/PostController.php
public function show(Post $post) {
    $linkProvider = (new GenericLinkProvider())
        ->withLink(new Link('related', route('posts.related', $post), ['title' => 'Related Posts']))
        ->withLink(new Link('next', route('posts.next', $post), ['title' => 'Next Page']));

    return response()->json($post->toArray())
        ->header('Link', (new HttpHeaderSerializer())->serialize($linkProvider->getLinks()));
}

4. Blade Integration for Client-Side Hints

Generate <link> tags dynamically:

// app/Helpers/WebLinkHelper.php
function weblink_tags($rel, $href, $attributes = []) {
    $link = new Link($rel, $href, $attributes);
    return (new HtmlLinkSerializer())->serialize($link);
}

Usage in Blade:

{{ weblink_tags('preconnect', 'https://cdn.example.com', ['crossorigin']) }}

5. HTTP/2 Server Push (Server-Side)

Use Link headers as push candidates (requires server config):

// app/Http/Middleware/PushAssets.php
public function handle($request, Closure $next) {
    $response = $next($request);
    if ($request->is('*')) {
        $linkProvider = (new GenericLinkProvider())
            ->withLink(new Link('preload', asset('js/vendor.js'), ['as' => 'script']))
            ->withLink(new Link('preload', asset('fonts/inter.woff2'), ['as' => 'font']));

        return $response->header('Link', (new HttpHeaderSerializer())->serialize($linkProvider->getLinks()));
    }
    return $response;
}

Nginx Example:

location / {
    proxy_pass http://app;
    proxy_set_header Link $http_link;
    push_preload on;
}

Integration Tips

  1. Service Container Binding: Bind GenericLinkProvider to reuse across requests:

    // app/Providers/AppServiceProvider.php
    public function register() {
        $this->app->singleton(GenericLinkProvider::class, function () {
            return new GenericLinkProvider();
        });
    }
    

    Usage:

    $this->app->make(GenericLinkProvider::class)
        ->withLink(new Link('prefetch', '/api/data'));
    
  2. Caching Link Providers: Cache static links (e.g., for /robots.txt or /sitemap.xml):

    $linkProvider = Cache::remember('weblink.assets', now()->addHour(), function () {
        return (new GenericLinkProvider())
            ->withLink(new Link('preload', asset('css/app.css')))
            ->withLink(new Link('preconnect', 'https://fonts.gstatic.com'));
    });
    
  3. Environment-Specific Links: Use config to toggle links per environment:

    // config/weblink.php
    'enabled' => env('WEBLINK_ENABLED', true),
    'links' => [
        'preload' => [
            'css/app.css' => ['as' => 'style'],
            'js/app.js' => ['as' => 'script'],
        ],
    ],
    

    Middleware:

    if (config('weblink.enabled')) {
        $linkProvider = collect(config('weblink.links'))
            ->map(fn ($attrs, $href) => new Link('preload', $href, $attrs))
            ->reduce(fn ($provider, $link) => $provider->withLink($link), new GenericLinkProvider());
    }
    
  4. Testing Headers: Use Laravel’s Testing\TestResponse to assert headers:

    $response = $this->get('/dashboard');
    $response->assertHeader('Link', 'preload="/css/app.css;as=style"');
    

Gotchas and Tips

Pitfalls

  1. Header Injection Timing:

    • Issue: Headers must be added before the response is sent. Late middleware or controller logic may fail.
    • Fix: Use Laravel’s finishRequest() event or ensure middleware runs early in the stack.
  2. Duplicate Links:

    • Issue: Multiple middleware/controllers may add the same Link, causing malformed headers.
    • Fix: Use GenericLinkProvider::getLinks() to merge links or deduplicate:
      $provider = $provider->withLinks($newLinks)->getLinks()->unique();
      
  3. Non-Standard Link Types:

    • Issue: Custom rel values (e.g., rel="modulepreload") may not be supported in all browsers.
    • Fix: Validate against W3C specs or microformats.
  4. HTTP/2 Server Push Limitations:

    • Issue: Not all servers/proxies support push (e.g., Cloudflare requires configuration).
    • Fix: Test with curl -v or Chrome DevTools’ "Network" tab (check "Push" column).
  5. Case Sensitivity:

    • Issue: Link header values are case-sensitive (e.g., preload vs Preload).
    • Fix: Use constants like Link::REL_PRELOAD:
      new Link(Link::REL_PRELOAD, '/file.css', ['as' => Link::AS_STYLE]);
      
  6. Cross-Origin Restrictions:

    • Issue: Preloading cross-origin resources (e.g., crossorigin="anonymous") may fail if the server lacks CORS headers.
    • Fix: Test with curl -I or browser dev tools.

Debugging

  1. Inspect Headers:

    • Browser: DevTools → Network tab → Check "Link" header in response.
    • CLI: curl -I http://example.com/dashboard.
  2. Validate Serialization:

    • Use HttpHeaderSerializer::serialize() to debug malformed headers:
      $serializer = new HttpHeaderSerializer();
      $links = $linkProvider->getLinks();
      dd($serializer->serialize
      
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.
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core