How to create a resume with Gatsbyjs
Online resume
There are a lot of reasons to use a static site generator to generate your resume online:
- it is always nice to have a fast loading time
- you don’t want to take any chance with the site being down when a prospective employer accesses your resume
- it is cheap to deploy: the load on the page should be low, so a free hosting solution like Netlify makes sense
For all those reasons, Gatsby makes a good choice as a platform to publish your resume online.
This article will do exactly that:
- the resume we will build is deployed with Netlify at https://resume-with-gatsby.netlify.com/
- you can find the source code on GitHub at https://github.com/pcarion/resume-with-gatsby
Resume definition format
You will update the content of your resume regularly, so you really don’t want to sprinkle this content inside a static HTML template.
The JSON Resume is an open-source project to create a JSON-based standard for resumes.
Personally, I find that a JSON file is more difficult to update than a yaml file, so we’ll use the format defined by the JSON resume project, but in a YAML format.
The project comes with a sample resume, from the fictional character Richard Hendriks from the excellent series “Silicon Valley” on HBO:
https://github.com/jsonresume/resume-schema/blob/v1.0.0/examples/valid/complete.json
Using a YAML format, the resume looks like this:
---basics: name: Richard Hendriks label: Programmer image: '' email: richard.hendriks@mail.com phone: "(912) 555-4321" url: http://richardhendricks.example.com summary: Richard hails from Tulsa. He has earned degrees from the University of Oklahoma and Stanford. (Go Sooners and Cardinal!) Before starting Pied Piper, he worked for Hooli as a part time software developer. While his work focuses on applied information theory, mostly optimizing lossless compression schema of both the length-limited and adaptive variants, his non-work interests range widely, everything from quantum computing to chaos theory. He could tell you about it, but THAT would NOT be a “length-limited” conversation! location: address: 2712 Broadway St postalCode: CA 94115 city: San Francisco countryCode: US region: California
Gatsby setup
To install Gatsby, you start with installing the 3 required packages
yarn init -yyarn add gatsby react react-dom
You can then add the usual scripts in your package.json
file to start the Gatsby server:
"scripts": { "build": "gatsby build", "clean": "gatsby clean", "develop": "gatsby develop"},
At this stage, you can already start Gatsby with yarn develop
, but there is nothing available for rendering.
Loading the resume in Gatsby
The gatsby-source-filesystem
plugin allows you to load any file in Gatsby.
yarn add gatsby-source-filesystem
To configure this plugin, you create a gatsby-config.js
file where you tell the plugin which directory to parse to read files.
module.exports = { plugins: [ { resolve: `gatsby-source-filesystem`, options: { path: `./resume`, }, }, ],}
You can then start Gatsby (yarn run develop
) and load the Graphiql server, usually at that URL: http://localhost:8000/___graphql
The gatsby-source-filesystem
will populate the allFile
root with the files it found, as shown by this query:
query MyQuery { allFile { edges { node { absolutePath } } }}
the results will show your resume file:
{ "data": { "allFile": { "edges": [ { "node": { "absolutePath": "<path to>/resume/resume.yaml" } } ] } }}
Exploration
The step here is not required, but it shows how you could write your own plugin to parse the resume.
In the gatsby-node.js
file, you could write a very basic plugin to read the content of the resume, using the onCreateNode
method to later create new nodes to expose your resume in the GraphQL API:
async function onCreateNode({ node, loadNodeContent }) { if (node.internal.mediaType !== `text/yaml`) { return; }
const content = await loadNodeContent(node); console.log(`File: ${node.absolutePath}:`); console.log(content);}
exports.onCreateNode = onCreateNode;
When you restart the server, you can see the content of the resume file on screen:
success onPreBootstrap - 0.009ssuccess createSchemaCustomization - 0.002sFile: <path to>/resume/resume.yaml:---basics: name: Richard Hendriks label: Programmer
Interesting but there are existing plugins who already do that … and much more.
Transformer plugin: gatsby-transformer-yaml
This plugin is a good candidate for us:
- it reads the yaml file
- parses it
- makes it available if the GraphQL API
You install that plugin with:
yarn add gatsby-transformer-yaml
and the magic happens when you restart the server: 2 new root types appear in the Graphiql interface, allResumeYaml
and resumeYaml
.
If we suppose that the site will contain only one resume, we can get the content of the resume using that query:
query MyQuery { resumeYaml { basics { email name phone } }}
and, we get back:
{ "data": { "resumeYaml": { "basics": { "email": "richard.hendriks@mail.com", "name": "Richard Hendriks", "phone": "(912) 555-4321" } } }}
Time to render some data
Let’s create our first page:
- you can delete the
gatsby-node.js
file containing our exploration plugin. - create a
src/pages/index.js
We’ll start with the most basic data extraction (name and email) to make sure that all is in order.
In src/pages/index.js
:
import React from 'react';
const Resume = ({ data }) => { const resume = data.resumeYaml; const { basics } = resume; return ( <React.Fragment> <h1>{basics.name}</h1> <h2>{basics.email}</h2> </React.Fragment> );};
export default Resume;
export const query = graphql` query MyQuery { resumeYaml { basics { email name } } }`;
This will give us our first page:
Not quite enough yet to get you a job at Hooli, but it’s a promising start.
Resume rendering
The JSON resume project contains also a library of themes to render resume following the specification.
For the purpose of this presentation, I have chosen the flat theme by Mattias Erming, because
- it is pretty well designed
- it is open source (MIT) - https://github.com/erming/jsonresume-theme-flat
- the styling is easy to extract: one
style.css
file and one template file
Process to build the resume
I won’t describe all the steps to port that template to Gatsby, just the major steps
extra package: gatsby-react-helmet
Helmet is nice addition because it makes it very easy to:
- to set page title
- add external css dependencies
You install that package with:
yarn add gatsby-plugin-react-helmet react-helmet
and add it to your gatsby-config.js
file.
issue with CSS ordering
The way you add a specif css document (the one coming with the flat theme example), is by importing if in the gatsby-browser.js
document:
import "./src/styles/style.css"
The style requires 2 other CSS loaded from a CDN, and you can use Helmet to do that:
<Helmet> <title>{basics.name}</title> <meta name="description" content={`resume for ${basics.name}`} /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.2.0/css/bootstrap.min.css" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/2.0.2/octicons.min.css" /></Helmet>
The problem is that the local style loaded by gatsby-browser.js
is loaded before the styles loaded by Helmet and that broke the rendering: for example the H1..4 styles were the ones defined by bootstrap, and not the local styles file.
The only solution I found, was to load bootstrap as a dependency and load it from gatsby-browser.js
, before the local style:
import 'bootstrap/dist/css/bootstrap.css'import "./src/styles/style.css"
porting process
The process involved updating the GraphQL query to import more and more data (the minimal theme only omits the projects
section of the resume).
The final query asks for all the data:
query MyQuery { resumeYaml { basics { email name label phone url summary profiles { network url username } } work { description endDate(formatString: "MMM, YYYY") highlights location name startDate(formatString: "MMM, YYYY") position summary url } volunteer { endDate(formatString: "MMM, YYYY") highlights organization position startDate(formatString: "MMM, YYYY") summary url } education { area courses endDate(formatString: "MMM, YYYY") gpa institution startDate(formatString: "MMM, YYYY") studyType } awards { awarder date(formatString: "MMM, YYYY") summary title } publications { name publisher releaseDate(formatString: "MMM, YYYY") summary url } skills { keywords level name } languages { fluency language } interests { keywords name } references { name reference } } }
and each section of the resume has its own component:
const Resume = ({ resume }) => { const { basics, work, volunteer, education, awards, publications, skills, languages, interests, references } = resume; return (<React.Fragment> <Helmet> <title>{basics.name}</title> <meta name="description" content={`resume for ${basics.name}`} /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/2.0.2/octicons.min.css" /> </Helmet> <Header basics={basics} /> <div id="content" className="container"> <Contact basics={basics} /> <About basics={basics} /> <Profiles profiles={basics.profiles||[]} /> <Work works={work} /> <Volunteer volunteers={volunteer} /> <Education educations={education} /> <Awards awards={awards} /> <Publications publications={publications} /> <Skills skills={skills} /> <Languages languages={languages} /> <Interests interests={interests} /> <References references={references} /> </div></React.Fragment>);
Pretty easy to read and update.
Deployment
We won’t describe here the actual deployment as there are a lot of articles out there describing how to deploy a Gatsby site.
For instance, the site https://resume-with-gatsby.netlify.com/ was deployed on Netlify with a couple of clicks.