My new personal blog and portfolio is now online. And it's a static ReactJS progressive web application made with GatsbyJS! Let me break it down for you.
But why design a new website?
New personal brand = new website showing it off.
And I wanted to wrap my head around the GatsbyJS framework. I had minimal experience with it a few months ago when I was looking for static solutions for my Stay Regular studio and WeedPornDaily blog. I ended up using it for the Kushy documentation before switching to Slate (although I may switch back, as I prefer the JS backend over Ruby). They've come a long way since I first used it -- from much improved documentation to a trove of plugins I was dying to explore.
PWA or Bust
My goal was to create a website that was (mostly) static, classified as a progressive web app or PWA, deployed from a Git repository, and served only by CDN. All of my content is preloaded from the API during the build process, and hard-coded into the HTML. Only things like comments are loaded from remote APIs, since the system would require a server-side application to handle authenticated requests (and I'm saving my cycles on Heroku).
When compiled, this website is purely HTML, CSS, and JS.
I'm able to accomplish all of this thanks to the magic of the GatsbyJS framework. It acts as a sort of static site generator that builds static sites from ReactJS components and a GraphQL API. Rather than fuss with something like next.js to handle SSR (and still not have route splitting or Webpack setup), GatsbyJS makes it simple to package a complete server-side rendered static React application.
The GatsbyJS framework handles everything from webpack bundling, to route splitting, to server-side rendering.
The Featured
I come from the world of Wordpress, so I tried to make this blog as full featured as possible. The GatsbyJS framework provides you with a boilerplate Hello World style app with 2 pages, and that's it. Everything else requires a plugin or custom code. All these features are added on top of the base GatsbyJS features:
-
One-click deploy - I simply run
npm run deploy
and the website is built and uploaded to Github Pages from my local machine. - Markdown - All my content is written in Markdown with small bits of HTML sprinkled in when necessary.
- Syntax Highlighting - Code is colored by PrismJS, and integrated using a Gatsby Prism plugin.
- Responsive Images - All the images on the website respond the user's browser size, serving smaller files for smaller viewports, making the site super data efficient.
- Tags - I have a tag page where you can browse all the tags from every post, and clicking each tag takes you to the tag archive (more SEO points!).
- Paginated Archives - You can't have proper SEO without a way for users and robots to browse your entire content library. I was able to pull this off with a plugin and some magic.
- Comments - These are handled by Disqus and their React component.
- RSS Feed - You can't have a blog without an RSS feed for someone to feed directly into their brain as opposed to using the interface you toiled over for weeks. This was made dead simple with a plugin too.
-
SEO Optimized - From being server-side rendered, to pumping out Structured Data using
react-helmet
, to a sitemap I installed -- this website is ready for Google.
The only thing missing is a CMS, but I wouldn't be able to use Github Pages, I'd have to use a service like Netlify to handle automated builds.
The Design
I set stylistic standards for the brand by picking things like font and colors. I wanted something light, modern, and graphic -- with inspiration from Japanese design. Blue was the most dominant color, since it represented me. I then experimented with creating components to exemplify the direction of the design system. Heavy use of white space, rounded edges, and subtle gradients to create a soft space. And bold graphic images and colors would break up the monotony of a white wall.
Here's what I ended up with after a few rounds in Sketch:
The Development
The GatsbyJS docs are fantastic. Most of what I was able to do was outlined pretty well in there. Although there were a few techniques that I had to really search to find in Github issues or StackOverflow answers.
I couldn't find it anywhere in the docs how to accomplish multiple GraphQL queries on a page. GatsbyJS only allows for GraphQL queries in main layout templates, not inside individual components. Everyone kept pointing to the GraphQL docs and saying to use fragments, but the GraphQL docs only describe fragments as a way to fetch fields for queries -- not entire queries. Finally I found someone on Github having a similar issue, and someone showed how to define multiple GraphQL queries on a single page:
export const query = graphql`
query IndexQuery {
blog: allMarkdownRemark(
sort: {fields: [frontmatter___date], order: DESC},
limit: 3
filter:{frontmatter:{section:{eq: "blog"}}}
) {
totalCount
edges {
node {
id
frontmatter {
title
date(formatString: "DD MMMM, YYYY")
cover_image {
publicURL
childImageSharp {
sizes(maxWidth: 1240 ) {
srcSet
}
}
}
section
}
fields {
slug
}
excerpt
}
}
},
projects: allMarkdownRemark(
sort: {fields: [frontmatter___date], order: DESC},
limit: 3
filter:{frontmatter:{section:{eq: "project"}}}
) {
totalCount
edges {
node {
id
frontmatter {
title
date(formatString: "DD MMMM, YYYY")
cover_image {
publicURL
childImageSharp {
sizes(maxWidth: 1240 ) {
srcSet
}
}
}
section
}
fields {
slug
}
}
}
}
}
`;
I also had an issue figuring out the GatsbyJS createPage
method for generating static pages for nodes in the gatsby-node.js
file. In the docs, they describe using the function by calling a promise that queries the GraphQL for data, that then gets converted into static pages (like individual blog posts). However, I needed to run multiple queries on different endpoints, such as blogs AND projects. I figured this one out by observing someone's GatsbyJS website on Github. I ended up using callback functions inside the createPage
method and passed the callbacks the necessary variables to query GraphQL:
/**
* Pagination for /blog/ page
*/
function createBlogPagination(graphql, createPage, resolve, reject) {
graphql(`
{
allMarkdownRemark(
filter:{frontmatter:{section:{eq: "blog"}}}
) {
totalCount
edges {
node {
id
}
}
}
}
`).then(result => {
createPaginatedPages({
edges: result.data.allMarkdownRemark.edges,
createPage: createPage,
pageTemplate: "src/templates/blog-archive.js",
pageLength: 6,
pathPrefix: "blog",
buildPath: (index, pathPrefix) => index > 1 ? `${pathPrefix}/${index}` : `/${pathPrefix}` // This is optional and this is the default
});
})
}
/**
* Create slug pages for markdown files
* Create pages for each tag
*/
exports.createPages = ({ graphql, boundActionCreators }) => {
const { createPage } = boundActionCreators
return new Promise((resolve, reject) => {
graphql(`
{
allMarkdownRemark {
edges {
node {
excerpt
}
}
}
}
`).then(result => {
/**
* Create blog posts based on slugs
*/
result.data.allMarkdownRemark.edges.forEach(({ node }) => {
// Grab random tag to do related posts
var tag = node.frontmatter.tags[Math.floor(Math.random() * node.frontmatter.tags.length)];
createPage({
path: node.fields.slug,
component: path.resolve(`./src/templates/blog-post.js`),
context: {
// Data passed to context is available in page queries as GraphQL variables.
tag: tag,
slug: node.fields.slug,
},
})
});
resolve()
})
createBlogPagination(graphql, createPage, resolve, reject);
createProjectsPagination(graphql, createPage, resolve, reject);
})
};
JAMstacks are the future
As I observe trends in full-stack web development, I'm finding more companies talking about switching to a microservice based architecture where the client-side application talks to several different APIs for different functions. And depending on the application, it becomes easier to push more data into the CDN, preloaded from the APIs, allowing for a more efficient global stream of content. And it's even been proven by companies like Smashing Magazine that it's possible to create static websites with authentication, or e-commerce shopping carts..
I'm excited to explore the world of JAMstacks and push the capabilities of frameworks like GatsbyJS.
Thanks for all the fish
Thanks to GatsbyJS for creating awesome framework, and thanks for Github for hosting my repo and website for free (including a custom domain!).
Cheers,
Oscar
Keep Reading:
Top comments (5)
Wow! I stumbled upon this post while doing a Google search about Gatsby. Then I viewed your website, and . . . I love it because I have been building something similar.
I am greatly inspired by the:
I'm loving the Gatsby/Netlify combo as well. I've been using it since last fall for iamdeveloper.com. It's crazy how amazing the Netlify free tier is which includes custom domains.
That's Awesome! Love hearing other's experiences with static site generators. I tried Gatsby for my blog and while it's awesome, I wanted something simpler. I opted for GoHugo instead.
it's amazing how much you can do with just a static site nowadays. Love Netlify's new AWS lambda function integration.
"You can't have a blog without an RSS feed for someone to feed directly into their brain as opposed to using the interface you toiled over for weeks." β I love this, so true... π
You should totally check out netlify.com/ for hosting your Gatsby site, their Continuous Deployment is amazing for static site generators.