📜 ⬆️ ⬇️

As we broke up mobile Lenta.ru to the speed of light

image

AMP - for sure, you have already heard about this technology promoted by Google. It would seem that another fashionable technology for hipsters, which everyone will soon forget. However, in reality, this feature is already running in the production of a significant number of news sites, including such giants as the Guardian, Times, Washington Post, and so forth, and so on. A short story about AMP buns was already on the pages of “Habra”, and I would like to focus in a little more detail on how to incorporate this into the project, and what kind of profit you can actually get.


Very briefly on how this works.


AMP is a technology that allows you to speed up the loading of mobile pages. At its core, this is the same HTML, but not just HTML, but slyly designed according to special rules. The page is rendered using a special script (AMP runtime), which takes care of rendering optimization.
')
Execution of other scripts on the page is prohibited so that their changes in DOM will not prevent us from optimizing. This does not mean that your pages will not be interactivity. It can be done, but again by special rules (for example, in a special component).
In addition, when parsing, the Google bot detects AMP pages, caches their contents and will return them faster in the future.

In the issue of Google AMP-resources are visible in a special carousel at the top of the page.



If we talk about the automatic redirect to the amp-version with a direct access to the link, then browser support for amp-pages and automatic transition to them has not yet been implemented, but is only expected. AMP is good for content pages where there are no significant number of behavioral scripts (however, we can implement various interactive infographics, mini-games, etc. inside the iframe).

All of the above led us to the intention to make AMP at home. And that's how it was:

Step 1 - Create New Templates


On the backend we use Rails, as a template engine - Slim. First of all, we create new paths in routes.rb for entities that we are interested in (in this case it will be news and the article is the main content of our site). It does not matter in principle what kind of address the amp version of the pages will have - it can be both a subdomain of amp.youpage.com/article, and, for example, youpage.com/article/amp, if only the scheme is uniform.

Then we create new templates for rendering the AMP version of our pages, and boldly remove all unnecessary from them.

Under the superfluous means the following things:
- Javascript code
- Inline-styles
- Prohibited tags in amp-html, such as: object, frame, embed, select, form, input, option, textarea (however, the input specification may still change - follow the development of the project.)

In general, it is necessary to cut out everything that complicates the rendering of the page or can block it.

def amp_strip_tags(text = '') text .gsub(%r{<img(.+?)\/>}, '') .gsub(%r{<iframe.+?\/iframe>}m, '') .gsub(%r{<script.+?<\/script>}m, '') end 


Particular attention would be paid to the head of our pages. It should have a fairly clearly defined structure, like this:

Bed sheet html
  <meta charset="utf-8"> <title>...</title> <meta name=“viewport" content=”width=device-width,minimum-scale=1,initial-scale=1” <link rel="canonical" href="{   }" /> <style amp-custom>{ }</style> <!--  --> <script type="application/ld+json">{...}</script> <!--  FOUC --> <style amp-boilerplate> body{ -webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both; -moz-animation: -amp-start 8s steps(1,end) 0s 1 normal both; -ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both; animation:-amp-start 8s steps(1,end) 0s 1 normal both; } @-webkit-keyframes -amp-start{ from{ visibility:hidden }to{ visibility:visible } } @-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}} @-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}} @-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}} @keyframes -amp-start{from{visibility:hidden}to{visibility:visible}} </style> <noscript> <style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style> </noscript> <script async src="https://cdn.ampproject.org/v0.js"></script> {amp-components scripts} 


Please note that all scripts are connected with the async attribute.

Step 2 - Shovel Styles


Depending on the implementation, we can make the AMP version as similar to a normal mobile one as possible, or completely redesign it. We chose the first path. So, for CSS processing we use Stylus, and BEM-style naming. On the mobile version, we have about the following set of files:

Long list


Obviously, we will not need some of them. Therefore, not all will be included in the style sheet for AMP, and besides, we will probably need some corrections.
In particular, inside the styles can not be applied:
- Universal selector * and: not ()
- overflow: scroll, overflow: auto (you can’t do scrolling blocks)
- filter
-! Important

