symfony/web-link
Symfony WebLink component manages typed links between resources and serializes them to HTTP Link headers. Use it to advertise preload, prefetch, and other resource hints for faster navigation and HTTP/2 push, following HTML5 and W3C specs.
composer require symfony/web-link
use Symfony\Component\WebLink\GenericLinkProvider;
use Symfony\Component\WebLink\HttpHeaderSerializer;
use Symfony\Component\WebLink\Link;
$linkProvider = new GenericLinkProvider();
$linkProvider->addLink(new Link('preload', '/css/app.css', [
'as' => 'style',
'crossorigin' => true,
]));
header('Link: ' . (new HttpHeaderSerializer())->serialize($linkProvider->getLinks()));
Link (represents a single link with rel, href, and attributes).GenericLinkProvider (aggregates links; immutable by design).HttpHeaderSerializer (converts links to HTTP Link: header format).Preloading Critical Assets
Add preload links for above-the-fold resources (CSS, fonts, scripts):
$provider = new GenericLinkProvider();
$provider->addLink(new Link('preload', '/fonts/roboto.woff2', ['as' => 'font']));
Prefetching Non-Critical Resources
Use prefetch for future pages or lazy-loaded assets:
$provider->addLink(new Link('prefetch', '/next-page'));
HTTP/2 Push (Server-Side)
Serialize links in the Link: header to enable HTTP/2 push:
header('Link: ' . (new HttpHeaderSerializer())->serialize($provider->getLinks()));
Dynamic Link Providers
Extend GenericLinkProvider or implement LinkProviderInterface for context-aware links (e.g., route-based assets):
class RouteAssetLinkProvider implements LinkProviderInterface {
public function getLinks(): array {
return [new Link('preload', route_to_asset('app.css'))];
}
}
Parsing Incoming Links
Parse Link: headers from HTTP responses (Symfony 8+):
use Symfony\Component\WebLink\LinkHeaderParser;
$links = (new LinkHeaderParser())->parse($response->getHeader('Link'));
Response objects:
$response = new Response();
$response->headers->addLink($provider->getLinks());
<link> tags:
{% for link in app.webLinkProvider.getLinks() %}
<link rel="{{ link.rel }}" href="{{ link.href }}" {% for attr, value in link.attributes %} {{ attr }}="{{ value }}" {% endfor %}>
{% endfor %}
public function handle(Request $request, Closure $next) {
$response = $next($request);
$response->headers->addLink($this->linkProvider->getLinks());
return $response;
}
Immutable Providers
GenericLinkProvider is immutable. Use addLink() or withLink() to create new instances:
// Wrong: $provider->addLink() returns void.
// Correct: $provider = $provider->withLink(new Link(...));
Header Serialization Quirks
?) must be quoted in headers:
new Link('preload', '/search?q=test', ['as' => 'script']) // Serializes as: <'/search?q=test'>; rel="preload"; as="script"
HTTP/2 Push Limitations
Rel/Attribute Validation
rel values (e.g., modulepreload) must comply with W3C specs.as="invalid") may be silently ignored.Link: headers are sent.error_log((new HttpHeaderSerializer())->serialize($provider->getLinks()));
Link: header follows RFC 8288.Custom Link Providers
Implement LinkProviderInterface for dynamic logic (e.g., route-based assets):
class ApiDocumentationLinkProvider implements LinkProviderInterface {
public function getLinks(): array {
return [new Link('alternate', '/api-docs', ['type' => 'application/json'])];
}
}
Attribute Normalization
Override Link::getAttributes() to transform attributes before serialization:
class CustomLink extends Link {
public function getAttributes(): array {
$attrs = parent::getAttributes();
$attrs['priority'] = 'high'; // Force a default.
return $attrs;
}
}
Header Serializer Extensions
Extend HttpHeaderSerializer to customize output (e.g., add a prefix):
class CustomSerializer extends HttpHeaderSerializer {
public function serialize(array $links): string {
return 'Custom-Prefix: ' . parent::serialize($links);
}
}
Link Header Parsing
Use LinkHeaderParser to extract links from HTTP responses (e.g., for pagination):
$links = (new LinkHeaderParser())->parse($response->getHeader('Link'));
$nextPageLink = $links->get('next');
GenericLinkProvider instances across requests if links are static.Link::sameAs() to check for existing links before adding:
if (!$provider->hasLink($newLink)) {
$provider = $provider->withLink($newLink);
}
How can I help you explore Laravel packages today?