Phil Tietjen
Posted on March 5, 2020
Welcome to part 2 of the heavily acclaimed series "Adding a blog to the devplebs site so Keith can post hot content!"
Last Time
- We Installed the gatsby-theme-blog plugin to our existing devplebs gatsby site.
- We tried to create a mock post, but, we ran into a compile error for a missing Date value.
- We went hunting through the source code and found some interesting things about how the gatsby-theme-blog is architected along with the schema for blog posts.
- We submitted a PR for both the gatsby-theme-blog and gatsby-theme-blog-core to display this schema in its readme so hopefully, no one else gets as lost as we did!
- We saw that the installation and usage of our blog theme succeeded, as a whole blog section was added to the site. However, the look and feel didn't match up with the rest of the site!
Will we use shadowing to solve our problem? will we install the gatsby-theme-blog-core plugin instead? Will we be able to finish implementing a blog onto our site? Find out Now!
What the Heck is Shadowing?
To begin, let's go over what shadowing is when it comes to Gatsby.
Since themes are usually deployed as npm packages that other people use in their sites, you need a way to modify certain files, such as React components, without making changes to the source code of the theme. This is called Shadowing
Shadowing is a filesystem-based API that allows us to replace one file with another at build time. For Example, if you had a theme with a Header component you could replace that Header with your own by creating a new file and placing it in the current location for Shadowing to find it.
Gatsby docs https://www.gatsbyjs.org/docs/theme-api/#shadowing
Thankfully Gatsby has tons of documentation. According to the rest of the Shdaowing API, we can either override components completely or extend off of them depending on how their built; which is pretty cool, so let's start.
Shadowing the Layout.
Since we're missing our Header and Footer that is contained in the Layout component wrapping the application, I'm guessing our blog theme has its own layout that we'll need to find and use ours instead.
Step 1 - Finding the theme component
We installed the theme already so I'm going to go through my node_modules
directory to find the gatsby-theme-blog
package.
inside the package, the layout component lives under /src/components/layout
.
Step 2 - Create a matching directory structure to shadow the theme
cd src
mkdir gatsby-theme-blog/components
cd gatsby-theme-blog/components
touch layout.js
Now in our devplebs site, we have src/gatsby-theme-blog/components/layout.js
.
The directory for the theme name is important so that gatsby knows at build time what file to use for that file referenced in the theme.
Understanding that this happens on build time is also important, if you are already running the local server you will need to stop it and start it back up to take effect.
Step 3 - Override the Layout
import { Layout } from "../../components/Layout"
export default Layout
We already have a Layout component so we can just import our existing component in and export default it out. Essentially, we're just swapping out the theme layout to use ours.
Progress! I might go against my spoiler warning and continue with shadowing.
Step 4 - Override the Posts
The <Posts />
theme component appears to be acting as a page template so we can shadow this and make the changes we need to make it look like our episodes page.
cd gatsby-theme-blog/components
touch posts.js
The same thing as before, we can create a posts.js
file inside the gatsby-theme-blog
directory to shadow the existing Posts component included in the theme.
import React, { Fragment } from "react"
import { Link } from "gatsby"
- import { Styled, css } from "theme-ui"
import Layout from "../components/layout"
import SEO from "../components/seo"
- import Footer from "../components/home-footer"
+ import Section from "../components/Section"
+ import { Container } from "../components/Container"
+ import { Card } from "../../components/Card"
+ import Header from "../../components/Header"
const Posts = ({ location, posts, siteTitle, socialLinks }) => (
<Layout location={location} title={siteTitle}>
- <main>
+ <Section bgColor="#419d78">
+ <Container>
+ <Header size="2xl" align="center" fontWeight="light-bold" shadow>
+ Blog Posts
+ </Header>
{posts.map(({ node }) => {
const title = node.title || node.slug
const keywords = node.keywords || []
return (
<Fragment key={node.slug}>
+ <SEO title="Blog" keywords={keywords} />
- <div>
- <Styled.h2
- css={css({
- mb: 1,
- })}
- >
- <Styled.a
- as={Link}
- css={css({
- textDecoration: `none`,
- })}
- to={node.slug}
- >
- {title}
- </Styled.a>
- </Styled.h2>
- <small>{node.date}</small>
- <Styled.p>{node.excerpt}</Styled.p>
- </div>
+ <Link to={node.slug}>
+ <Card
+ key={node.slug}
+ title={title}
+ header={node.date}
+ text={node.excerpt}
+ />
+ </Link>
</Fragment>
)
})}
+ </Container>
+ </Section>
- </main>
- <Footer socialLinks={socialLinks} />
</Layout>
)
export default Posts
There isn't a whole lot going on in the themes posts file and because I only want to mostly update the styles and use our own components I decided to use trusty ol' copy-paste. I then took things I didn't need out and some of my own stuff I wanted to use.
Step 5 - Override the Post
we'll also want to shadow the post component which will be the same process.
cd gatsby-theme-blog/components
touch post.js
import React from "react"
- import { Styled, css } from "theme-ui"
- import PostFooter from "../components/post-footer"
- import Layout from "../components/layout"
+ import Layout from "./layout"
import SEO from "../components/seo"
import { MDXRenderer } from "gatsby-plugin-mdx"
+ import { Container } from "../../components/Container"
+ import { Card } from "../../components/Card"
+ import Header from "../../components/Header"
+ import Section from "../../components/Section"
const Post = ({
data: {
post,
site: {
siteMetadata: { title },
},
},
location,
previous,
next,
}) => (
<Layout location={location} title={title}>
- <SEO title={post.title} description={post.excerpt} />
- <main>
- <Styled.h1>{post.title}</Styled.h1>
- <Styled.p
- css={css({
- fontSize: 1,
- mt: -3,
- mb: 3,
- })}
- >
- {post.date}
- </Styled.p>
+ <Section bgColor="#419d78">
+ <Container>
+ <SEO title={post.title} description={post.excerpt} />
+ <PostCard>
+ <Header
+ color="black"
+ size="2xl"
+ align="center"
+ fontWeight="light-bold"
+ >
+ {post.title}
+ </Header>
<MDXRenderer>{post.body}</MDXRenderer>
+ <PostFooter {...{ previous, next }} />
+ </PostCard>
+ </Container>
+ </Section>
- </main>
- <PostFooter {...{ previous, next }} />
</Layout>
)
export default Post
Step 6 - Investigate the placeholder content in the post footer
We're getting closer, however, the small post footer still contains placeholder content so we'll have to dig into some of the source code for the blog theme to see what we need to do. We at least know that it's something in the <PostFooter />
component since that's under the rendered post content.
// node_modules/gatsby-theme-blog/src/components/post-footer.js
import React from 'react'
import { Link } from 'gatsby'
import { css, Styled, Flex } from 'theme-ui'
import Bio from '../components/bio'
const Footer = ({ previous, next }) => (
<footer
css={css({
mt: 4,
pt: 3
})}
>
<Styled.hr />
<Bio /> {// <---------------- Dive in}
{(previous || next) && (
... // next & prev logic
)}
</footer>
)
export default Footer
// node_modules/gatsby-theme-blog/src/components/bio.js
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Image from "gatsby-image"
import { Styled, css, Flex } from "theme-ui"
import BioContent from "./bio-content"
const Bio = () => {
const data = useStaticQuery(bioQuery)
const {
site: {
siteMetadata: { author },
},
avatar,
} = data
return (
<Flex css={css({ mb: 4, alignItems: `center` })}>
{avatar ? ( // <------ Keep note of this
<Image
fixed={avatar.childImageSharp.fixed}
alt={author}
css={css({
mr: 2,
mb: 0,
width: 48,
minWidth: 48,
borderRadius: 99999,
})}
/>
) : (
<div
css={css({
mr: 2,
mb: 0,
width: 48,
minWidth: 48,
borderRadius: 99999,
})}
role="presentation"
/>
)}
<Styled.div>
<BioContent /> {// <------------ Dive in}
</Styled.div>
</Flex>
)
}
const bioQuery = graphql`
query BioQuery {
site {
siteMetadata {
author
}
}
avatar: file(absolutePath: { regex: "/avatar.(jpeg|jpg|gif|png)/" }) {
childImageSharp {
fixed(width: 48, height: 48) {
...GatsbyImageSharpFixed
}
}
}
}
`
export default Bio
// node_modules/gatsby-theme-blog/src/components/bio-content.js
import React, { Fragment } from "react"
import { Styled } from "theme-ui"
/**
* Shadow me to add your own bio content
*/
export default () => (
<Fragment>
Words by <Styled.a href="http://example.com/">Jane Doe</Styled.a>.
<br />
Change me. This is all quite default.
</Fragment>
)
Bingo! Turns out the <BioContent />
component is not only statically rendering the placeholder content but is currently an actionable example to override with shadowing for your own content.
We also found a condition in the <Bio />
component that looks like we can actually have a little image next to our <BioContent />
.
Summarizing the two things we need to do next.
- Add an image called
avatar
in our assets directory for<Bio />
. - Shadow
<BioContent />
with our own content (It's asking for it)
Step 7 - Add the avatar image to the assets directory
Now thanks to the plugins used in the gatsby-theme-blog
, Gatsby will take that image at build time and populate the GraphQL data layer with the images it's created. Then, the condition in the <Bio />
component will be able to successfully query the avatar
image and render it.
Just like in part 1 when we came across a pain point for something we didn't know, I'm going to open an issue and pull request to the gatsby repository thanks to open source magic!
Step 8 - Override the Bio-Content
cd gatsby-theme-blog/components
touch bio-content.js
import React, { Fragment } from "react"
- import { Styled } from "theme-ui"
+import Header from "../../components/Header"
-/**
- * Shadow me to add your own bio content
- */
export default () => (
<Fragment>
- Words by <Styled.a href="http://example.com/">Jane Doe</Styled.a>.
- <br />
- Change me. This is all quite default.
+ <Header color="#232129">Written by Keith Brewster.</Header>
</Fragment>
)
Wrap up
After all that shadowing we did it! It may need a little bit of extra tweaking with styling but some of that is specific to how we've built and styled out the site.
Ideally, I would have liked to just have used the gatsby-theme-blog-core
package because the gatsby-theme-blog
comes with some extra stuff we didn't need like theme-ui
. For the sake of this post, our use case, and my laziness I decided to go with shadowing because I had a feeling shadowing was actually going to be less work to do with a low impact if any. This will naturally vary depending on the complexity or specific architecture of the theme and your existing gatsby site.
I would heavily recommend using the gatsby-theme-blog-core
theme if you are creating your own blog theme!
Things I feel good about :)
- We successfully integrated a gatsby blog theme into our site.
- We only shadowed 4 components to do it.
- Components were small enough that we didn't have to recreate much in our shadowing.
Things I didn't feel good about :(
- We had no prior knowledge we needed an avatar image for the functionality in the ` component.
- I was a little bummed out the "Written by" was static in the
<BioContent />
component. It's a good actionable example of shadowing a component to have your own content there, however in my opinion, this should be something either included in the theme config or an author should be specified in each post to enable more than 1 author. That's also easier said than done. - Having to dig into the source code of a theme to hunt down components to shadow can be tedious at times. (upcoming tooling for this is hinted in the docs)
Things to say
I continue to like a lot of things with Gatsby and what they're doing. I think there are really cool things coming down the pipeline from the various teams and the whole Gatsby project is open source! They're a really cool team and community; making contributions is very smooth with their GitHub setup.
That's it for this little mini-series of installing the gatsby-theme-blog
into our existing devplebs gatsby site so Keith can post some extra quality content.
I hope you all enjoyed this, it took me longer than expected with lots of things happening between podcasting, doing talks at meetups, and looking into other forms of content!
Time For The Plug!
We Have a Podcast!
Keith Brewster and Phil Tietjen are 2 Canadian Web Developers and friends who decided to start what may be best described as a web development-focused and personality-driven podcast show called "Friday Night Deploys". It's a weekly show aimed to release every Friday where we share our experiences and stories about related topics and we typically like to go off the rails here and there.
Where To Listen
Spotify: https://open.spotify.com/show/7oXdJ5aETg5GBSNC6jZSNq
Itunes: https://podcasts.apple.com/ca/podcast/friday-night-deploys/id1485252900
Google Play Music: https://play.google.com/music/m/I54hbbplhdmovo2so6cxsctkcaq?t=Friday_Night_Deploys
Our Website: https://devplebs.tech
PodBean: https://devplebs.podbean.com/
Where To Reach Us
Twitter: https://twitter.com/DevPlebs (DM's or Mentions welcome)
Email: deadbeats@devplebs.tech
We hope you have fun listening and hope to hear from you!
Posted on March 5, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.