Magento 2.3 + GraphQL + Gatsby = Fast Landing Pages

Since there is already Magento 2.3-develop with GraphQL available, I’ve decided - why not give it a try and use it to generate a static landing page.. and we’ll use Gatsby.js as the “generator” :)

But let’s first think for a second..

( link to the Demo )

Why someone would do that???

That’s a good question! But I have two answers:

  1. Just for fun
  2. Make a VERY FAST landing page!

There is no need to explain the first point. But the second one deserves some explanation. You want landing pages to be very fast to increase conversion rates and there is no easy way to archive that when you are using standard tools provided by Magento. You can spend a lot of time but in the end you’ll still have quite a long way to go.

So how to make such a landing page?

Gatsby.js internally provides you with the ability to query GraphQL “resources” to generate static pages. This is quite a new concept.. and a very extensible one.

You can define your own resources which will emit whatever you want when you query them. The logic here can be very complex and implementing it without GraphQL would be a hard task.

For the sake of simplicity I’ll skip setting up Gatsby.js project. You can read about it on the official website.

So to achieve our goal we will need to define our own node which we will be able to query from our page and which will send a query to Magento GraphQL endpoint.

You can do this in the gatsby-node.js file and the implementation can look like this:

var crypto = require("crypto")
var graphqlRequest = require('graphql-request');
const Promise = require('bluebird')

const allProductsQuery = `{
  backPacks: products (
    search:"Backpack"
    filter: {
      price:{gt: "0"}
    }
    pageSize: 25
  ) {
    items {
      sku
      name
      image
      thumbnail
      small_image
      url_key
      price {
        regularPrice {
          amount {
            value
            currency
          }
        }
      }
    }
  }
  tShirts: products (
    search:"Tee"
    filter: {
      price:{gt: "0"}
    }
    pageSize: 8
  ) {
    items {
      sku
      name
      image
      thumbnail
      small_image
      url_key
      price {
        regularPrice {
          amount {
            value
            currency
          }
        }
      }
    }
  }
}`

const createMagento = ({createNode}) => {
    fieldData = {};
    return new Promise((resolve, reject) => {
        const client = new graphqlRequest.GraphQLClient('http://m23.hom/graphql', {});
        const userQueryResult = client.request(allProductsQuery);

        userQueryResult.then((res) => {
            res.id = '123';
            res.parent = null;
            res.children = [];
            res.internal = {
                type: `MagentoProducts`,
                contentDigest: crypto
                    .createHash(`md5`)
                    .update(JSON.stringify(res))
                    .digest(`hex`)
            }

            createNode(res)

            resolve();
        })

    })
}

exports.sourceNodes = ({boundActionCreators}) => {
    return Promise.join(
        createMagento(boundActionCreators)
    )
}

Let’s take a look at the important parts

The allProductsQuery contains two queries. There we search for some backpacks and some t-shirts and specify what fields and how many records to return.

Next we create a GraphQL client which points to our Magento2.3 installation:

const client = new graphqlRequest.GraphQLClient('http://m23.hom/graphql', {});

And then we create a Gatsby node which contains our query result:

gqlResult.then((res) => {
            res.id = '123';
            res.parent = null;
            res.children = [];
            res.internal = {
                type: `MagentoProducts`,
                contentDigest: crypto
                    .createHash(`md5`)
                    .update(JSON.stringify(res))
                    .digest(`hex`)
            }

            createNode(res)

            resolve();
        })

That’s it! Pretty simple, huh?

Our Page

Now we need to make some use of this data. Let’s create a page where we will display our products.

const CatalogProduct = ({product}) => {
    const imageStyle = {
        width: '7rem'
    };

    return <div className="cell medium-3">
        <a href={SITE_ROOT + product.url_key + '.html'}>
            <img style={imageStyle} src={MEDIA_PATH + product.small_image}/>
        </a>
        <div>
            <small>${product.price.regularPrice.amount.value}</small>
        </div>
        <label>
            <a href={SITE_ROOT + product.url_key + '.html'}>{product.sku}</a>
        </label>
    </div>
}

class Index extends React.Component {
    render() {
        const siteTitle = get(this, 'props.data.site.siteMetadata.title')

        return (
            <div style={{marginTop: '7rem'}}>
                <Helmet title={siteTitle}>
                    <meta name="description" content=""/>
                </Helmet>
                <Logo/>
                <Callout color="#f0f0f0">
                    <h1>Luma Backpacks</h1>
                    <div className="grid-x" style={{background:"#fff", marginBottom: "1rem"}}>
                    {
                        this.props.data.backPacks.backPacks.items.map(
                            (product, key) => <CatalogProduct key={key} product={product}/>
                        )
                    }
                    </div>
                </Callout>
                <Callout color="white">
                    <h1>Luma T-Shirts</h1>
                    <div className="grid-x" style={{background:"#fff", marginBottom: "1rem"}}>
                    {
                        this.props.data.tShirts.tShirts.items.map(
                            (product, key) => <CatalogProduct key={key} product={product}/>
                        )
                    }
                    </div>
                </Callout>
            </div>
        )
    }
}

export const pageQuery = graphql`
query getAllArtistsRecordsReviews {
    backPacks: magentoProducts {
        backPacks {
            items {
                sku
                name
                small_image
                url_key
                price {
                    regularPrice {
                        amount {
                            value
                            currency
                        }
                    }
                }

            }
        }
    }
    tShirts: magentoProducts {
        tShirts {
            items {
                sku
                name
                small_image
                url_key
                price {
                    regularPrice {
                        amount {
                            value
                            currency
                        }
                    }
                }

            }
        }
    }
}
`

In the end you will see something like this: luma gatsby

Conclusion

GraphQL will allow us to do things not possible before with Magento 2. And we as developers can use it to improve store performance and shopping experience in lots of ways.

Also it’s clear that by the end of this year a LOT of great things will happen in this space. In the meantime we already have something to experiment with.

Checkout the Demo