Gatsby Update!
After all these years, Finally a meaningful post. Not a markdown cheat-sheet, not a teaser/update about forgotten half completed project (although "teaser" project had three upgrades after that post, I never find time to write about.) With this post again I'm plaining to motivate myself to write regularly, hopefully this time I will be successful. So let's start.
Why Change? Why Gatsby?
Old blog was based off Pelican Static Site Generator (Old Blog source can be found in the source branch). I don't used much but it was rock solid, after 3 years still working and in usable form. Although I'm not sure what can go wrong in a static site but, you'll never know.
So why the change? Mainly to write this post. Also old style was getting really old, I didn't change much but new style look minimal and modern I think? (I'm not good at designing). Another problem was that I haven't dealt with python in a long time, and I'm not motivated to edit 4-5 year old python project. So as a solution decided to move blog something new. For a small project (of course half completed project) I played with Hugo, It was really fast as claimed but Go was not for me. Then I saw Gatsby a new Hype in the static site scene (like 2 years ago), It had every popular buzz word at the time React, performance, scalability. I was ready to join Hype-Train and play with Gatsby but there was no opportunity (AKA to lazy to do hobby projects). But now I'm ready to join. Also at work I'm using Typescript and React so it was easy to join on train (probably the main reason)
How?
I'm not going to write as detailed a tutorial, cause Gatsby has enough documents and tutorials. Only going to explain some tips and tricks I used.
Theme/Starter
I used Gatsby Starter Chronoblog template with minimal edits. With shadowing and override features, It was fairly easy.
Multiple Authors (sort of)
Old blog was combined effort with my friend, I think there is only 1 post from him but I wanted to preserve it.
first we need to add author
field to post frontmatter. So override postQuery
in post template with creating src\gatsby-theme-chronoblog\templates\post.js
file
import { graphql } from 'gatsby';import Post from 'gatsby-theme-chronoblog/src/components/post';export default Post;export const postQuery = graphql`query($id: String!) {mdx(id: { eq: $id }) {idexcerptfrontmatter {categoryauthortitledatedescriptiontagscover {childImageSharp {fluid(maxWidth: 768, quality: 90) {...GatsbyImageSharpFluid_withWebppresentationWidthpresentationHeightsrc}resize(width: 768) {src}}}}fields {slug}body}}`;
Now we have author metadata but we need to display it in website, For this Chronoblog has a post-footer.mdx
.
create post-footer component in src\gatsby-theme-chronoblog\post-footer.mdx
. Then we can easily access global site configuration and post data from component props. So I added a hack with default Chronoblog components, if post has different author than site author it displays author name from post frontmatter, else it's uses beautiful default AuthorBanner
component from Chronoblog. Of course with this approach guest authors banner pretty dull looking but for now its good enough.
<div>{props.postData.frontmatter.author &&props.postData.frontmatter.author !== props.siteMetadata.author ?<AuthorBanner><div><AuthorBannerHeading>{props.postData.frontmatter.author}</AuthorBannerHeading></div></AuthorBanner>:<AuthorBanner></AuthorBanner>}</div>
Disqus comments
I think there better solutions but old blog was using and I'm to lazy to migrate 4 old comments to a new system.
There a plugin gatsby-plugin-disqus
add disqus to plugins configuration in gatsby-config.js
plugins: [...,{resolve: `gatsby-plugin-disqus`,options: {shortname: `yourshortname`}}]
then add Disqus
component to post-footer component in src\gatsby-theme-chronoblog\post-footer.mdx
to show comments
import { Disqus } from 'gatsby-plugin-disqus';<Disqusconfig={{url: props.siteMetadata.siteUrl + props.postData.fields.slug,title: props.postData.frontmatter.title,id: props.postData.id}}/>
Travis auto build and deploy to github pages
Automation is god send!
First we need ghpages tool, run npm install gh-pages --save-dev
in project dir to add it. Then a deploy script for Travis, we can use npm scripts
add this to scripts
in package.json
(of course update repo url to your repo)
"travis-deploy": "gatsby build --prefix-paths && gh-pages -d public -r https://$GH_TOKEN@{yourgitrepo}",
then create a travis.yml
language: node_jsbefore_script:- npm install -g gatsby-clinode_js:- "10"deploy:provider: scriptscript: npm i --quiet && npm run travis-deployskip_cleanup: trueon:branch: v2
We are ready to connect our repo to travis. After connecting repo don't forget to add your github auth token GH_TOKEN
in Travis Environment Variables settings. Then we are done, now every time you push a change to repo travis will build and push to gh-pages branch.
Dev.to cross posting dream
Yeah I don't post much, but I want those sweet views.
So Dev.to supports RSS import, It should be easy right? No It won't easy. Because of code highlighting or Chronoblog theme; RSS html output is full off inline styles, so Dev.to's html to markdown converter freaks out and displays bunch of empty html tags in markdown. To fix it first I tried to give raw markdown output in RSS but rendering mdx
pain in the butt and also looks like Dev.to only supports html in RSS. So for now I removed style
tags and css classes from html output, yeah probably it will break RSS readers but who is using them? (a controversial topic maybe?)
of course gatsby has RSS feed plugin
add RSS feed plugin plugins configuration in gatsby-config.js
{resolve: `gatsby-plugin-feed`,options: {query: `{site {siteMetadata {siteTitlesiteDescriptionsiteUrlsite_url: siteUrldescription siteDescriptiontitle: siteTitle}}}`,feeds: [{serialize: ({ query: { site, allMdx } }) => {return allMdx.edges.map((edge) => {return Object.assign({}, edge.node.frontmatter, {description: edge.node.excerpt,date: edge.node.frontmatter.date,author: edge.node.frontmatter.author,title: edge.node.frontmatter.title,url: site.siteMetadata.siteUrl + edge.node.fields.slug,guid: site.siteMetadata.siteUrl + edge.node.fields.slug,custom_elements: [{'content:encoded': edge.node.html.replace(/<style((.|\n|\r)*?)<\/style>/gi, '').replace(/class="(.*?)"/gi, '')},{tags:edge.node.frontmatter.tags &&edge.node.frontmatter.tags.join(',')},{category:edge.node.frontmatter.tags &&edge.node.frontmatter.tags.join(',')}]});});},query: `{allMdx(limit: 1000,sort: { order: DESC, fields: [frontmatter___date] },filter: { fields: { type: { eq: "posts" } } }) {edges {node {excerpthtmlidfields {slugtype}frontmatter {authortitledatelinkdrafttags}body}}}}`,output: '/rss.xml',title: `Fregram Blog`}]}}
Probably half of tags in the RSS is useless but I did not found a good document about it, so left all of them. Main magic happens in serialize
function using regex replace removes style tags and css classes from html, If you have a working configuration you only need to add this change.
edge.node.html.replace(/<style((.|\n|\r)*?)<\/style>/gi, '').replace(/class="(.*?)"/gi, '')
also for tags support you need to comma separated list so add these too
{tags:edge.node.frontmatter.tags &&edge.node.frontmatter.tags.join(',')},{category:edge.node.frontmatter.tags &&edge.node.frontmatter.tags.join(',')}
In Conclusion
Everything is better and I'm happy
To tell the truth it's not much different from old Pelican setup, maybe more modern. Like with mdx
and shadowing gatsby look more easy to customize, but as a Static Website Generator
I think they are same. Of course if you are using or interested in React and graphql (although you don't see react much, it's mostly hidden especially using themes) it's good weekend project.