How to Use Nuxt AMP Module to Create Accelerated Mobile Pages

April 22nd 2020

Accelerated Mobile Pages (AMPs) are a syntax format for web pages to create fast, performant websites that are optimized for mobile users. AMP pages are similar to static site generated pages such as those generated by Gatsby.js or Nuxt.js in that they are optimized for performance, but they have very apparent differences. The biggest difference is that AMP pages have specific html format that needs to be adhered to in order for the page to be considered an AMP. Also, to ensure small page sizes, AMP format does not allow JavasScript (outside of the one required external JavaScript file which includes and loads the AMP JS library). Because of these differences, AMPs are going to look quite different than their static generated cousins. So why would you want to use AMPs over SSG pages?

Benefits of AMP

The greatest benefit of accelerated mobile pages is going to be the fact that the AMP project is backed and endorsed by Google themselves. This means that they support the AMP standard and we do know that speed, security and mobile accessibility are very large search ranking factors. All together, AMP pages are going to rank higher in search results because of their page speed and security and the syntax format endorsed by Google and other search engines.

Using the Nuxt AMP Module

Previously, before the official @nuxtjs/amp module we had to do a lot more work and had a lot fewer options to generate AMP pages using Nuxt. This required you to hook into Nuxt lifecycle events and run regular expressions on the outputted HTML to change them into AMP pages. Fortunately, the @nuxt/amp module does a lot of the heavy lifting for us and provides a lot more options such as the mode option which allows us to identify if we want pages to be generated as both AMP pages and regular Nuxt pages. It also provides the ability for us to specify a custom layout for our AMP pages so we can create a more simple layout or change out our navigation for an AMP compatible componentshttps://amp.dev/documentation/components/ in our layout. Speaking of components this is another benefit of using the @nuxtjs/amp module as it detects AMP components inside pages and injects the required AMP JavaScript Files for those specific components.

Installing the Nuxt AMP Module

Installation for the module is simple. All you need to do is navigate to your nuxt project and you can use your package manager of choice to run:

yarn add @nuxtjs/amp
//or
npm i @nuxtjs/amp

Now with our dependency installed we can open our nuxt.config.js to add it to our modules array:

module.exports = {
  modules: [
    '@nuxtjs/amp'
  ],
  amp: {
    //module options here
  }
}

The @nuxtjs/amp module gives us options that we can include at a global module level and some options can be added/overriden at the page configuration level.

Nuxt AMP Configuration

One of the first configuration options we want to set at the module level is the origin property. The origin property is the main domain of the nuxt site and is used to create the canonical link for pages the hyrbid pages that have both amp pages and regular site pages. The canonical link in AMP is used to ensure you don’t have duplicate content and Google and the other search engines can serve the AMP pages for mobile experience but can also index and serve the regular page when necessary. We are going to use an environment variable to set the origin property. First, install the dotenv node package to use inside our nuxt.config.js by running:

yarn add dotenv
//or
npm i dotenv
require('dotenv').config()

module.exports = {
  modules: [
    '@nuxtjs/amp'
  ],
  amp: {
    origin: process.env.ORIGIN_URL || 'http://localhost:3000'
  }
}

Now we’re able to create a .env file and add our ORIGIN_URL such as:

ORIGIN_URL="https://example.com"

Now when AMP generates hybrid pages such as a page found at ./pages/about.vue each page generated will have a <link> tag with the appropriate rel attribute such as:

This link tag will be added to the to the non-AMP page:

<link rel="amphtml" href="https://www.example.com/amp/about">

And this to the AMP page:

<link rel="canonical" href="https://www.example.com/about">

The next option we can look at adding to our amp module options is the mode property. This property allows us to identify if we want our nuxt pages to be generated in a hybrid mode which generates both AMP versions of the page and non AMP versions. If we want all of our pages to be served as AMP we can use the only option. The mode option defaults to hybrid as that is what most Nuxt projects would want.

Default behaviour of amp module. (only all pages serve in AMP mode by default, hybrid pages serves in both normal and AMP mode, false pages does not serve AMP by default )

