How To Start With GatsbyJS – part 1: First Steps

Share

This article is part 1 of “How to start with Gatsby JS” series.

Introduction

Let me show you how to use GatsbyJS with Styled Components and Storybook.

Gatsby is a framework generator built with React and GraphQL. This is a static-site generator that helps you build blazingly fast websites and apps.

To front-end side, I will use Styled Components – the library which allows writing CSS styled in JS. You will also learn about Storybook for React – UI development environment that you can use to visualize different states of your UI components.

What Tools You’ll Be Using

Why you should get to know Gatsby?

  • Performance – Gatsby sites are so far the fastest sites on earth.
  • Popularity – it’s built on React so you got the whole bunch of things that you love about React
  • Easy to learn – You can find a lot of well-written tutorials
  • And many more here

Prerequisites

  • Yarn and Node 10+ installed
  • Basic understanding of React

Let’s do this!

Step 1: Installation

I will use the simple Gatsby Starter Storybook created by markoradak. To create a new project you just clone the starter GitHub repository:

$ git clone https://github.com/markoradak/gatsby-starter-storybook.git

Next, go to the project directory and install packages:

$ cd gatsby-starter-storybook
$ yarn

When the installation is over and the terminal doesn’t show any errors, start your app:

$ yarn start

Gatsby will start a development environment and a Storybook. The server is showing you the starter template by default at localhost:8000:

Image Component in Storybook

And the Storybook at http://localhost:9000:

The image you can see is a React component (src/components/Image/index.js) loaded to stories (src/components/Image/index.stories.js).

How to tell Storybook where to find stories? In .storybook/config.js – this basic configuration automatically imports all files ending in *.stories.js.

Step 2. Create a new component and stories

Let’s start with create Header directory with index.js component and index.stories.js.
I recommend separating a logic of the component and styles into two files (index.js and styles.js) and putting both of them to directories of the component name.

Application structure

Use Styled Components to render components with tags and some styles. Assume that the Header will have two variants: default and light.

Header/index.js

import React from 'react';
import PropTypes from 'prop-types';
 
import { HeaderStyled, HeaderTitleStyled } from './styles';
 
const Header = props => {
  return (
    <HeaderStyled light = {props.light}>
      <HeaderTitleStyled>
        Gatsby Project + Storybook
      </HeaderTitleStyled>
    </HeaderStyled>
  )
};
 
Header.propTypes = {
  light: PropTypes.bool,
};
 
export default Header;

Header/styles.js

import styled, { css } from 'styled-components';

const HeaderTitleStyled = styled.h1`
  font-size: 36px;
  font-weight: 600;
  color: #fff;
`;
 
const HeaderStyled = styled.header`
  display: flex;
  align-items: center;
  width: 100%;
  background: #744c9d;
  padding: 20px 30px;
  height: 120px;
 
  ${props => props.light && css`
    background: #ccc;
 
    ${HeaderTitleStyled} {
      color: #000;
    }
  `}
`;

export {
    HeaderTitleStyled,
    HeaderStyled,
};

Add Header component to pages/index.js, and remove unnecessary code from Index page.

import React from 'react';

import Layout from '../global/Layout';
import Header from '../components/Header';

const IndexPage = () => (
  <Layout>
    <Header/>
  </Layout>
);
 
export default IndexPage;

Go to your browser. The default Header should be looking like:

Header

Open Header/index.stories.js and write your first story with two variants like this:

import React from 'react';
import { storiesOf } from '@storybook/react';

import Header from '.';
 
storiesOf('Header', module)
  .add('default', () => (
    <Header />
  ))
  .add('light', () => (
    <Header light />
  ));

Next, go to .storybook/config.js and remove unnecessary styles from Wrapper Styled Component.
You can also remove whole Wrapper component and use Fragment or shorter syntax <></> which won’t add any extra nodes to the DOM.

import React, { Fragment } from 'react';

const Decorator = storyFn => (
  <Fragment>
    <GlobalStyle />
    {storyFn()}
  </Fragment>
);

Now everything is ready. Run your storybook and check the result:

Heading in Storybook

Step 3. Create a theme using Theme Provider

A theme is helpful if you would like to keep all variables in one place in a project or you need to create several page themes.

In this step, I will create a theme by wrapping all my components in a ThemeProvider wrapper component, and by referencing the properties of props.theme in our styled-components CSS. Create a theme directory in src/ and put there a index.js file. Next, create theme object with some properties:

src/theme/index.js

export default {
 color: {
   white: '#fff',
   black: '#000',
   lightGray: '#ececec',
   purple: '#744c9d',
 },
 size: {
   inner: '1260px',
 }
};

Wrap the IndexPage component in a ThemeProvider wrapper component. Remember to import theme and Theme Provider.

pages/index.js

import { ThemeProvider } from 'styled-components';

import theme from '../theme';

const IndexPage = () => (
  <ThemeProvider theme={theme}>
    <Layout>
      <Header/>
    </Layout>
  </ThemeProvider>
);

export default IndexPage;

And use theme properties in styled-components CSS:

Header/styles.js

const HeaderTitleStyled = styled.h1`
  font-size: 36px;
  font-weight: 600;
  color: ${props => props.theme.color.white};
`;

const HeaderStyled = styled.header`
  display: flex;
  align-items: center;
  width: 100%;
  background: ${props => props.theme.color.purple};
  padding: 20px 30px;
  height: 120px;

  ${props => props.light && css`
    background: ${props => props.theme.color.lightGray};

    ${HeaderTitleStyled} {
      color: ${props => props.theme.color.black}
    }
  `}
`;

Any change of property in theme/index.js, will update this property in the component where it was used.
Now my app works fine, but Storybook does not read theme property. To fix it, i’ll open Storybook config and add ThemeProvider to decorator.

import { ThemeProvider } from 'styled-components';
import theme from '../src/theme';

const Decorator = storyFn => (
 <ThemeProvider theme={theme}>
   <Fragment>
     <GlobalStyle/>
     {storyFn()}
   </Fragment>
 </ThemeProvider>
);

Theme Provider was added to the Storybook.

Step 4. Make your app responsive

The easiest way to build a responsive app is by using media queries like in normal CSS.

const HeaderStyled = styled.header`
  background: ${props => props.theme.color.black};

   @media only screen and (min-width: 1024px) {
     background: ${props => props.theme.color.purple};
   }
`;

However, let’s try to make media queries more dynamic. Set breakpoints values in breakpoints array in theme.js and then use it in media object in new created global/MediaQueries.js

theme/index.js

export default {
  breakpoints: ['768px', '1050px', '1440px'],
  ...
};

global/MediaQueries.js

import theme from '../theme';

const [
  phone,
  tablet,
  desktop,
] = theme.breakpoints;

const media = {
  phone: `min-width: ${phone}`,
  tablet: `min-width: ${tablet}`,
  desktop: `min-width: ${desktop}`,
};

export default media;

Import the media object and change CSS media query to a property of a media object.

import media from '../../global/MediaQueries';

const HeaderStyled = styled.header`
  ...
  background: ${props => props.theme.color.black};

  @media (${media.tablet}) {
    ...
    background: ${props => props.theme.color.purple};
   }
`;

The header looks this now:

Responsive header

To be continued…

That’s it for now.

In the next part, you will study dynamic components on the example of typography.

Comments
    Leave a Reply

    View Comments (0)...

    Related articles:

    What is JAMstack?

    How To Start With GatsbyJS – part 3: Gatsby Image