8000 minor #10309 Add docs for the WebLink component (dunglas, xabbuh) · symfony/symfony-docs@2b637e3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2b637e3

Browse files
committed
minor #10309 Add docs for the WebLink component (dunglas, xabbuh)
This PR was merged into the 3.4 branch. Discussion ---------- Add docs for the WebLink component The WebLink component is available since Symfony 3.3, but I never took the time to add the docs (however, a blog post explaining how to use it was available). This documentation is based on https://dunglas.fr/2017/10/symfony-4-http2-push-and-preloading/. If necessary, I can grant any copyright regarding this post to the Symfony projec 10000 t. symfony/symfony#21478 symfony/symfony#22273 Closes #7515. Commits ------- 91ee3bc Fix RST ea7b3da @nicolas-grekas' review 38fda88 fix build e12e776 RST 088690f Fix link e3d4036 RST 178821e refactor 9f4ae9b fix typo 6beb4eb Add docs for the WebLink component
2 parents cdb5ee0 + 91ee3bc commit 2b637e3

File tree

7 files changed

+325
-0
lines changed

7 files changed

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

components/weblink.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
Installation
15+
------------
16+
17+
.. code-block:: terminal
18+
19+
$ composer require symfony/weblink
20+
21+
Alternatively, you can clone the `<https://github.com/symfony/weblink>`_ repository.
22+
23+
.. include:: /components/require_autoload.rst.inc
24+
25+
Usage
26+
-----
27+
28+
Basic usage::
29+
30+
use Fig\Link\GenericLinkProvider;
31+
use Fig\Link\Link;
32+
use Symfony\Component\WebLink\HttpHeaderSerializer;
33+
34+
$linkProvider = (new GenericLinkProvider())
35+
->withLink(new Link('preload', '/bootstrap.min.css'));
36+
37+
header('Link: '.(new HttpHeaderSerializer())->serialize($linkProvider->getLinks()));
38+
39+
echo 'Hello';
40+
41+
42+
.. seealso::
43+
44+
Read the :doc:`WebLink documentation </weblink>` to learn how
45+
to use the features implemented by this component.
46+
47+
.. _`Web Links`: https://tools.ietf.org/html/rfc5988
48+
.. _`HTTP/2 Server Push`: https://tools.ietf.org/html/rfc7540#section-8.2
49+
.. _`Resource Hints`: https://www.w3.org/TR/resource-hints/

index.rst

Lines changed: 1 addition & 0 deletions
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

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

0 commit comments

Comments
 (0)
0