https://github.com/nuxt-community/amp-module/blob/master/docs/api/options.md
require('dotenv').config()

module.exports = {
  modules: [
    '@nuxtjs/amp'
  ],
  amp: {
    origin: process.env.ORIGIN_URL || 'http://localhost:3000',
    mode: 'hybrid', //could use `only` or `false` as well
  }
}

Finally, we can explore the routeAliases option. If your app uses AMP only on a few routes you can provide those routes into an Array. Routes are absolute, without ‘/amp’ prefix, eg. ['/about', '/contact']. This would specify the routes that you want to use to generate as AMP pages. Note, that the routeAliases option does not work for dynamic routes such a dynamic page route found at /pages/post/_id.vue etc.

Nuxt AMP Page Configuration

With the @nuxtjs/amp module installed you have a few options at the nuxt page level that are available to set within the nuxt page component. The two options that you have here are: amp and ampLayout. The amp option allows you to override the mode option specified at the module level. For instance, if you have your mode set to hybrid but you know that you do not want one of your pages to be generated as an AMP page you can set the amp: false within your page export such as:

<template>
  <div>
    <h1>Not an AMP Page</h1>
  </div>
</template>
<script>
export default {
  amp: false
}
</script>

This will ensure that your page will not contain an AMP counterpart. Lastly, you can set the option for ampLayout which will specify which layout the amp generator should use to generate the amp page. This option is recommended because AMP pages more than likely will need to be customized to remove JavaScript functionality in your header/footer/sidebar components that are typically included in your default nuxt layout. Instead, these components can be replaced by the appropriate AMP Component and included inside your ampLayout component.

Creating AMP Layout in Nuxt

It is recommended to create a special layout for your AMP pages. The @nuxtjs/amp module makes this easy with the ampLayout property on the page level. This allows us to use AMP Components within our AMP Layout. Let’s say we create a layout at ./layouts/amp.vue which could look like:

<template>
  <amp-body>
    <amp-sidebar id="sidebar1" layout="nodisplay" side="right">
      <ul>
        <li>Nav item 1</li>
        <li><a href="#idTwo" on="tap:idTwo.scrollTo">Nav item 2</a></li>
        <li>Nav item 3</li>
        <li><a href="#idFour" on="tap:idFour.scrollTo">Nav item 4</a></li>
        <li>Nav item 5</li>
        <li>Nav item 6</li>
      </ul>
    </amp-sidebar>
    <Nuxt />
  </amp-body>
</template>
<script>
export default {

}
</script>
<style>
  @import "~/assets/styles/default.amp.css"
</style>

There are a couple important key points in the layout that we created. First, we are using the <amp-body> which is required for the use of specific AMP components such as the <amp-sidebar> component. We are also moving the imported default.amp.css out of our nuxt.config.js and importing it into our <style> tag inside our layout. It’s recommended that you do this for both your AMP Layout pages and your non AMP Layout pages so as not to include any css globally in the nuxt.config.js file.

However we recommend to create a separate style file for AMP pages and import it in AMP layout, also remove styles from nuxt.config and import those files in default layout instead.

https://github.com/nuxt-community/amp-module/blob/master/docs/guide/styling.md

AMP Components

As mentioned previously, the AMP syntax offers custom components that allow us to add functionality, interactivity and design to our AMP pages (since we are not allowed to use any JavaScript outside of the AMP scripts). The @nuxtjs/amp module detects if components are included within a page and adds the required corresponding amp script to our final page output. To see a list of amp components that the module supports you can consult the AMP elements page to see if the component is supported.

@nuxtjs/amp automatically detect AMP elements inside page and inject required scripts.

https://github.com/nuxt-community/amp-module/blob/master/docs/api/amp-elements.md

Conclusion

The @nuxtjs/amp module is a great utility for us to create AMP pages in our Nuxt.js module. It allows us to define pages that we want to generate as both AMP pages and regular Nuxt pages. We can create and define a specific layout for AMP pages to include AMP components, in which the module will include the required AMP scripts for us in our rendered pages. Enjoy creating high performant, fast and secure pages using the AMP protocol in your Nuxt project!