Accelerated Mobile Pages, or AMP, is an open source web components framework that increases the speed of loading webpages. AMP imposes strict guidelines on the HTML, CSS, and JavaScript of a webpage, controlling how external resources like media, ads, and other scripts are loaded.
In this tutorial, we’ll navigate through some of AMP’s guidelines, learning how to manage some of the trade-offs that arise. We’ll cover how to display resource-consuming elements on a webpage while still adhering to AMP’s rules by using AMP components in a Next.js project.
If you wish to follow along, all of the code for this tutorial is available on my GitHub. Let’s get started!
Limitations of AMP
AMP optimizes webpage loading by preventing developers from using custom elements that include resources like images, video, and audio. Similarly, developers can’t write custom JavaScript for tasks like displaying dynamic ads, embedding social media posts, and creating interactive forms. To work around these limitations, we’ll use AMP components.
AMP components
AMP components are custom-written pieces of HTML that we can use to add complex features to our webpage while still remaining compliant with AMP’s standards.
Currently, the AMP component catalog includes built-in components for many common tasks, like adding images, calculating webpage analytics, and displaying ads. Because built-in components are included in the base library of AMP, you don’t need to include them explicitly in your code.
Extended components are extensions to the base of the library and are not included by default. In your code, you’ll need to include extended components explicitly as custom elements. For example, you may wish to add page analytics with amp-analytics
or add a lightbox with amp-lightbox
.
The catalog also includes experimental components, which are released but not yet supported for wide use. If you can’t find what you need in the component catalog, you may wish to write your own AMP component!
Now that we know what AMP components are available, let’s add one to a webpage!
Turn a webpage into an AMP page
Before we can add an AMP component to our webpage, we’ll need to configure our webpage as an AMP page. The amp
configuration accepts two types of values, true
and hybrid
. Entering a value of true
turns the webpage into an AMP HTML page. Entering a value of hybrid
creates two versions of the webpage, one in AMP HTML and one in standard HTML, with standard HTML as the default.
Let’s configure our webpage as an AMP page with true
:
export const config = { amp: true }
Now, let’s create a true AMP page by running the code block below:
export default function Page = () => { return <h1>My First AMP Page</h1> }
When we export the true AMP page, Next.js will create two versions of the page: an optimized version for your users and an unoptimized version for search engines.
To create a hybrid AMP page, all you have to do is change the configuration value of the page to hybrid
:
export const config = { amp: 'hybrid' } export default function Page = () => { return <h1>My First AMP Page</h1> }
To visit the AMP page, you’ll need to add ?amp=1
to the end of the URL. Additionally, because hybrid
isn’t a Boolean value like true
, you’ll need to surround it with quotes.
Hybrid AMP pages require you to write valid HTML for both AMP and standard HTML pages. To render the correct HTML, we can use the useAmp
React Hook.
Importing the useAmp
React Hook
Add the useAmp
React Hook to your webpage by importing the package below:
import { useAmp } from 'next/amp'
Next, create a variable that saves the output of the React Hook:
const isAmp = useAmp()
Now, you can use either a ternary operator or an if
statement to render the correct HTML:
{isAmp ? ( // AMP component ) : ( // Standard HTML ) }
Finally, we’ll put everything together! In the example below, we’ll use amp-img
, an AMP component that loads images, to display an image on our webpage:
import { useAmp } from "next/amp"; import Image from "next/image"; export const config = { amp: "hybrid" }; export default function Hybrid() { const isAmp = useAmp(); return ( <div> <h1>Hybrid AMP Page</h1> {isAmp ? ( <amp-img alt="A view of the sea" src="/chiangmai.jpeg" width="640" height="360" ></amp-img> ) : ( <Image alt="A view of the sea" src="/chiangmai.jpeg" width="640" height="360" /> )} </div> ); }
In the AMP version in the example above, we don’t have to use the default HTML <img>
tag. Additionally, because amp-img
is included as a built-in component, we didn’t have to import it into our webpage! If a component from the AMP component library is not included in the base library, we’ll receive the following notification that it requires an external script:
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.2.js"></script>
In Next.js, you’ll need to include this script
tag in the head of your document, as seen in the code block below:
<Head> <script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.2.js" ></script> </Head>
Validating AMP pages
Before we export our AMP page, let’s make sure it meets AMP’s requirements. There are plenty of methods for adding validation, for example, npm packages, command-line tools, browser extensions, and the developer console! Let’s take a look at the built-in method for AMP validation in Next.js, amphtml-validator
.
During building and exporting, amphtml-validator
requires that AMP pages meet the AMP specification. Any warnings or errors will be displayed in the terminal.
For example, let’s say that you try to use a regular HTML <img>
tag instead of amp-img
. It will result in an error on export, as seen in the code below:
Amp Validation /hybrid?amp=1 error The parent tag of tag 'img' is 'div', but it can only be 'i-amphtml-sizer-intrinsic'. error The parent tag of tag 'img' is 'div', but it can only be 'i-amphtml-sizer-intrinsic'. > Build error occurred Error: AMP Validation caused the export to fail. https://nextjs.org/docs/messages/amp-export-validation
If you want to use a custom AMP validator, you can add the path to your custom validation rules in the next.config.js
file:
module.exports = { amp: { validator: './custom_validator.js', }, }
Exporting AMP pages in Next.js
If there are no validation errors, running next export
will export all of our pages to static HTML pages. Next.js automatically detects if a page supports AMP and exports the page in the correct format.
As mentioned earlier, a hybrid AMP page will be exported as two files. For example, say we have a hybrid page called pages/blog.js
. It would be exported as out/blog.html
, a standard HTML page with a client-side React runtime, and out/blog.amp.html
, an AMP HTML page.
Next.js will automatically insert a link from the AMP page to the standard HTML page, and vice versa, as seen in the following two code snippets, respectively:
<link rel="amphtml" href="/blog.amp.html" /> <link rel="canonical" href="/blog" />
If pages/blog.js
were a true AMP page, it would export a single HTML file called out/blog.html
.
Conclusion
Now, you know how to get started with AMP components in Next.js!
In this tutorial, we covered built-in, extendable, and experimental AMP components, true and hybrid AMP pages, and the useAmp
React Hook. Then, we learned how to validate and export AMP pages in Next.js.
At the time of writing, AMP only supports CSS-in-JS for styling. However, support for CSS Modules is being developed, and you can find some workarounds on GitHub.
Similarly, there is no official support for TypeScript. Although it is on the roadmap, there is no scheduled release date yet. As a workaround, you can create a file with custom types called amp.d.ts
inside your project and add custom types for AMP.
I hope you enjoyed this tutorial! If you find yourself stuck, leave a comment, and I’ll do my best to help you out.