This is how we get the root amp.styl:
 @import 'reset' @import 'variables' @import 'mixins' @import 'fonts' @import 'general' @import 'amp/icons' @import 'amp/blocks/**/*.styl' @import 'elements/button' _apply_media_cache() 

Having gotten rid of the above, and having corrected the style design as necessary, the resulting styles should be displayed inside the resulting page. The webpack builder is ours, and the resulting css file is inserted into the template via such a helper:

 def amp_stylesheet_content css_file_path = Rails.root.join('public').to_s + URI(stylesheet_path('amp.css')).path File.read(css_file_path) end 


Inside the head:

 <style amp-custom> =amp_stylesheet_content.html_safe </style> 


(In this case, we use raw html, since slim does not know how to create attributes with no values ​​at standard settings)

It is important that the size of the style file does not exceed 50 kB. In general, this is enough, besides, do not forget about the minification. We took the style of 35 KB.

Step 3 - Media Content Must Be Inside AMP Components


Basically, the media content of the news site can be divided into 4 categories:
- Images (perhaps a series of images - galleries)
- Video
- Social network widgets
- Special interactive (for example, mini-games, infographics, etc.)

In order to display all of this, various components are provided in AMP.

So: for images we have a picture similar to HTML5 picture amp-img:

 <amp-img alt=" " width="420px" height="280px" src="http://icdn.lenta.ru/images/2016/02/11/12/20160211121428311/pic_8dc2c0121a05e635e509d1981d4fda63.jpg" layout="responsive"></amp-img> 


As well as amp-carousel (suitable not only for images, but also for other content)

 <amp-carousel width=300 height=400> <amp-img src="my-img1.png" width=300 height=400></amp-img> <amp-img src="my-img2.png" width=300 height=400></amp-img> <amp-img src="my-img3.png" width=300 height=400></amp-img> </amp-carousel> 


and amp lightbox (normal lightbox)

 <button on="tap:my-lightbox">  !</button> <amp-lightbox id="my-lightbox" layout="nodisplay"> <div class="lightbox"> <amp-img src="my-full-image.jpg" width=300 height=800 on="tap:my-lightbox.close"> </div> </amp-lightbox> 


For video - amp-video

 <amp-video width=400 height=300 src="https://supervideo.com/videos/myvideo.mp4" poster="fallback-poster.jpg"> <div fallback> <p>Ooops! Sorry, your browser doesn't support HTML5 video!</p> </div> <source type="video/mp4" src="foo.mp4"> <source type="video/webm" src="foo.webm"> </amp-video> 


And a diverse set of widgets for popular social networks (unfortunately, VK is not among them yet).

