Skip to content

Commit 6beb4eb

Browse files
committed
Add docs for the WebLink component
1 parent 795febe commit 6beb4eb

File tree

7 files changed

+315
-0
lines changed

7 files changed

+315
-0
lines changed
Loading
Loading
55.5 KB
Loading
367 KB
Loading

components/weblink.rst

+303
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
.. index::
2+
single: WebLink
3+
single: Components; WebLink
4+
5+
The WebLink Component
6+
======================
7+
8+
The WebLink component provides tools to create `Web Links`_.
9+
It allows to easily leverage `HTTP/2 Server Push`_ as well as `Resource Hints`_.
10+
11+
.. versionadded:: 3.3
12+
The WebLink component was introduced in Symfony 3.3.
13+
14+
By implementing cutting edge web standards, namely `HTTP/2 Server Push`_ and
15+
W3C's `Resource Hints`_, the WebLink component
16+
brings great opportunities to boost webapp's performance.
17+
18+
Thanks to WebLink, HTTP/2 (**h2**) servers are able to push resources to clients
19+
before they even know that they need them (think to CSS or JavaScript
20+
files, or relations of an API resource). WebLink also enables other very
21+
efficient optimisations that work with HTTP 1:
22+
23+
- telling the browser to fetch or to render another webpage in the
24+
background ;
25+
- init early DNS lookups, TCP handshakes or TLS negotiations
26+
27+
Let's discover how easy it is to use it and the real life benefits you
28+
can expect.
29+
30+
To benefit from HTTP/2 Server Pushes, a HTTP/2 server and a HTTPS connection
31+
are mandatory (even in local).
32+
Both Apache, Nginx and Caddy support these protocols.
33+
Be sure they are properly configured before reading.
34+
35+
Alternatively, you can use the `Docker installer and runtime for
36+
Symfony`_ provided by Kévin Dunglas (community supported).
37+
38+
It includes everything you need to run Symfony
39+
(PHP :doc:`configured properly for Symfony </performance>`, and Composer)
40+
as well as a development reverse proxy (Apache) supporting HTTP/2 Server Push
41+
and HTTPS (most clients only support HTTP/2 over TLS).
42+
43+
Unzip the downloaded archive, open a shell in the resulting directory and run
44+
the following command:
45+
46+
.. code-block:: terminal
47+
48+
# Install Symfony and start the project
49+
$ docker-compose up
50+
51+
Open ``https://localhost``, if this nice page appears, you
52+
successfully created your first Symfony 4 project and are browsing it in
53+
HTTP/2!
54+
55+
.. image:: /_images/components/weblink/symfony4-http2.png
56+
57+
Let's create a very simple homepage using
58+
the `Twig`_ templating engine.
59+
60+
The first step is to install the library itself:
61+
62+
.. code-block:: terminal
63+
64+
composer req twig
65+
66+
Symfony is smart enough to download Twig, to automatically register it,
67+
and to enable Symfony features requiring the library.
68+
It also generates a base HTML5 layout in the ``templates/`` directory.
69+
70+
Now, download `Bootstrap`_, extract the archive and copy the file
71+
``dist/css/bootstrap.min.css`` in the ``public/`` directory of our
72+
project.
73+
74+
Symfony comes with a `nice integration with of the most popular CSS framework`_.
75+
76+
.. note::
77+
78+
In a real project, you should use Yarn or NPM with
79+
:doc:`Symfony Encore </frontend/encore/bootstrap>`_
80+
to install Bootstrap.
81+
82+
Now, it's time to create the template of our homepage:
83+
84+
.. code-block:: html
85+
86+
<!DOCTYPE html>
87+
<html>
88+
<head>
89+
<meta charset="UTF-8">
90+
<title>Welcome!</title>
91+
<link rel="stylesheet" href="/bootstrap.min.css">
92+
</head>
93+
<body>
94+
<main role="main" class="container">
95+
<h1>Hello World</h1>
96+
<p class="lead">That's a lot of highly dynamic content, right?</p>
97+
</main>
98+
</body>
99+
</html>
100+
101+
And finally, register our new template as the homepage using the builtin
102+
:doc:`TemplateController </templating/render_without_controller>`_:
103+
104+
.. code-block:: yaml
105+
106+
# config/routes.yaml
107+
index:
108+
path: /
109+
defaults:
110+
_controller: 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction'
111+
template: 'homepage.html.twig'
112+
113+
Refresh your browser, this nice homepage should appear:
114+
115+
.. image:: /_images/components/weblink/homepage-requests.png
116+
117+
HTTP requests are issued by the browser, one for the homepage, and
118+
another one for Bootstrap. But we know from the very beginning that the
119+
browser **will** need Bootstrap. Instead of waiting that the browser
120+
downloads the homepage, parses the HTML (notice "Initiator: Parser" in
121+
Chrome DevTools), encounters the reference to ``bootstrap.min.css`` and
122+
finally sends a new HTTP request, we could take benefit of the HTTP/2
123+
Push feature to directly send both resources to the browser.
124+
125+
Let's do it! Install the WebLink component:
126+
127+
.. code-block:: terminal
128+
129+
composer req weblink
130+
131+
As for Twig, Symfony will automatically download and register this component into our app.
132+
Now, update the template to use the ``preload`` Twig helper that
133+
leverages the WebLink component:
134+
135+
.. code:: html+twig
136+
137+
{# ... #}
138+
<link rel="stylesheet" href="{{ preload('/bootstrap.min.css') }}">
139+
{# ... #}
140+
141+
Reload the page:
142+
143+
.. image:: /_images/components/weblink/http2-server-push.png
144+
145+
As you can see (Initiator: Push), both
146+
responses have been sent directly by the server.
147+
``bootstrap.min.css`` has started to be received before the browser even requested it!
148+
149+
.. note::
150+
151+
Google Chrome provides a nice interface to debug HTTP/2 connections.
152+
Open ``chrome://net-internals/#http2`` to start the tool.
153+
154+
How does it works?
155+
~~~~~~~~~~~~~~~~~~
156+
157+
The WebLink component tracks Link HTTP headers to add to the response.
158+
When using the ``preload()`` helper, a ``Link`` header
159+
with a `preload`_
160+
``rel`` attribute is added to the response:
161+
162+
.. image:: /_images/components/weblink/response-headers.png
163+
164+
According to `the Preload specification`_,
165+
when a HTTP/2 server detects that the original (HTTP 1) response
166+
contains this HTTP header, it will automatically trigger a push for the
167+
related file in the same HTTP/2 connection.
168+
The Apache server provided in the Docker setup supports this feature.
169+
It's why Bootstrap is pushed
170+
to the client!
171+
172+
Popular proxy services and CDN including
173+
`Cloudflare`_, `Fastly`_ and `Akamai`_ also leverage this feature.
174+
It means that you can push resources to
175+
clients and improve performance of your apps in production right now!
176+
All you need is Symfony 3.3+ and a compatible web server or CDN service.
177+
178+
If you want to prevent the push but let the browser preload the resource by
179+
issuing an early separate HTTP request, use the ``nopush`` attribute:
180+
181+
.. code-block:: html+twig
182+
183+
{# ... #}
184+
<link rel="stylesheet" href="{{ preload('/bootstrap.min.css', {nopush: true}) }}">
185+
{# ... #}
186+
187+
Before using HTTP/2 Push, be sure to read `this great article`_ about
188+
known issues, cache implications and the state of the support in popular
189+
browsers.
190+
191+
In addition to HTTP/2 Push and preloading, the WebLink component also
192+
provide some helpers to send `Resource
193+
Hints <https://www.w3.org/TR/resource-hints/#resource-hints>`__ to
194+
clients, the following helpers are available:
195+
196+
- ``dns_prefetch``: "indicate an origin that will be used to fetch
197+
required resources, and that the user agent should resolve as early
198+
as possible"
199+
- ``preconnect``: "indicate an origin that will be used to fetch
200+
required resources. Initiating an early connection, which includes
201+
the DNS lookup, TCP handshake, and optional TLS negotiation, allows
202+
the user agent to mask the high latency costs of establishing a
203+
connection"
204+
- ``prefetch``: "identify a resource that might be required by the next
205+
navigation, and that the user agent *should* fetch, such that the
206+
user agent can deliver a faster response once the resource is
207+
requested in the future"
208+
- ``prerender``: "identify a resource that might be required by the
209+
next navigation, and that the user agent *should* fetch and
210+
execute, such that the user agent can deliver a faster response once
211+
the resource is requested in the future"
212+
213+
The component can also be used to send HTTP link not related to
214+
performance. For instance, any `link defined in the HTML specification`_:
215+
216+
.. code:: html+twig
217+
218+
{# ... #}
219+
<link rel="alternate" href="{{ link('/index.jsonld', 'alternate') }}">
220+
<link rel="stylesheet" href="{{ preload('/bootstrap.min.css', {nopush: true}) }}">
221+
{# ... #}
222+
223+
The previous snippet will result in this HTTP header being sent to the
224+
client:
225+
``Link: </index.jsonld>; rel="alternate",</bootstrap.min.css>; rel="preload"; nopush``
226+
227+
You can also add links to the HTTP response directly from a controller
228+
or any service:
229+
230+
.. code:: php
231+
232+
// src/Controller/BlogPostAction.php
233+
namespace App\Controller;
234+
235+
use Fig\Link\GenericLinkProvider;
236+
use Fig\Link\Link;
237+
use Symfony\Component\HttpFoundation\Request;
238+
use Symfony\Component\HttpFoundation\Response;
239+
240+
final class BlogPostAction
241+
{
242+
public function __invoke(Request $request): Response
243+
{
244+
$linkProvider = $request->attributes->get('_links', new GenericLinkProvider());
245+
$request->attributes->set('_links', $linkProvider->withLink(new Link('preload', '/bootstrap.min.css')));
246+
247+
return new Response('Hello');
248+
}
249+
}
250+
251+
.. code-block:: yaml
252+
253+
# app/config/routes.yaml
254+
blog_post:
255+
path: /post
256+
defaults:
257+
_controller: 'App\Controller\BlogPostAction'
258+
259+
Last but not least, as all Symfony components, WebLink can be used as a
260+
standalone PHP library:
261+
262+
.. code-block:: php
263+
264+
<?php
265+
266+
require __DIR__.'/../vendor/autoload.php';
267+
268+
use Fig\Link\GenericLinkProvider;
269+
use Fig\Link\Link;
270+
use Symfony\Component\WebLink\HttpHeaderSerializer;
271+
272+
$linkProvider = (new GenericLinkProvider())
273+
->withLink(new Link('preload', '/bootstrap.min.css'));
274+
275+
header('Link: '.(new HttpHeaderSerializer())->serialize($linkProvider->getLinks()));
276+
277+
echo 'Hello';
278+
279+
To see how WebLink is used in the wild, take a look to the `Bolt`_
280+
and `Sulu`_ CMS, they both use WebLink to trigger HTTP/2 pushes.
281+
282+
While we're speaking about interoperability, WebLink can deal with any link implementing
283+
`PSR-13`_.
284+
285+
Thanks to Symfony WebLink, there is no excuses to not to switch to HTTP/2!
286+
287+
.. _`Web Links`: https://tools.ietf.org/html/rfc5988
288+
.. _`HTTP/2 Server Push`: https://tools.ietf.org/html/rfc7540#section-8.2
289+
.. _`Resource Hints`: https://www.w3.org/TR/resource-hints/
290+
.. _`Twig`: https://twig.symfony.com/
291+
.. _`Docker installer and runtime for Symfony`: https://github.com/dunglas/symfony-docker
292+
.. _`Bootstrap`: https://getbootstrap.com/
293+
.. _`nice integration with of the most popular CSS framework`: https://symfony.com/blog/new-in-symfony-3-4-bootstrap-4-form-theme
294+
.. _`preload`: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content
295+
.. _`the Preload specification`: https://www.w3.org/TR/preload/#server-push-(http/2)
296+
.. _`Cloudflare`: https://blog.cloudflare.com/announcing-support-for-http-2-server-push-2/
297+
.. _`Fastly`: https://docs.fastly.com/guides/performance-tuning/http2-server-push
298+
.. _`Akamai`: https://blogs.akamai.com/2017/03/http2-server-push-the-what-how-and-why.html
299+
.. _`this great article`: https://www.shimmercat.com/en/blog/articles/whats-push/
300+
.. _`link defined in the HTML specification`: https://html.spec.whatwg.org/dev/links.html#linkTypes
301+
.. _`Bolt`: https://bolt.cm/
302+
.. _`Sulu`: https://sulu.io/
303+
.. _`PSR-13`: http://www.php-fig.org/psr/psr-13/

index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Topics
5454
testing
5555
translation
5656
validation
57+
weblink
5758
workflow
5859

5960
Best Practices

weblink.rst

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
WebLink
2+
=======
3+
4+
Symfony natively supports `Web Linking`_. It is especially useful to improve
5+
the performance of your application by leveraging the HTTP/2 protocol and
6+
preloading capabilities of modern web browsers.
7+
8+
Read the the :doc:`WebLink Component documentation </components/weblink>` to learn how
9+
to use these features.
10+
11+
.. _`Web Linking`_: https://tools.ietf.org/html/rfc5988

0 commit comments

Comments
 (0)