Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2b637e3

Browse filesBrowse 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 project. 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
Copy full SHA for 2b637e3

File tree

7 files changed

+325
-0
lines changed
Filter options

7 files changed

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

‎components/weblink.rst

Copy file name to clipboard
+49Lines 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

Copy file name to clipboardExpand all lines: index.rst
+1Lines 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

Copy file name to clipboard
+275Lines 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)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.