What Challenges I Faced in Integrating Web Stories into a Next.js Blogging Website
Nitish Kumar Singh
Dec 24, 2023Hello, developers! In this blog post, I will discuss the challenges I faced while integrating Web Stories into my blogging website, built using Next.js.
I use Next.js for my site, and the image below shows how I manage routing in Next.js for my website at the time of writing this post.
Web Stories
Web stories are short, immersive, and visually engaging narratives presented in a slideshow format. Combining images, videos, and text, they offer an amazing way to share information. Designed for quick information sharing, web stories provide a mobile-friendly, bite-sized storytelling experience, ideal for capturing attention and conveying information in a concise and engaging manner.
To build Web Stories, we need to follow the AMP project, designed for writing HTML code using components provided by this project and some conditions. If you are not familiar with Web Stories, you can explore more about it by visiting Web-Stories, Creating your first Web Story, and reading the AMP HTML Specification.
The following code shows an example of HTML code for a Web Story, "Joy of Pets."
<!DOCTYPE html>
<html ⚡>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"/>
<noscript>
<style amp-boilerplate>
body {
-webkit-animation: none;
-moz-animation: none;
-ms-animation: none;
animation: none;
}
</style>
</noscript>
<title>Joy of Pets: My</title>
<link rel="canonical" href="pets.html">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-story" src="https://cdn.ampproject.org/v0/amp-story-1.0.js"></script>
<script async custom-element="amp-video" src="https://cdn.ampproject.org/v0/amp-video-0.1.js"></script>
<link href="https://fonts.googleapis.com/css?family=Oswald:200,300,400" rel="stylesheet"/>
<style amp-custom>
amp-story {
font-family: "Oswald", sans-serif;
color: #fff;
}
amp-story-page {
background-color: #000;
}
h1 {
font-weight: bold;
font-size: 2.875em;
font-weight: normal;
line-height: 1.174;
}
p {
font-weight: normal;
font-size: 1.3em;
line-height: 1.5em;
color: #fff;
}
q {
font-weight: 300;
font-size: 1.1em;
}
amp-story-grid-layer.bottom {
align-content: end;
}
amp-story-grid-layer.noedge {
padding: 0px;
}
amp-story-grid-layer.center-text {
align-content: center;
}
.wrapper {
display: grid;
grid-template-columns: 50% 50%;
grid-template-rows: 50% 50%;
}
.banner-text {
text-align: center;
background-color: #000;
line-height: 2em;
}
</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>
</head>
<body>
<amp-story standalone title="Joy of Pets" publisher="AMP tutorials"
publisher-logo-src="assets/AMP-Brand-White-Icon.svg" poster-portrait-src="assets/cover.jpg">
<amp-story-page id="cover">
<amp-story-grid-layer template="fill">
<amp-img src="assets/cover.jpg" width="720" height="1280" layout="responsive" alt=""> </amp-img>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical">
<h1>The Joy of Pets</h1>
<p>By AMP Tutorials</p>
</amp-story-grid-layer>
</amp-story-page>
<amp-story-page id="page1">
<amp-story-grid-layer template="vertical">
<h1>Cats</h1>
<amp-img
src="assets/cat.jpg"
width="320"
height="580"
layout="responsive">
</amp-img>
<q>Dogs come when they're called. Cats take a message and get back toyou. --Mary Bly</q>
</amp-story-grid-layer>
</amp-story-page>
<!-- Page 2 (Dog): 2 layers (fill + thirds) -->
<amp-story-page id="page2">
<amp-story-grid-layer template="fill">
<amp-img
src="assets/dog.jpg"
width="720"
height="1280"
layout="responsive"
>
</amp-img>
</amp-story-grid-layer>
<amp-story-grid-layer template="thirds">
<h1 grid-area="upper-third">Dogs</h1>
<p grid-area="lower-third">
Dogs were probably the first tame animals. They have accompanied
humans for some 10,000 years. Some scientists assert that all dogs,
domestic and wild, share a common ancestor in the small South Asian
wolf.
</p>
</amp-story-grid-layer>
</amp-story-page>
<!-- Page 3 (Bird): 3 layers (fill + vertical + vertical) + Audio-->
<amp-story-page id="page3" background-audio="assets/bird-singing.mp3">
<amp-story-grid-layer template="fill">
<amp-img
src="assets/bird.jpg"
width="720"
height="1280"
layout="responsive"
>
</amp-img>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical">
<h1>Birds</h1>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" class="bottom">
<q animate-in="fly-in-left"
>A bird is three things: Feathers, flight and song, And feathers are
the least of these. -Marjorie Allen Seiffert</q
>
</amp-story-grid-layer>
</amp-story-page>
<!-- Page 4 (Rabbit): 3 layers (fill (video) + vertical + vertical) -->
<amp-story-page id="page4">
<amp-story-grid-layer template="fill">
<amp-video
autoplay
loop
width="720"
height="1280"
poster="assets/rabbit.jpg"
layout="responsive"
>
<source src="assets/rabbit.mp4" type="video/mp4" />
</amp-video>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical">
<h1>Rabbits</h1>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" class="bottom">
<p>
Rabbits can learn to follow simple voice commands and come when
called by name, and are curious and playful.
</p>
</amp-story-grid-layer>
</amp-story-page>
<!-- Page 5 (Collage): 2 layers + animations -->
<amp-story-page id="page5">
<amp-story-grid-layer template="vertical" class="noedge">
<div class="wrapper">
<amp-img
src="assets/cat.jpg"
width="720"
height="1280"
layout="responsive"
animate-in="fade-in"
animate-in-delay="0.4s"
>
</amp-img>
<amp-img
src="assets/dog.jpg"
width="720"
height="1280"
layout="responsive"
animate-in="fade-in"
animate-in-delay="0.6s"
>
</amp-img>
<amp-img
src="assets/bird.jpg"
width="720"
height="1280"
layout="responsive"
animate-in="fade-in"
animate-in-delay=".8s"
>
</amp-img>
<amp-img
src="assets/rabbit.jpg"
width="720"
height="1280"
layout="responsive"
animate-in="fade-in"
animate-in-delay="1s"
>
</amp-img>
</div>
</amp-story-grid-layer>
<amp-story-grid-layer template="vertical" class="center-text">
<p class="banner-text" animate-in="whoosh-in-right">
Pets can lower your stress levels!
</p>
</amp-story-grid-layer>
</amp-story-page>
</amp-story>
</body>
</html>
According to the AMP HTML Specification, I need to completely change HTML code to the above format, where we need to add ⚡
or amp
as an attribute in the HTML opening tag, keep only one amp-story
tag as a child in the body
tag, and add some scripts
and styles in the head section.
The following image shows the folder structure of "Routing-Types" that I have tried for interacting with web stories.
I want to show a preview of all Web Stories using page.js
of the web-stories
folder when the URL path is "/web-stories"
and show a Web Story using "page.js" of the "[story-path]"
folder when the URL path is "web-stories/routing-in-next-js_story-id.
But the problem is that when the story page is routed, we need to change HTML to AMP HTML. For doing this, we need to conditionally render "RootLayout" for the traditional web page where the Navbar and more components do not change when navigating to different URLs and the AMP web page where we include only one "amp-story
" tag that comes from the story page as children props.
I have tried both Next.js Parallel Routing and Routes Groups, but it did not work as I wanted. In Routes Groups, it works well but reloads the page every time when a new story is opened from the stories page because of Routes Group shifting.
I want to show the Story-Page without a page reload, whether the story opens directly or by navigating from the "Web-Stories-Page" with Server-Side rendering.
So, I'm going to take complete control of my blogging website using Express.js on the back-end side on Vercel and manage the front-end using pure JavaScript.
If anyone has ideas on how to build it using Next.js, please provide only some hints or suggestions on how to achieve this using Next.js because taking full control over the front-end and back-end is painful and requires writing a lot of code. Thanks in advance.