For replacement it is convenient to use your own helper:

 def amp_img(cloud_unit, version, params={}) if cloud_unit.versions.present? && cloud_unit.versions[version.to_s].present? version = cloud_unit.versions[version.to_s] if cloud_unit.caption.present? alt = cloud_unit.caption elsif cloud_unit.alt.present? alt = cloud_unit.alt else alt = '' end attrs = { alt: strip_tags(alt), width: version.width.to_s + 'px', height: version.height.to_s + 'px', src: cloud_url(version.rel_url), class: params[:addclass], layout: params[:layout] #sizes: "(min-width: 650px) 50vw, 90vw" } content_tag('amp-img', nil, attrs) end end 


In order to make it easier for the editor to work with content, there are so-called in the admin panel. “Widgets” are boxes where you can optionally embed various content. For example, to insert -instagram or -facebook of a post it is enough for an editor to insert a link to it, from which a full-fledged widget code is then formed. We need new views for amp widgets, which is quite simple - regular values ​​pulled out (for example, the youtube-roller code) are inserted into the template of the corresponding amp component, which is then displayed on the page.

In addition, you need to connect the libraries of the required components inside the head.

The important point to focus on is that in order to speed up the rendering, the size of the media elements must be determined in advance, so we explicitly set the width and height (real) for the images and widgets.

If we want to inject some very special content into the page, then we can use the amp-iframe and implement any of the most bizarre behavior in it, without being limited to using js.

There are a number of restrictions on its use - for example, the content inside the amp-iframe can be served only via https, in addition, the amp-iframe should not be located in the first screen. Well, of course, the content can not access the DOM page, and the more so as to somehow change it. Everything that happens in the sandbox - will remain in the sandbox.
Loading of elements occurs asynchronously, so, most likely, in case of a bad connection, you will not first see their contents, but only placeholder (which, by the way, can be customized or turned off altogether). But after the content is loaded, it will become visible without any FOUC!
Instead of the social button widgets, you have to use the usual noscript option. Here, for example, for VK:

 .b-socials__button ab-socials__image.b-socials__image-vk href="http://vk.com/share.php?url=#{extlink}" target='_blank' title=("   ") 


Step 4 - Micromarking


For AMP pages, Google strongly requires the introduction of micromarking. In fact, a significant part of the sites already use this markup, but if you don’t have one yet, then it's time to start!
The schema.org is used as a dictionary, in this case, the essence of the NewsArticle perfectly fits our goals. You can insert markup into a page using JSON-LD (in my opinion, the most convenient way) or using microdata - special attributes that are set for tags with specific content. All the necessary data for this, most likely, you already have, and it remains only to substitute them into the template.

Step 5 - Analytics and Advertising


As you probably noticed, any large project begins to overgrow with various counters and metrics, like a ship - with seashells, with a similar action - slows it down. In order to somehow deal with this undesirable phenomenon, we can use the amp-pixel component, which, as the name implies, provides the functionality of a regular counter — sends a request to the specified address when the page is displayed.

 <amp-pixel src="https://foo.com/pixel?RANDOM"></amp-pixel> 


Very convenient - instead of RANDOM, a random number will be substituted.
There is also a native component of Google Analytics - amp-analytics

 <amp-analytics id="analytics1" type="googleanalytics"><script type="application/json">{ "vars": { "account": "UA-*******" }, "triggers": { "trackPageview": { "on": "visible", "request": "pageview" } } }</script></amp-analytics> 


In principle, we decided that it is worth replacing a mountain of counters with one Google Analytics, however, if this option is not allowed for you, then there are possibilities.

As far as advertising is concerned, currently, advertising content delivery systems that are widespread in the USA are mainly supported. To make friends, for example, with adFox, you can do this: get a link to the contents of the banner and place it inside the amp-iframe of a given size. Thus, advertising will come asynchronously and will never be able to prevent the page from loading.

As part of our project, we have not yet implemented advertising in AMP. Enjoy the freedom :)

Step 6 - Checking if everything is good


After you have successfully compiled your AMP versions of the pages, you need to check whether everything meets the specification so that the Google search bot processes them and includes them in the search results.

First, right on the local machine or dev server, you can open the checked page with the hash parameter # development = 1, and then look in the developer console.

If everything is OK, you will see something like this:



If not, the built-in validator will show where errors are found, and even provide links to documentation:



After you roll out to production, take a look here, and check that the microdata parses normally and has the necessary fields.

In addition, in the Google Webmaster tools you can find the “Mobile pages” tab where statistics on the indexed pages are collected, there you can find statistics and information about errors throughout the site, if any, but be careful - indexing it happens quite infrequently (once every few days), so after making changes you have to wait.

Speed ​​measurement


The speed of loading amp versions of pages is much higher, and the worse the quality of the connection, the more noticeable the difference. In general, we can talk about at least a 2-fold increase in download speed. Let's compare with the help of tools.pingdom.com indicators of a usual mobile page:



and amp versions:



The difference, as they say, is obvious. It is especially interesting to consider the waterfall of loading resources and compare (I will leave this task for interested readers).

For details in the nuances I recommend to see the official github of the project and documentation .

Source: https://habr.com/ru/post/280602/


All Articles