-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add docs for the WebLink component #10309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
6beb4eb
Add docs for the WebLink component
dunglas 9f4ae9b
fix typo
dunglas 178821e
refactor
dunglas e3d4036
RST
dunglas 088690f
Fix link
dunglas e12e776
RST
dunglas 38fda88
fix build
xabbuh ea7b3da
@nicolas-grekas' review
dunglas 91ee3bc
Fix RST
dunglas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
.. index:: | ||
single: WebLink | ||
single: Components; WebLink | ||
|
||
The WebLink Component | ||
====================== | ||
|
||
The WebLink component provides tools to create `Web Links`_. | ||
It allows to easily leverage `HTTP/2 Server Push`_ as well as `Resource Hints`_. | ||
|
||
.. versionadded:: 3.3 | ||
The WebLink component was introduced in Symfony 3.3. | ||
|
||
Installation | ||
------------ | ||
|
||
.. code-block:: terminal | ||
|
||
$ composer require symfony/weblink | ||
|
||
Alternatively, you can clone the `<https://github.com/symfony/weblink>`_ repository. | ||
|
||
.. include:: /components/require_autoload.rst.inc | ||
|
||
Usage | ||
----- | ||
|
||
Basic usage:: | ||
|
||
use Fig\Link\GenericLinkProvider; | ||
use Fig\Link\Link; | ||
use Symfony\Component\WebLink\HttpHeaderSerializer; | ||
|
||
$linkProvider = (new GenericLinkProvider()) | ||
->withLink(new Link('preload', '/bootstrap.min.css')); | ||
|
||
header('Link: '.(new HttpHeaderSerializer())->serialize($linkProvider->getLinks())); | ||
|
||
echo 'Hello'; | ||
|
||
|
||
.. seealso:: | ||
|
||
Read the :doc:`WebLink documentation </weblink>` to learn how | ||
to use the features implemented by this component. | ||
|
||
.. _`Web Links`: https://tools.ietf.org/html/rfc5988 | ||
.. _`HTTP/2 Server Push`: https://tools.ietf.org/html/rfc7540#section-8.2 | ||
.. _`Resource Hints`: https://www.w3.org/TR/resource-hints/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,6 +54,7 @@ Topics | |
testing | ||
translation | ||
validation | ||
weblink | ||
workflow | ||
|
||
Best Practices | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
WebLink | ||
======= | ||
|
||
Symfony natively supports `Web Linking`_. It is especially useful to improve | ||
the performance of your application by leveraging the HTTP/2 protocol and | ||
preloading capabilities of modern web browsers. | ||
|
||
By implementing cutting edge web standards, namely `HTTP/2 Server Push`_ and | ||
W3C's `Resource Hints`_, the WebLink component | ||
brings great opportunities to boost webapp's performance. | ||
|
||
Thanks to WebLink, HTTP/2 (**h2**) servers are able to push resources to clients | ||
before they even know that they need them (think about CSS or JavaScript | ||
files, or relations of an API resource). WebLink also enables other very | ||
efficient optimisations that work with HTTP 1.x: | ||
|
||
- telling the browser to fetch or to render another webpage in the | ||
background ; | ||
- initializing early DNS lookups, TCP handshakes or TLS negotiations | ||
|
||
To benefit from HTTP/2 Server Pushes, an HTTP/2 server and an HTTPS connection | ||
are required (even local ones). | ||
Both Apache, Nginx and Caddy support these protocols. | ||
Be sure they are properly configured before reading. | ||
|
||
Alternatively, you can use the `Docker installer and runtime for | ||
Symfony`_ provided by Kévin Dunglas (community supported). | ||
|
||
Unzip the downloaded archive, open a shell in the resulting directory and run | ||
the following command: | ||
|
||
.. code-block:: terminal | ||
|
||
# Install Symfony and start the project | ||
$ docker-compose up | ||
|
||
Open ``https://localhost``, if this nice page appears, you | ||
successfully created your first Symfony 4 project and are browsing it in | ||
HTTP/2! | ||
|
||
.. image:: /_images/components/weblink/symfony4-http2.png | ||
|
||
Let's create a very simple homepage using | ||
the Twig_ templating engine. | ||
|
||
The first step is to install the library itself: | ||
|
||
.. code-block:: terminal | ||
|
||
composer req twig | ||
|
||
Symfony is smart enough to download Twig, to automatically register it, | ||
and to enable Symfony features requiring the library. | ||
It also generates a base HTML5 layout in the ``templates/`` directory. | ||
|
||
Now, download Bootstrap_, extract the archive and copy the file | ||
``dist/css/bootstrap.min.css`` in the ``public/`` directory of our | ||
project. | ||
|
||
Symfony comes with `an integration of the most popular CSS framework`_. | ||
|
||
.. note:: | ||
|
||
In a real project, you should use Yarn or NPM with | ||
:doc:`Symfony Encore </frontend/encore/bootstrap>` | ||
to install Bootstrap. | ||
|
||
Now, it's time to create the template of our homepage: | ||
|
||
.. code-block:: twig | ||
|
||
{# templates/homepage.html.twig #} | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>Welcome!</title> | ||
<link rel="stylesheet" href="/bootstrap.min.css"> | ||
</head> | ||
<body> | ||
<main role="main" class="container"> | ||
<h1>Hello World</h1> | ||
<p class="lead">That's a lot of highly dynamic content, right?</p> | ||
</main> | ||
</body> | ||
</html> | ||
|
||
And finally, register our new template as the homepage using the builtin | ||
:doc:`TemplateController </templating/render_without_controller>`: | ||
|
||
.. code-block:: yaml | ||
|
||
# config/routes.yaml | ||
index: | ||
path: / | ||
defaults: | ||
_controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction' | ||
template: 'homepage.html.twig' | ||
|
||
Refresh your browser, this homepage should appear: | ||
|
||
.. image:: /_images/components/weblink/homepage-requests.png | ||
|
||
HTTP requests are issued by the browser, one for the homepage, and | ||
another one for Bootstrap. But we know from the very beginning that the | ||
browser **will** need Bootstrap. Instead of waiting that the browser | ||
downloads the homepage, parses the HTML (notice "Initiator: Parser" in | ||
Chrome DevTools), encounters the reference to ``bootstrap.min.css`` and | ||
finally sends a new HTTP request, we could take benefit of the HTTP/2 | ||
Push feature to directly send both resources to the browser. | ||
|
||
Let's do it! Install the WebLink component: | ||
|
||
.. code-block:: terminal | ||
|
||
composer req weblink | ||
|
||
As for Twig, Symfony will automatically download and register this component into our app. | ||
Now, update the template to use the ``preload`` Twig helper that | ||
leverages the WebLink component: | ||
|
||
.. code:: html+twig | ||
|
||
{# ... #} | ||
<link rel="stylesheet" href="{{ preload('/bootstrap.min.css') }}"> | ||
{# ... #} | ||
|
||
Reload the page: | ||
|
||
.. image:: /_images/components/weblink/http2-server-push.png | ||
|
||
As you can see (Initiator: Push), both | ||
responses have been sent directly by the server. | ||
``bootstrap.min.css`` has started to be received before the browser even requested it! | ||
|
||
.. note:: | ||
|
||
Google Chrome provides an interface to debug HTTP/2 connections. | ||
Open ``chrome://net-internals/#http2`` to start the tool. | ||
|
||
How does it works? | ||
~~~~~~~~~~~~~~~~~~ | ||
|
||
The WebLink component tracks ``Link`` HTTP headers to add to the response. | ||
When using the ``preload()`` helper, a ``Link`` header | ||
with a `preload`_ | ||
``rel`` attribute is added to the response: | ||
|
||
.. image:: /_images/components/weblink/response-headers.png | ||
|
||
According to `the Preload specification`_, | ||
when an HTTP/2 server detects that the original (HTTP 1.x) response | ||
contains this HTTP header, it will automatically trigger a push for the | ||
related file in the same HTTP/2 connection. | ||
The Apache server provided in the Docker setup supports this feature. | ||
It's why Bootstrap is pushed | ||
to the client! | ||
|
||
Popular proxy services and CDN including | ||
`Cloudflare`_, `Fastly`_ and `Akamai`_ also leverage this feature. | ||
It means that you can push resources to | ||
clients and improve performance of your apps in production right now! | ||
All you need is Symfony 3.3+ and a compatible web server or CDN service. | ||
|
||
If you want to prevent the push but let the browser preload the resource by | ||
issuing an early separate HTTP request, use the ``nopush`` attribute: | ||
|
||
.. code-block:: html+twig | ||
|
||
{# ... #} | ||
<link rel="stylesheet" href="{{ preload('/bootstrap.min.css', {nopush: true}) }}"> | ||
{# ... #} | ||
|
||
Before using HTTP/2 Push, be sure to read `this great article`_ about | ||
known issues, cache implications and the state of the support in popular | ||
browsers. | ||
|
||
In addition to HTTP/2 Push and preloading, the WebLink component also | ||
provides some helpers to send `Resource | ||
Hints <https://www.w3.org/TR/resource-hints/#resource-hints>`__ to | ||
clients, the following helpers are available: | ||
|
||
- ``dns_prefetch``: "indicate an origin that will be used to fetch | ||
required resources, and that the user agent should resolve as early | ||
as possible" | ||
- ``preconnect``: "indicate an origin that will be used to fetch | ||
required resources. Initiating an early connection, which includes | ||
the DNS lookup, TCP handshake, and optional TLS negotiation, allows | ||
the user agent to mask the high latency costs of establishing a | ||
connection" | ||
- ``prefetch``: "identify a resource that might be required by the next | ||
navigation, and that the user agent *should* fetch, such that the | ||
user agent can deliver a faster response once the resource is | ||
requested in the future" | ||
- ``prerender``: "identify a resource that might be required by the | ||
next navigation, and that the user agent *should* fetch and | ||
execute, such that the user agent can deliver a faster response once | ||
the resource is requested in the future" | ||
|
||
The component can also be used to send HTTP link not related to | ||
performance. For instance, any `link defined in the HTML specification`_: | ||
|
||
.. code:: html+twig | ||
|
||
{# ... #} | ||
<link rel="alternate" href="{{ link('/index.jsonld', 'alternate') }}"> | ||
<link rel="stylesheet" href="{{ preload('/bootstrap.min.css', {nopush: true}) }}"> | ||
{# ... #} | ||
|
||
The previous snippet will result in this HTTP header being sent to the | ||
client: | ||
``Link: </index.jsonld>; rel="alternate",</bootstrap.min.css>; rel="preload"; nopush`` | ||
|
||
You can also add links to the HTTP response directly from a controller | ||
or any service: | ||
|
||
.. code:: php | ||
|
||
// src/Controller/BlogPostAction.php | ||
namespace App\Controller; | ||
|
||
use Fig\Link\GenericLinkProvider; | ||
use Fig\Link\Link; | ||
use Symfony\Component\HttpFoundation\Request; | ||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
final class BlogPostAction | ||
{ | ||
public function __invoke(Request $request): Response | ||
{ | ||
$linkProvider = $request->attributes->get('_links', new GenericLinkProvider()); | ||
$request->attributes->set('_links', $linkProvider->withLink(new Link('preload', '/bootstrap.min.css'))); | ||
|
||
return new Response('Hello'); | ||
} | ||
} | ||
|
||
.. code-block:: yaml | ||
|
||
# app/config/routes.yaml | ||
blog_post: | ||
path: /post | ||
defaults: | ||
_controller: 'App\Controller\BlogPostAction' | ||
|
||
.. seealso:: | ||
|
||
As all Symfony components, WebLink can be used :doc:`as a | ||
standalone PHP library </components/weblink>`. | ||
|
||
To see how WebLink is used in the wild, take a look to the `Bolt`_ | ||
and `Sulu`_ CMS, they both use WebLink to trigger HTTP/2 pushes. | ||
|
||
While we're speaking about interoperability, WebLink can deal with any link implementing | ||
`PSR-13`_. | ||
|
||
Thanks to Symfony WebLink, there is no excuses to not to switch to HTTP/2! | ||
|
||
.. _`Web Linking`: https://tools.ietf.org/html/rfc5988 | ||
.. _`HTTP/2 Server Push`: https://tools.ietf.org/html/rfc7540#section-8.2 | ||
.. _`Resource Hints`: https://www.w3.org/TR/resource-hints/ | ||
.. _`Twig`: https://twig.symfony.com/ | ||
.. _`Docker installer and runtime for Symfony`: https://github.com/dunglas/symfony-docker | ||
.. _`Bootstrap`: https://getbootstrap.com/ | ||
.. _`an integration of the most popular CSS framework`: https://symfony.com/blog/new-in-symfony-3-4-bootstrap-4-form-theme | ||
.. _`preload`: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content | ||
.. _`the Preload specification`: https://www.w3.org/TR/preload/#server-push-(http/2) | ||
.. _`Cloudflare`: https://blog.cloudflare.com/announcing-support-for-http-2-server-push-2/ | ||
.. _`Fastly`: https://docs.fastly.com/guides/performance-tuning/http2-server-push | ||
.. _`Akamai`: https://blogs.akamai.com/2017/03/http2-server-push-the-what-how-and-why.html | ||
.. _`this great article`: https://www.shimmercat.com/en/blog/articles/whats-push/ | ||
.. _`link defined in the HTML specification`: https://html.spec.whatwg.org/dev/links.html#linkTypes | ||
.. _`Bolt`: https://bolt.cm/ | ||
.. _`Sulu`: https://sulu.io/ | ||
.. _`PSR-13`: http://www.php-fig.org/psr/psr-13/ |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing path where to put the file?