Create AMP pages using Nuxt.js
AMP Project pages are consistently fast and accessible and have premium placement in Google search results. With a few tweaks to the rendering process, it's possible to make Nuxt.js page AMP powered and reap the benefits!
The process for “ampify-ing” a page involves hooking into the render function of Nuxt.js in the hooks
configuration options to render pages as AMP compatible either in place of Nuxt.js pages or in their own namespace via the amphtml
meta link.
// nuxt.config.js
const ampify = require('./plugins/ampify')
module.exports = {
/*
** Hooks configuration
*/
hooks: {
// This hook is called before saving the html to flat file
'generate:page': (page) => {
if (/^\/amp\//gi.test(page.route)) {
page.html = ampify(page.html)
}
},
// This hook is called before serving the html to the browser
'render:route': (url, page, { req, res }) => {
if (/^\/amp\//gi.test(url)) {
page.html = ampify(page.html)
}
}
}
}
In this example, only pages under the /amp/
directory will be converted to AMP pages. These methods mutate the state of the page
object after rendering, so the changes being applied will be performed on already rendered HTML files using RegEx style mutations utilizing the ampify
function we have imported from the ampify.js
plugin file.
// plugins/ampify.js
const ampScript =
'<script async src="https://cdn.ampproject.org/v0.js"></script>'
const ampBoilerplate =
'<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>'
module.exports = (html) => {
// Add ⚡ to html tag
html = html.replace(/<html/gi, '<html ⚡')
// Combine css into single tag
let styleConcat = ''
html = html.replace(
/<style[^>]*data-vue-ssr[^>]*>(.*?)?<\/style>/gi,
(match, sub) => {
styleConcat += sub
return ''
}
)
html = html.replace(
'</head>',
`<style amp-custom>${styleConcat}</style></head>`
)
// Remove preload and prefetch tags
html = html.replace(/<link[^>]*rel="(?:preload|prefetch)?"[^>]*>/gi, '')
// Remove amphtml tag
html = html.replace(/<link[^>]*rel="(?:amphtml)?"[^>]*>/gi, '')
// Remove data attributes from tags
html = html.replace(/\s*data-(?:[^=>]*="[^"]*"|[^=>\s]*)/gi, '')
// Remove JS script tags except for ld+json
html = html.replace(
/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
(match) => {
return /application\/ld\+json/gi.test(match) ? match : ''
}
)
// Replace img tags with amp-img
html = html.replace(/<img([^>]*)>/gi, (match, sub) => {
return `<amp-img ${sub} layout=intrinsic></amp-img>`
})
// Add AMP script before </head>
html = html.replace('</head>', ampScript + ampBoilerplate + '</head>')
return html
}
The ampify script first replaces the opening <html>
tag with one including the AMP signifier ⚡
. The script then takes all <style>
tags and combines them into a single <style>
with the amp-custom
attribute. The script then strips out all preload and prefetch tags, any <link rel="amphtml">
tags, and all <script>
tags except for those used for JSON-LD structured data. The script then converts any <img>
tags to <amp-img>
tags, and finally adds imports for the two required AMP boilerplate snippets.
With the Javascript removed from the page some features will become unavailable, but most Nuxt.js projects should function fine. Links will no-longer be preloaded and rendered in place as an SPA, but will instead cause an actual page location change and re-render. Analytics and ad services will no longer function, but there are AMP plugins available to solve these issues in a highly performant manner (AMP Analytics, AMP Ads).
This script does the heavy lifting on a few of the more programmatic AMP modifications, but there are still a few additional modifications that will likely be required. For instance, while the <img>
tag is converted to an <amp-img>
tag, it will fail validation without a width
attribute. Also, CSS specificity exception !important
will cause your CSS to fail AMP validation.
To test what other steps will be required to make your page 100% AMP compliant, run it through the AMP Project validator. The next step is to head over to the AMP Project site and read through the “Create your first AMP Page” guide where you will find many useful tips for improving usability and SEO.