A JavaScript library for building user interfaces.
It’s the framework that Gatsby uses to build pages and structure content.
A query language that allows you to pull data into your website.
It’s the interface that Gatsby uses for managing site data.
Where do the files from the original refactr.tech site go?
Pages defined by react components
From HTML to JSX
module.exports = {
siteMetadata: {
title: "REFACTR.TECH"
},
plugins: [
{
resolve: `gatsby-source-airtable`,
options: {
apiKey: process.env.GATSBY_AIRTABLE_API_KEY,
tables: [
{
baseId: process.env.GATSBY_AIRTABLE_BASE_KEY,
tableName: `Speakers`,
queryName: `speakers`,
mapping: { headshot: `fileNode` }
},
{
baseId: process.env.GATSBY_AIRTABLE_BASE_KEY,
tableName: `Sessions`,
queryName: `sessions`,
tableLinks: ["Speakers"]
}
]
}
}
]
}
gatsby-config.js
With our GraphQL query we get back a node of data for each speaker.
export default ({ data }) => {
return (
<SpeakerCardList items={data.allAirtable.edges} />
);
};
export const speakerPageQuery = graphql`
{
allAirtable(filter: { table: { eq: "Speakers" } }) {
edges {
node {
fields {
slug
}
data {
speaker_name
role
company
twitter
linkedIn
company_url
}
}
}
}
}
`;
Those nodes of data are now available on this page.
speakers.js
import React from "react";
import { SpeakerCard } from "./SpeakerCard";
export const SpeakerCardList = ({ items }) => {
return items.map(item => (
<SpeakerCard {...item.node.data} slug={item.node.fields.slug} />
));
};
import React from "react";
import Img from "gatsby-image";
export const SpeakerCard = ({
twitter,
linkedIn,
headshot,
speaker_name,
role,
company,
slug
}) => (
<div className="col-xl-3 col-lg-3 col-md-4 col-sm-12">
<div className="speakers xs-mb30">
<div className="spk-img">
<img className="img-fluid" alt="trainer-img" src={headshot[0].url}/>
<ul>
<li>
<a href={twitter}>
<i className="fa fa-twitter" />
</a>
</li>
<li>
<a href={linkedIn}>
<i className="fa fa-linkedin" />
</a>
</li>
</ul>
</div>
<div className="spk-info">
<h3>
<a href={slug} rel="noreferrer noopener" target="_blank">
{speaker_name}
</a>
</h3>
<p>{role}</p>
<h6>{company}</h6>
</div>
</div>
</div>
);
Gatsby is not limited to making pages from files like many static site generators.
Gatsby lets map your GraphQL query results to create pages.
exports.onCreateNode = ({ node, actions }) => {
const { createNodeField } = actions;
if (node.internal.type === `Airtable` && node.table === `Speakers`) {
const slug = "/speakers/" + node.data.anchor
createNodeField({
node,
name: `slug`,
value: slug
});
}
};
{ id: '995475ec-7da4-538e-8232-1bf05043340c',
table: 'Speakers',
queryName: 'speakers',
internal:
{ type: 'Airtable',
contentDigest: '578c52ee6e014d486e694aa1e3f248f7',
owner: 'gatsby-source-airtable',
fieldOwners: { slug: 'default-site-plugin' } },
data:
{ speaker_name: 'Leonardo Graterol',
role: 'Web UI Engineer',
company: 'Globant',
twitter: 'https://twitter.com/pankas87',
linkedIn: 'https://www.linkedin.com/in/leonardo-graterol-24863223/',
bio: 'Leonardo is a fullstack(ish) web developer currently focused on frontend web development, working at the UI Engineering Studio of Globant.\n \n He has wide experience developing web sites and applications in several industries like e-commerce, digital marketing, GIS development companies and airlines.\n \n Leonardo is a fan of semantic HTML, good practices and web standards, and he believes in building a more accessible and inclusive online experience for everyone.',
featured: true,
session: [ 'recnq9psXs0kKF8X9' ],
anchor: 'leonardo-graterol',
order: 2,
Sessions_copy: [ 'recm05uYtbrDu7lvO' ],
session_track: [ 'Social Impact' ],
session_title:
[ 'Web Accessibility 101: Intersectional inclusion in the digital world' ],
url: 'https://refactr.tech/detail/speakers.html#leonardo-graterol',
session_url:
[ 'https://refactr.tech/detail/sessions.html#web-accessibility-101-intersectional-inclusion-in-' ],
session_anchor: [ 'web-accessibility-101-intersectional-inclusion-in-' ] },
fields: { slug: '/speakers/leonardo-graterol' }
}
We've extended a node to include a slug!
exports.createPages = ({ actions, graphql }) => {
const { createPage } = actions;
return graphql(
# GraphQL query for all nodes and new field on node goes here.
).then(result => {
# For each node of speaker data
result.data.speakers.edges.forEach(({ node }) => {
createPage({
# Build a path using our new field on the node
path: node.fields.slug,
# Use this page template
component: path.resolve(`./src/templates/the_speaker.js`),
# Data passed to context is available
# in page queries as GraphQL variables.
context: {
slug: node.fields.slug
}
});
});
});
};
creating a page
Easier to manage.
Better experience if user is offline or has spotty internet access?
Qualifies as a progressive web app
with GatsbyJS
without GatsbyJS
How do we make refactr.tech available offline and resilient on a spotty internet connection?
How do we make refactr.tech faster?
gatsyby-config.js
module.exports = {
siteMetadata: {
title: "REFACTR.TECH"
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `assets`,
path: `${__dirname}/src/styles/assets/img/`
}
},
{
resolve: `gatsby-source-airtable`,
options: {
apiKey: process.env.GATSBY_AIRTABLE_API_KEY,
tables: [
{
baseId: process.env.GATSBY_AIRTABLE_BASE_KEY,
tableName: `Speakers`,
queryName: `speakers`,
mapping: { headshot: `fileNode` }
}
]
}
},
'gatsby-plugin-sharp',
'gatsby-transformer-sharp'
]
};
How do we give refactr.tech the attributes of a progressive web app?
Text
{
"name":"REFACTR.TECH",
"short_name":"REFACTR.TECH",
"start_url":"/",
"theme_color":"#6b37bf",
"background_color":"#6b37bf",
"display":"standalone",
"icons":[
{
"src":"icons/icon-48x48.png?v=cd08a2755a01e54cfc25c889378da60f",
"sizes":"48x48",
"type":"image/png"
},
]
}
without Gatsby
with Gatsby
Easier to manage
Better experience if user is offline or has spotty internet access
Qualifies as a progressive web app
More than doubled performance