15 August, 2020
Guide Fari
My social card struggle with React Helmet
status: fixed
I've been fighting against react-helmet for a while now, and debugging the issue has left me with conflicted views. My SEO knowledge is a bit basic, that might explain why I'm struggling to catch the issue.
I'll break down the article into 2 parts:
- The set up of the site
- The problem & debugging attempts
1. Site setup
The site is build using GatsbyJS, and has an SEO component that makes use of react-helmet, which is available as a GatsbyJS plugin. There are 5 'hard-coded' pages (404, index, blog, about, contact), and the blog posts are programmatically generated (explained in the Gatsby docs here). The tutorial I followed to implement the SEO component is taken from Gatsby docs.
Relevant file links
Code snippets
The seo component can take the following props:
const SEO = ({ title, description, image, article }) => { ... }
And it also has fallback values, incase I don't pass down all props:
const {
defaultTitle,
titleTemplate,
defaultDescription,
siteUrl,
defaultImage,
twitterUsername,
} = site.siteMetadata
siteMetadata (containing default/fallback values) in the SEO component comes from the static graphql query:
const query = graphql`
query SEO {
site {
siteMetadata {
defaultTitle: title
titleTemplate
defaultDescription: description
siteUrl: url
defaultImage: image
twitterUsername : author
}
}
}
`
the query gets the data from gatsby-config.js:
module.exports = {
siteMetadata: {
title: `Goosebumps Collective`,
titleTemplate: "%s · Goosebumps Collective",
description: `Freelance Web Development & Curated Music`,
url: "https://goosebumps.co.zw",
image: `/goose.png`,
author: `@txndai`,
}
}
Default values & react-helmet structure:
const seo = {
title: title || defaultTitle,
description: description || defaultDescription,
image: `${siteUrl}${image || defaultImage}`,
url: `${siteUrl}${pathname}`,
}
return (
<Helmet title={seo.title} titleTemplate={titleTemplate}>
<meta name="description" content={seo.description} />
<meta name="image" content={seo.image} />
{seo.url && <meta property="og:url" content={seo.url} />}
{(article ? true : null) && <meta property="og:type" content="article" />}
{seo.title && <meta property="og:title" content={seo.title} />}
{seo.description && (
<meta property="og:description" content={seo.description} />
)}
{seo.image && <meta property="og:image" content={seo.image} />}
<meta name="twitter:card" content="summary_large_image" />
{twitterUsername && (
<meta name="twitter:creator" content={twitterUsername} />
)}
{seo.title && <meta name="twitter:title" content={seo.title} />}
{seo.description && (
<meta name="twitter:description" content={seo.description} />
)}
{seo.image && <meta name="twitter:image" content={seo.image} />}
</Helmet>
)
}
export default SEO
2. Problem + Debugging attemps
You'd think I have all my bases covered. When I share links to any page on the website, it remains as just a text link, and no card appears. I've tried Twitter, WhatsApp, & Facebook.
When I submit a url on Twitter Card Validator, the log I receive is:
INFO: Page fetched successfully
INFO: 3 metatags were found
ERROR: No card found (Card error)
I've been receiving that error from the get go (a good couple of weeks at the time of writing), and the case remains the same, as I have just tried this url.
Other social card validators
I've also tried iframely, socialsharepreview, metatags.io - all with fairly positive results, indicating that there's a title, description, & image (all open graph).
The <head>
element of all pages seem to have all the meta required, so I can't quite tell where my main issue lies.
Fix
Turns out the fix was as simple as opening tailwind.config.js
, and adding purge: ["./src/**/*.js"]
in the module.exports
object.
At some point, after iterating the SEO component further, the error being returned by the Twitter card validator was error "response is too large"
. This is why you should purge unused classes generated by tailwind.
links
- npm: react-seo-component - this may be a more consistent approach to SEO across projects, especially since I've been switching between NextJS & GatsbyJS sites 🤔