Gatsby and NextJS are popular alternatives to create static websites using React. This tutorial shows how to work with Gatsby: use CSS modules to style, add a new page, navigate between pages, create a custom layout, add a plugin, process markdown files, use GraphQL and create custom pages.
Sample App Overview
The sample app is available in Netlify. There is a Home page which has a background image and a link to Services page. Services page lists all the services that the company provides. The user can navigate to the respective service page by clicking on the link. Each service offering is available as a markdown file which gets dynamically converted to a static page.
I am using Yarn as the package manager. Please feel free to use NPM and type the equivalent commands when using NPM. And if you have not installed Gatsby, install it.
yarn global add gatsby-cli
Create a new project
Create a new project using gatsby-cli.
gatsby new gatsbydemo
Using this command creates a project using the default starter project. It is equivalent to the following command.
gatsby new gatsbydemo
https://github.com/gatsbyjs/gatsby-starter-default
There are several other starter templates. To use a different starter template, type the github repo of the starter template after the project name like so.
gatsby new blogdemo
https://github.com/gatsbyjs/gatsby-starter-blog
We will use the default starter template. So change directory to gatsbydemo.
cd gatsbydemo
To start the app, use:
gatsby develop
Open a new website localhost:8000
on the browser.
Style the page using CSS modules
Gatsby considers each component in src/pages
folder as a page. The component in index.js
represents the home page. Change the index page with the following code.
import React from 'react';
import SEO from '../components/seo';
const IndexPage = () => (
<div>
<SEO title="Vijay Consulting Services" keywords={[`gatsby`, `application`, `react`]} />
<div>
<div>
<div>
Vijay Consulting Services
</div>
<p>We offer custom application development using React framework</p>
<button>View our services</button>
</div>
</div>
</div>
);
export default IndexPage;
The new page does not have a Layout component. But it uses the SEO component. SEO component is a wrapper around React Helmet component. It outputs meta tags into the HTML page. Below the SEO component, we have the page layout. Our home page is a simple company page which offers React development services to its clients. Let’s style the home page. For styles, we use CSS modules.
In Gatsby, any file which has the module.css
extension is bundled as a CSS module. CSS module ensures that class names are distinct. Create a new file index.module.css
in the pages folder.
.home {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: url('../images/bg.jpeg') no-repeat center center fixed;
background-size: cover;
color: white;
}
.center {
text-align: center;
}
.company {
font-size: 36px;
}
.offering {
font-size: 24px;
margin-top: 48px;
}
.button {
background-color: rebeccapurple;
padding: 10px 20px;
font-size: 20px;
border: none;
outline: none;
}
.button a {
color: white;
text-decoration: none;
}
The class home
stretches the page and fills the entire browser window. It places the child with center
class in the center of the page. Within the center class, there is the company name styled using company
class, paragraph styled using offering
class and button styled using button
class. To use these classnames, import the CSS module.
import styles from './index.module.css';
Modify the page content to use these styles.
<div className={styles.home}>
<div className={styles.center}>
<div className={styles.company}>Vijay Consulting Services</div>
<p className={styles.offering}>
We offer custom application development using React framework
</p>
<button className={styles.button}>
View our services
</button>
</div>
</div>
Place a background image in the images folder for the code to work. Gatsby uses Webpack which bundles the image appropriately. This is how the home page should look.
Create a new page
Creating a new page in Gatsby is quite simple. Just add another component to the pages folder. Create the file, services.js:
import React from 'react';
import Layout from '../components/layout';
import styles from './services.module.css';
export default function Services() {
return (
<Layout>
<div>
<h1>Services</h1>
<p>View our service offerings:</p>
<ul className={styles.services}>
<li>React apps</li>
<li>React Native apps</li>
<li>Next apps</li>
<li>Gatsby apps</li>
</ul>
</div>
</Layout>
)
}
Services page uses the Layout component and uses another CSS module to style the menu. Create a new file, service.module.css
:
.services {
margin-top: 24px;
font-size: 16px;
}
.services a:link, .services a:visited {
color: rgba(0,0,0,.56);
text-decoration: none;
}
.services a:hover {
color: black;
text-decoration: underline;
}
On the browser, navigate to the new page by typing localhost:8000/services
. Next, we will link the Home page to the Services page.
Navigating between pages
The Link component in Gatsby allows navigation between pages. To allow the button on the home page to navigate to the newly created services page, add the following code in index.js.
<button className={styles.button}>
<Link to="/services">View our services</Link>
</button>
Import the Link component at the top of the file.
import { Link } from 'gatsby';
Clicking on the button should navigate back to the services page. But how do we move back to the Home page? Let’s modify the Header component which is part of the Layout component in the components folder.
Modifying the Layout
Add the following code below the h1 tag in the Header component (src/components/header.js).
<div>
<ul className={styles.menu}>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/services">Services</Link>
</li>
</ul>
</div>
Add a CSS module, header.module.css
:
.menu {
list-style: none;
margin: 24px 0 0 0;
}
.menu li {
display: inline;
margin-right: 16px;
}
.menu li a {
color: #e0e0e0;
text-decoration: none;
}
.menu li a:hover {
color: white;
text-decoration: underline;
}
The above styles make the menu within the header look better. Import the module in the header component.
import styles from './header.module.css';
With the above changes, we can navigate between the Home page and the Services page easily. This is how the Services page should look now.
Reading files from the filesystem
Create a new services folder with the markdown files from the github repo for this article.
Gatsby uses the plugin mechanism for processing data. This includes the files in the local filesystem. All the plugins are available in gatsby-config.js
. The starter template has few plugins included. One of them is gatsby-plugin-react-helmet
for inserting meta tags. There is another plugin for processing image files in the images folder.
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`
}
}
Use the same plugin for reading markdown files from the services folder.
{
resolve: `gatsby-source-filesystem`,
options: {
name: `services`,
path: `${__dirname}/src/services`
}
},
Add a new plugin
There are several plugins available. Install the remark plugin for processing markdown files.
yarn add gatsby-transformer-remark
Add the plugin to the config file, gatsby-config.js
'gatsby-transformer-remark'
This plugin adds a few nodes to the GraphQL schema.
GraphQL with Gatsby
GraphQL is an alternative to REST for querying and updating data. Gatsby allows components to query for data using GraphQL. To explore GraphQL data, open localhost:8000/___graphql.
The above image shows GraphiQL in action. The remark plugin makes allMarkdownRemark
available in the GraphQL schema. With data available from markdown files, we can create new pages dynamically from the markdown files.
Creating page dynamically
There is a gatsby-node.js
file which customises the creation of GraphQL nodes, pages, etc. When a new remark node is created, we will add a slug as an additional field to the node.
Open gatsby-node.js and export a new function.
exports.onCreateNode = ({ node, getNode, actions }) => {
if (node.internal.type === 'MarkdownRemark') {
const fileNode = getNode(node.parent);
actions.createNodeField({
node,
name: 'slug',
value: fileNode.name.toLowerCase()
});
}
}
Open GraphiQL and query for the slug and you should see the markdown filename as the slug.
{
allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
Add another function to the same file to create pages dynamically.
exports.createPages = ({ graphql, actions }) => {
graphql(`
query {
allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
`).then(result => {
result.data.allMarkdownRemark.edges.forEach(edge => {
actions.createPage({
path: '/services/' + edge.node.fields.slug,
component: path.resolve('./src/services/service.js'),
context: {
slug: edge.node.fields.slug
}
});
});
});
}
This function makes a GraphQL query and for each markdown file, it adds a new page dynamically. The absolute path is /services/<slug>
. And a new component in services folder renders that page. We pass the slug as a context to the service component.
Page to render markdown content
In the services folder, create a new file, service.js. This will be a page component. Page components can export a query variable which has a GraphQL query which will retrieve data for the component. For our service component, we need HTML from the markdown file.
export const query = graphql`
query($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
html
frontmatter {
title
}
}
}
`;
Import graphql from gatsby package.
import { graphql } from 'gatsby';
The data from GraphQL query is available in props.data object. To display the HTML, we destructure the props object and set the HTML within a div container.
export default function Service(props) {
const {
html,
frontmatter: { title }
} = props.data.markdownRemark;
return (
<Layout>
<div>
<h1>{title}</h1>
<div dangerouslySetInnerHTML={{ __html: html }} />
</div>
</Layout>
);
}
With these changes in place, we have the Service pages available. To navigate to the pages, open services.js and add links like so.
<ul className={styles.services}>
<li>
<Link to="/services/react-app">React apps</Link>
</li>
<li>
<Link to="/services/react-native-app">React Native apps</Link>
</li>
<li>
<Link to="/services/nextjs-app">Next apps</Link>
</li>
<li>
<Link to="/services/gatsby-app">Gatsby apps</Link>
</li>
</ul>
The Service page is shown below.
Build the app
Finally, it is time to build the app.
gatsby build
The build output is available in the /public folder. Run the built app using
gatsby serve
Open localhost:9000 to view the app.
The build folder can be deployed to any hosting service like Netlify, Github pages, Now, etc. When the page downloads, JavaScript also downloads. Subsequent navigation is all client-side on the browser.
Summary
We covered lot of ground in this tutorial. We learnt how to:
- Style a page using CSS module
- Add a new page
- Navigate between pages
- Customise Layout / Header
- Read files from filesystem
- Add a plugin
- Query data using GraphQL
- Add pages dynamically
- Component to render dynamic pages
- Build the app
The code for the tutorial is available in a Github repo. Please ask me any questions in the comments below.
Hello is there any way to render the swagger document using getsby
sorry, but when I follow your steps, there are many errors in bulding site.
you should update your article correctly