DEV Community

Joel Varty
Joel Varty

Posted on

The Genius of NextJS and Gatsby as Static Site Generators

At Agility CMS we've chosen to create starter sites for both NextJS and Gatsby. Both are static site generators built on top of React, but they take a very different approach to how they actually generate the static html/js/css for a website.
Or do they?

GitHub logo agility / agilitycms-nextjs-starter-2020

A starter NextJS website using Agility CMS, Tailwinds CSS, and several pre-built components.

GitHub logo agility / agility-gatsby-starter

A sample GatsbyJS website using the Agility CMS Gatsby source plugin

They both actually do one thing in a very similar way, and I think it's just genius: they give you a "hook" to specify the JSON data that will be used to generate the output for the site. This ends up being the "props" variable that gets passed to your React components. This data is used both during the build process on the server and also ON THE CLIENT SIDE.

That's right - your React code is executed during BUILD time and also in the BROWSER, so the execution of your code can happen in 2 different contexts. That's a little weird, at first, but if you're smart about it, you can make this work for you.

First of all, having that JSON data available is what makes NextJS and Gatsby pretty magical. It means that, as a framework on top of React, they can route pages after the first page-load without doing a full page reload - all that's needed is that extra JSON and whatever extra dependencies are on the new page.

You can see this on pretty much any Gatsby or NextJS site - if the developers have used the <Link> component correctly.

One area where I saw a huge performance improvement was on a listing page. Check out the blog listing page here: https://agilitycms.com/resources/posts

Originally, this page was rendered on the front-end using this module: which had to do calls back to the server every time more posts needed to be loaded.

loadMore(skip, take) {

        var url = `/Listing/Posts?skip=${skip}&take=${take}`

        fetch(url)
            .then(response => response.json())
            .then(data => {

                let noMore = false;
                if (!data.posts || !data.posts.length || data.posts.length == 0) {
                    noMore = true;
                }

                this.setState(prevState => ({
                    posts: prevState.posts.concat(data.posts),
                    loadingMore: false,
                    skip: data.skip,
                    take: data.take,
                    noMoreData: noMore
                }));


            }).catch(err => {
                console.warn("An error occurred while loading more data...", err);
                this.setState(prevState => ({
                    loadingMore: false,
                    noMoreData: true
                }));
            });

        return false;
    }
Enter fullscreen mode Exit fullscreen mode

Gatsby

With Gatsby, we were able to get all the data we needed for loading posts at BUILD time with a <StaticQuery> and then use an <InfiniteScroll> component to render that on the client-side.

The big win here? No calls back to the server!

Here's the main component that loads the list of posts: https://github.com/agility/agility-website-gatsby/blob/master/src/modules/PostListing.js

export default props => (
    <StaticQuery
        query={graphql`
        query PostListingQuery {
            allAgilityBlogPost(filter: {properties: {referenceName: {eq: "blogposts"}}}, sort: {fields: customFields___date, order: DESC}) {
              nodes {
                contentID
                customFields {
                  date(formatString: "MMMM D, YYYY")
                  excerpt
                  title
                  uRL
                  postImage {
                    url
                    label
                  }
                }

              }
            }
          }
        `}
        render={queryData => {

            let posts = queryData.allAgilityBlogPost.nodes;

            const viewModel = {
                item: props.item,
                posts: posts
            }
            return (
                <ReusablePostListing {...viewModel} />
            );
        }}
    />
)
Enter fullscreen mode Exit fullscreen mode

Here's the reusable component that actually renders out the posts with the InfiniteScroll component: https://github.com/agility/agility-website-gatsby/blob/master/src/components/reusable-post-listing.jsx

loadMorePosts(skip, take) {

        let noMore = false;

        let thesePosts = [];
        if (skip >= this.allPosts.length) {
            noMore = true;
        } else {
            thesePosts = this.allPosts.slice(skip, skip + take)
        }

        this.setState(prevState => ({
            posts: prevState.posts.concat(thesePosts),
            loadingMore: false,
            skip: skip,
            noMoreData: noMore
        }));        
    }
Enter fullscreen mode Exit fullscreen mode

NextJS

The same logic holds for NextJS websites built with Agility CMS.

Check out this Post Listing example from the starter site. https://github.com/agility/agilitycms-nextjs-starter-2020/blob/master/components/agility-modules/PostsListing.js

While Gatsby has a component that renders data from GraphQL, the Agility CMS NextJS project uses a "getCustomInitialProps" method that allows you to do any data fetches at BUILD time, and then NextJS provides that JSON data to the component at render time and on the client for use.

PostsListing.getCustomInitialProps = async function ({agility, channelName, languageCode}) {
    const api = agility;

    //get our posts
    let rawPosts = await api.getContentList({ referenceName: 'posts', languageCode });

    return {
        posts
    }
}
Enter fullscreen mode Exit fullscreen mode

Note the use of the component in both examples.

This is all made possible by 2 amazing static site generation frameworks that are making it easier to make a faster web.


Get Started Now

Get started on a free Agility CMS account today to test out Gatsby or NextJS with starter solutions pre-configured and ready to go. Sign up here.

Top comments (0)