Accelerated Mobile Pages (AMP) using Middleman

Accelerated Mobile Pages (AMP) using Middleman

Here, we will talk about how to create AMP blog pages in Middleman . If you are not familiar with AMP, I recommend reading this blog post in which I talk about what AMP is and why it is useful.


So you want to create AMP blogs in a static site generator? Well, first you start by selecting a static site generator - here I have chosen Middleman. While I work with Middleman, this can be effectively used in any Ruby-based static site generator.

It is definitely not recommended to have only AMP blog pages, a normal blog page should also be there for all the desktop viewers.

THE LAYOUT

So let’s create the AMP blog layout first,

<!doctype html>
<html amp lang="en">
<head>
<meta charset="utf-8" />
<script async src="https://cdn.ampproject.org/v0.js"></script>
<meta
name="viewport"
content="width=device-width,minimum-scale=1,initial-scale=1"
/>
<%= partial "partials/ampmeta" %>
<style amp-custom>
<%= partial "stylesheets/ampstyle.css" %>
</style>
<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
custom-element="amp-social-share"
src="https://cdn.ampproject.org/v0/amp-social-share-0.1.js"
></script>
<script
async
custom-element="amp-sidebar"
src="https://cdn.ampproject.org/v0/amp-sidebar-0.1.js"
></script>
</head>
<body>
<%= partial "partials/ampsidebar" %> <% content:yield %> <%= content %> <%=
partial "partials/ampfoot_nav" %>
</body>
</html>

So what is this? Here we give the basic layout for all the blog pages. Most of what is on this page is defined in the official AMP description.

In line 7, we give <%= partial "partials/ampmeta" %> which gives us all the meta tags that are for that specific page, all the meta tags that are supported in normal HTML will be supported here.

In line 8 to 10, we add the styles to the CSS, as the styles should be inlined in AMP - we just add the stylesheet as a partial so that it adds here as an inline style.

Then some styles and scripts which are required by AMP, the social share and sidebar script are provided by the AMP Project to give us the social sharing and sidebar functionality without the use of external Javascript. Oh yeah, you can’t use any other Javascript other that the ones that are provided. This is the point where most of the developers shy away from Javascript, but we’ll move forward.

THE CONFIG

Let’s dive right in,

require 'fastimage'
require 'nokogiri'
set :markdown_engine, :kramdown
set :markdown, fenced_code_blocks: true, disable_indented_code_blocks: true, strikethrough: true, smartypants: true, with_toc_data: true
activate :blog do |blog|
blog.name: "svramp"
blog.prefix: "amp/svr"
blog.permalink: "{title}"
blog.sources: "{year}-{month}-{day}-{title}.html"
blog.summary_separator:/\(READMORE\)/
blog.paginate:true
blog.page_link: "/{num}"
blog.per_page:15
blog.layout: "ampsvr_layout"
blog.new_article_template:File.expand_path('new_article.markdown.erb', File.dirname(__FILE__))
end
helpers do
def convert(paragraph)
paragraph.gsub! '<img', '<amp-img'
end
end

The fastimage and nokogiri gems are used for finding the size of the images, which we will talk about soon.

Then in line 4 and 5 we define the markdown engine which converts .md files into HTML, and then in line 7 we see the actual blog gem which helps us make the blog pages using our layout - more info on this can be found here .

Then we have a simple img to amp-img converting helper because sometime we inline image tags in our blog post and this can help with that.

THE MAGIC

And then we have some extra work,

<%
doc:Nokogiri::HTML::DocumentFragment.parse(content)
doc.search('img').each do |img|
src:img.attribute('src')
if img['src'] =~ /http(.*)/
img['width']:800
img['height']:400
else
img['width']:FastImage.size('source/'+src)[0]
img['height']:FastImage.size('source/'+src)[1]
end
end
doc.search('amp-img').each do |img|
if img['layout'] == 'responsive'
src:img.attribute('src')
img['width']:FastImage.size('source/'+src)[0]
img['height']:FastImage.size('source/'+src)[1]
end
end
content:doc.to_html
content.gsub!("<img", '<amp-img layout="responsive"')
content.gsub!("<iframe", '<amp-iframe layout="responsive" sandbox="allow-scripts allow-same-origin allow-popups" allowFullScreen
frameborder="0" ')
content.gsub!("</img", "</amp-img")
content.gsub!("</iframe", "</amp-iframe")
%>

In here, we use nokogiri to select all the images and give them a definite height and width because AMP needs definite size values defined to them.

And then we substitute some image and i-frame tags with proper amp tags.


So there you have it, that was a brief intro on how to write AMP for Middleman, hope you found something useful in it and let me know @praveenjuge if you have something else to discuss.


Some related articles -