A few months ago I showed how using preconnect resource hints can severely speed up your website. I found out that for Magento 2 there are no ready-to-use solutions to integrate preload, preconnect or prefetch headers into your store. So today I’ll show you how to add preload
, preconnect
and prefetch
resource hints to Magento 2’s head.
What are Resource Hints?
Resource hints are various link relationship elements that give website owners more control over the timing and when and how of used resources:
<link rel="preconnect" />
being very useful e.g. to speed up loading 3rd party scripts and resources.<link rel="prefetch />
could come in handy once a visitor enters the shopping cart, to prepare the resources used for navigation through the checkout.<link rel="preload />
is often used e.g. for webfonts to make sure the display of text isn’t changed while loading.
How Preconnect speeds up your Magento 2 Store
While preload
and prefetch
are features which make your site feel faster, preconnect
actually speeds up your store. Here’s how it works:
Preconnect
establishes a connection to the source at pageload. DNS Lookup, Initial Connection and SSL negotiation happen asynchronously. When the browser needs the actual file, it can start downloading immediately without having to wait. Without preconnect
this entire handshake process happens one after another, slowing down the loading of the page.
Add Resource Hints to your Store’s Head
Since Resource Hints are link relationship elements (like stylesheets) they need to be defined in <head>
. Sadly, Magento doesn’t offer an easy way to add resource hints to its head. So in order to this, we need to build a simply module consisting of two things:
- An observer,
- A list of elements we want to add.
Hint: if you don’t want or can’t build a module for Magento 2. No worries, I’ve created and expanded this extension with a very easy-to-use configuration. Scroll to the bottom of this post for a link. 🙂
Creating the Magento 2 module
Building a Magento 2 extension always starts with two things:
registration.php
etc/module.xml
These files should be added inside the folder [magento 2-root]/app/code/Dan0sz/ResourceHints
.
app/code/Dan0sz/ResourceHints/registration.php
<?php | |
/** | |
* @author : Daan van den Bergh | |
* @url : https://daan.dev | |
* @package : Dan0sz/ResourceHints | |
* @copyright: (c) 2019 Daan van den Bergh | |
*/ | |
\Magento\Framework\Component\ComponentRegistrar::register( | |
\Magento\Framework\Component\ComponentRegistrar::MODULE, | |
'Dan0sz_ResourceHints', | |
__DIR__ | |
); |
app/code/Dan0sz/ResourceHints/etc/module.xml
<?xml version="1.0" encoding="UTF-8"?> | |
<!-- | |
/** | |
* @author : Daan van den Bergh | |
* @url : https://daan.dev | |
* @package : Dan0sz/ResourceHints | |
* @copyright: (c) 2019 Daan van den Bergh | |
*/ | |
--> | |
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> | |
<module name="Dan0sz_ResourceHints" setup_version="1.0.0"> | |
<sequence> | |
<module name="Magento_Catalog" /> | |
</sequence> | |
</module> | |
</config> |
Adding an Observer
At certain (many) points in Magento 2’s code, events are triggered — or dispatched. This allows us to hook into these events and execute code. This is achieved using an observer. E.g. in an earlier post I’ve shown how to use an observer to add a product to Magento 2’s topmenu.
To hook into an observer, we need two things:
- Register the observer to the event,
- An observer-class, containing (at least) an
execute()
-method.
The event we will be hooking into is called layout_generate_blocks_after
which allows us to add resource hints to Magento 2’s head, after Magento is done generate the other blocks within the layout. Since it is considered a frontend-event, the below file needs to be placed inside the etc/frontend
-folder.
app/code/Dan0sz/ResourceHints/etc/frontend/events.xml
<?xml version="1.0" encoding="UTF-8"?> | |
<!-- | |
/** | |
* @author : Daan van den Bergh | |
* @url : https://daan.dev | |
* @package : Dan0sz/ResourceHints | |
* @copyright: (c) 2019 Daan van den Bergh | |
*/ | |
--> | |
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> | |
<event name="layout_generate_blocks_after"> | |
<observer name="dan0sz_resource_hints_framework_view_layout_builder" instance="Dan0sz\ResourceHints\Observer\Framework\View\Layout\Builder" /> | |
</event> | |
</config> |
app/code/Dan0sz/ResourceHints/Observer/Framework/View/Layout/Builder.php
<?php | |
/** | |
* @author : Daan van den Bergh | |
* @url : https://daan.dev | |
* @package : Dan0sz/ResourceHints | |
* @copyright: (c) 2019 Daan van den Bergh | |
*/ | |
namespace Dan0sz\ResourceHints\Observer\Framework\View\Layout; | |
use Magento\Framework\Event\Observer; | |
use Magento\Framework\Event\ObserverInterface; | |
use Magento\Framework\View\Page\Config as PageConfig; | |
class Builder implements ObserverInterface | |
{ | |
/** @var PageConfig $pageConfig */ | |
private $pageConfig; | |
/** | |
* Builder constructor. | |
* | |
* @param PageConfig $pageConfig | |
*/ | |
public function __construct( | |
PageConfig $pageConfig | |
) { | |
$this->pageConfig = $pageConfig; | |
} | |
/** | |
* @param Observer $observer | |
* | |
* @return $this | |
*/ | |
public function execute(Observer $observer) | |
{ | |
$resourceHints = [ | |
'google' => [ | |
'resource' => 'https://www.google-analytics.com', | |
'type' => 'preconnect', | |
], | |
'next-page' => [ | |
'resource' => 'https://example.com/next-page', | |
'type' => 'prefetch' | |
], | |
'stylesheet' => [ | |
'resource' => 'styles.css', | |
'type' => 'preload', | |
'as' => 'stylesheet' | |
] | |
]; | |
foreach ($resourceHints as $resource) { | |
$this->pageConfig->addRemotePageAsset( | |
$resource['resource'], | |
'link_rel', | |
[ | |
'attributes' => ['rel' => $resource['type'] ] | |
] | |
); | |
} | |
return $this; | |
} | |
} |
Registering the Magento 2 Extension
That’s it. You’re done coding! 🙂 All you need to do now is register your extension following the conventional method:
bin/magento setup:upgrade
and if you’re in production mode:bin/magento setup:di:compile
(orrm -rf generated/*
)bin/magento setup:static-content:deploy [nl_NL en_US xx_XX]
bin/magento cache:flush
Easily Configure Preconnect, Preload and Prefetch with Resource Hints for Magento 2
In this post I’ve discussed the basics of how to add resource hints — such as (DNS) preconnect, preload and prefetch — to Magento 2’s head in order to improve pageload times.
If you’re looking for a fast and easily configurable way to add Resource Hints to Magento 2, consider downloading Resource Hints for Magento 2. A Magento 2 extension created by me and freely available on Github. 🙂
Can You share this module.
Hi Anup, the last link in the post links to the Github repo. You can also install it using composer, though. 🙂
Hi greatt tutorial and it really works. I was wondering how can I add a Preload for my font? My font is located in my local server but somehow it says I need to preload these fonts. Using the admin store configuration from your module what value should I place for the font? Should it only be the font name? Or should I add the entire font url (which right now is using a cached version that might change often). Would appreciate your reply on this
it’s a great blog thank you for sharing such useful information,
i have a question, my site is using Luma icons, and when I run a speed test using google speed test i have this suggestion :
Leverage the font-display CSS feature to ensure text is user-visible while webfonts are loading.
Potential Savings
…fonts/Luma-Icons.woff2
so my question is how to solve it, how can i preload this font ? is it enough to add the font name like in your example (style.css) ?
Thanks for sharing. It helped me a lot in my development.
line 56 in the observer is bad syntax your missing the closing bracket e.g correct line
‘attributes’ => [‘rel’ => $resource[‘type’] ]
i meant line 59*
You’re absolutely right. I adjusted it. 🙂 Thnx for notifying me!