TLDR; You want to build an awesome modern web application? I show you how!
Check that you have an updated version of the below requirements by entering the following into the command-line interface (eg. iTerm2):
gcc --versionnode -vgatsby -vInstall any of the missing preequisites before continuing.
gatsby new repo_name https://github.com/gatsbyjs/gatsby-starter-hello-worldnpm installnpm install --save gatsby-plugin-styled-components styled-components babel-plugin-styled-components gatsby-plugin-prefetch-google-fonts gatsby-plugin-react-helmet react-helmetReplace TITLE, DESCRIPTION and AUTHOR with your values and then add the following code in ./gatsby-config.js located in the root (next to package.json).
module.exports = {
siteMetadata: {
title: `TITLE`,
description: `DESCRIPTION`,
author: `@AUTHOR`,
},
plugins: [
`gatsby-plugin-styled-components`,
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-plugin-prefetch-google-fonts`,
options: {
fonts: [
{
family: `Roboto Mono`,
variants: [`400`, `700`]
},
{
family: `Roboto`,
subsets: [`latin`]
}
]
}
}
]
};Test that the project works correctly by running.
gatsby developA blank page should appear at localhost:8000 with the words Hello World!
Add the following css to a new CSS-file at ./src/styles/global.css
html,
body {
height: 100%;
margin: 0;
padding: 0;
font-family: "Roboto", "sans-serif";
}Create a file called ./gatsby-browser.js with the following code in the root (next to package.json)
import "./src/styles/global.css";Add code for a layout component in a new JS-file at ./src/components/Layout.js.
import React from "react"
import styled from "styled-components"
import Header from "./Header"
import Footer from "./Footer"
const Wrapper = styled.div`
min-height: 100vh;
display: flex;
flex-direction: column;
`
const Body = styled.div`
flex: 1 0 auto;
padding: 0 1rem;
`
export default ({ meta, categories, children }) => {
return (
<Wrapper>
<Header meta={meta} categories={categories} />
<Body>{children}</Body>
<Footer />
</Wrapper>
)
}Add code for a dynamic fixed header component that appears when scrolling up and dissapears when scrolling down in a new JS-file at ./src/components/Header.js
import React, { useEffect, useState } from "react"
import styled from "styled-components"
import SEO from "./seo"
import Link from "./Link"
const Wrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1rem;
background-color: #ccc;
top: 0;
position: sticky;
transform: ${p => (p.show ? "translateY(0%)" : "translateY(-100%)")};
transition: transform 0.4s;
`
const List = styled.ul``
const ListItem = styled(Link)`
margin-left: 1rem;
`
const HomeLink = styled(Link)`
font-size: 24px;
`
const ListLink = ({ to, children }) => <ListItem to={to}>{children}</ListItem>
export default ({ meta, categories = [] }) => {
let [position, setPosition] = useState(0)
let [visible, setVisible] = useState(true)
useEffect(() => {
const handleScroll = () => {
let tempPosition = window.pageYOffset
if (position > 100) {
setVisible(position > tempPosition)
} else {
setVisible(true)
}
setPosition(tempPosition)
}
window.addEventListener("scroll", handleScroll)
return () => {
window.removeEventListener("scroll", handleScroll)
}
})
return (
<Wrapper show={visible}>
<SEO {...meta} />
<HomeLink to="/">Home</HomeLink>
<List>
{categories.map(category => (
<ListLink to={category.slug}>{category.title}</ListLink>
))}
</List>
</Wrapper>
)
}Add code for a fixed bottom footer component with basic styling in a new JS-file at ./src/components/Footer.js.
import React from "react";
import styled from "styled-components";
const Wrapper = styled.div`
flex-shrink: 0;
background-color: #ccc;
padding: 1rem;
`;
export default () => <Wrapper>Footer</Wrapper>;Add code for a link component with basic styling in a new JS-file at ./src/components/Link.js.
import { Link as LinkUI } from "gatsby";
import styled from "styled-components";
const Link = styled(LinkUI)`
text-decoration: none;
color: black;
cursor: pointer;
`;
export default Link;Add code for an Seo component in a new JS-file at ./src/components/Seo.js
/**
* SEO component that queries for data with
* Gatsby's useStaticQuery React hook
*
* See: https://www.gatsbyjs.org/docs/use-static-query/
*/
import React from "react"
import Helmet from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"
const SEO = ({ description, lang = "", meta = [], title, url }) => {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
}
}
}
`
)
const metaTitle = title || site.siteMetadata.title
const metaDescription = description || site.siteMetadata.description
return (
<Helmet
htmlAttributes={{
lang,
}}
title={metaTitle}
titleTemplate={`%s | ${site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: metaTitle,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: site.siteMetadata.author,
},
{
name: `twitter:title`,
content: metaTitle,
},
{
name: `twitter:description`,
content: metaDescription,
},
].concat(meta)}
>
<link rel="canonical" href={url} />
</Helmet>
)
}
export default SEOAdd the following data into a new JSON-file at ./src/data/categories.json
[
{
"slug": "/him/",
"title": "Him"
},
{
"slug": "/her/",
"title": "Her"
}
]Add template code for a home page in a new JS-file at ./src/templates/homePage.js.
import React from "react"
import Layout from "../components/Layout"
export default ({ pageContext: { categories } }) => {
return (
<Layout meta={{ title: "Home" }} categories={categories}>
<h1>Home</h1>
</Layout>
)
}Add template code for category page in a new JS-file at ./src/templates/categoryPage.js.
import React from "react"
import Layout from "../components/Layout"
export default ({
pageContext: {
categories,
page: { title },
},
}) => {
return (
<Layout meta={{ title }} categories={categories}>
<h1>{title}</h1>
</Layout>
)
}Add a new file called gatsby-node.js with the following code in the root (next to package.json)
const categoriesRaw = require("./src/data/categories.json");
exports.createPages = async ({ actions: { createPage } }) => {
const categories = Object.values(categoriesRaw);
createPage({
path: `/`,
component: require.resolve("./src/templates/homePage.js"),
context: { categories }
});
categories.forEach(page => {
createPage({
path: page.slug,
component: require.resolve("./src/templates/categoryPage.js"),
context: { categories, page }
});
});
};Remove the old pages folder at ./src/pages
npm install --save gatsby-plugin-manifest gatsby-plugin-offlineYou can use a custom logo or the default Gatsby logo by downloading it from https://www.gatsbyjs.org/Gatsby-Monogram.svg. Then save it to ./src/images/icon.svg
Replace REPOSITORY_NAME and REPO_NAME with names of your choice then add the following.
// in gatsby-config.js
module.exports = {
plugins: [
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `REPOSITORY_NAME`,
short_name: `REPO_NAME`,
start_url: `/`,
background_color: `#f7f0eb`,
theme_color: `#222222`,
display: `standalone`,
icon: `src/images/icon.svg`,
},
},
`gatsby-plugin-offline`,
],
}// in gatsby-browser.js
export const onServiceWorkerUpdateReady = () => {
const answer = window.confirm(
`This application has been updated. ` +
`Reload to display the latest version?`
)
if (answer === true) {
window.location.reload()
}
}Build and serve the project to see all the parts in action:
- A progressive web app
- Dynamically created pages
- A layout structure with header, body and footer.
gatsby build && gatsby serve- Open the chrome browser
- Access dev-tools with cmd+shift+i
- Go to the audits tab and click generate report
- Performance 92
- Accessibility 94
- Best practices 93
- SEO 100
- PWA