How Pages work in Next.js

Follow

When using Agility CMS, we believe Editors should have full control over the pages on their website and should not need to rely on a developer. The agilitycms-next-starter makes it easy to source content and also generates the pages of your website based on your sitemap in Agility CMS.

Editors in the CMS can control what pages are available, what the URLs are, what page template they're using, and exactly what UI Components (Modules) make up each and every page.

Page Generation

The following example is based on the Next.js Starter Blog Template instance. Don't have one? Sign up for one!

Screen_Shot_2020-09-29_at_9.11.39_AM.png

The above figure represents a sitemap of Pages as well as the UI Components (Modules) that are on each page - all are managed in the CMS. 

This means that when a build occurs in your Next.js site, the following pages will be auto-generated for you:

  • /
  • /posts
  • /posts/* - your dynamic page route for all of your blog posts (i.e. /posts/my-first-post)
  • /about

Page Rendering

When a page is being generated during build time, the final step is rendering the page to HTML. In the agilitycms-next-starter site, the [...slug].js file located within the pages directory takes care of this for you. It returns a Layout.js component that passes all necessary props to render each page.

Sample source code for ./pages/[...slug].js

import React, { Component } from "react";
import { getAgilityPageProps, getAgilityPaths } from "agility/agility.node";
import { handlePreview } from "agility/agility.browser";
import Layout from "components/agility-global/Layout";

class AgilityPage extends Component {
  render() {
    handlePreview();

    return <Layout {...this.props} />
  }
}

export async function getStaticProps(context) {
  const props = await getAgilityPageProps({ context });
  return {
    props: props,
    revalidate: 1, //will refresh page every 1 second on Vercel...
  };
}

export async function getStaticPaths() {
  const paths = await getAgilityPaths();
  return {
    paths: paths,
    fallback: true,
  };
}

export default AgilityPage;

Page Rendering Process

  1. getStaticProps is a function in Next.js that will pre-render a page at build time using the props that it returns. getAgilityPageProps will get all the context for a particular page and return it as your props
    export async function getStaticProps(context) {
      const props = await getAgilityPageProps({ context });
      return {
        props: props,
        revalidate: 1, //will refresh page every 1 second on Vercel...
      };
    }

    Instant Builds?

    Take note of the revalidate tag. When your Next.js and Agility CMS site is hosted on Vercel, the revalidate tag turns your deployment into an instant build machine - meaning your pages are built as they change!
  2. The props are then passed into the AgilityPage component which returns a Layout component that will handle your Page Templates.
    class AgilityPage extends Component {
      render() {
        handlePreview();
    
        return <Layout {...this.props} />;
      }
    }
  3. The Layout.js component located within the ./components/agility-global directory resolves which Page Template should be rendered (<AgilityPageTemplate />) and passes the necessary content as props. The Layout.js component will also handle your site SEO.
    import PreviewBar from "./PreviewBar";
    import GlobalHeader from "./GlobalHeader";
    import GlobalFooter from "./GlobalFooter";
    import { useRouter } from "next/router";
    import Head from "next/head";
    import dynamic from "next/dynamic";
    import tw from "twin.macro";
    
    const MainElem = tw.main`p-8`;
    
    import Error from "next/error";
    
    export default function Layout(props) {
      const { page, sitemapNode, dynamicPageItem, notFound } = props;
    
      console.log(props);
    
      // If the page is not yet generated, this will be displayed
      // initially until getStaticProps() finishes running
      const router = useRouter();
      if (router.isFallback) {
        return
      }
    
      console.log("notFound", notFound);
      if (notFound === true) {
        return ;
      }
    
      const AgilityPageTemplate = dynamic(() =>
        import("components/agility-pageTemplates/" + props.pageTemplateName)
      );
    
      if (dynamicPageItem?.seo?.metaDescription) {
        page.seo.metaDescription = dynamicPageItem.seo.metaDescription;
      }
    
      return (
        <>
          <Head>
            <title>{sitemapNode?.title} - Agility CMS Sample Blog</title>
            <meta name="viewport" content="initial-scale=1.0, width=device-width" />
            <meta name="description" content={page.seo.metaDescription} />
            <meta name="generator" content="Agility CMS" />
            <meta name="agility_timestamp" content={new Date().toLocaleString()} />
            {dynamicPageItem?.seo?.ogImage && (
              <meta property="og:image" content={dynamicPageItem.seo.ogImage} />
            )}
            <link rel="stylesheet" href="/prose.css" />
          </Head>
          <PreviewBar {...props} />
    
          <MainElem>
            <GlobalHeader {...props} />
            <AgilityPageTemplate {...props} />
            <GlobalFooter {...props} />
          </MainElem>
        </>
      );
    }
  4. Page Templates in Agility CMS use the <ContentZone /> component to identify where modules for specific zones should be rendered within the Page Template.

    import React, { Component } from 'react';
    import ContentZone from 'components/agility-global/ContentZone'
    
    class OneColumnTemplate extends Component {
        render() {
            return (
            <div className="one-column-template">
                <ContentZone name='MainContentZone' {...this.props} />
            </div>
            );
        }
    }
    
    export default OneColumnTemplate;
  5. Within each <ContentZone /> component defined in the template, each module that exists on the content zone in the CMS is resolved to a react component and rendered in-place.

    Here's an example from the Rich Text Area Module found within the ./components/agility-modules directory:

    import React from "react";
    import { renderHTML } from "agility/utils";
    import tw from "twin.macro";
    
    import { Container, ContentWithPaddingLg } from "components/misc/Layouts";
    export const RichText = tw.div`prose prose-sm sm:prose lg:prose-lg xl:prose-xl`;
    
    export default (props) => {
      return (
        <Container>
          <ContentWithPaddingLg>
            <RichText
              className="prose"
              dangerouslySetInnerHTML={renderHTML(props.fields.textblob)}
            ></RichText>
          </ContentWithPaddingLg>
        </Container>
      );
    };

    Learn How Modules work in Next.js

1 out of 1 found this helpful

Comments

0 comments

Please sign in to leave a comment.