# Gatsby ## Step 1: Start gatsby project The Gatsby CLI tool lets you quickly create new Gatsby-powered sites and run commands for developing Gatsby sites. It is a published npm package. The Gatsby CLI is available via npm and should be installed globally by running: ``` js npm install -g gatsby-cli ``` When creating a new Gatsby site, you can use the following command structure to create a new site based on any existing Gatsby starter: ``` javascript gatsby new [SITE_DIRECTORY_NAME] [URL_OF_STARTER_GITHUB_REPO] ``` for example : to creat a new site based on the “hello world” starter using the following command: ``` javascript gatsby new hello-world https://github.com/gatsbyjs/gatsby-starter-hello-world ``` ### Familiarizing with Gatsby pages Open up the ``` /src ``` directory in your code editor. Inside is a single directory: ``` /pages ```. Open the file at ``` src/pages/index.js```. The code in this file creates a component that contains a single div and some text — appropriately, “Hello world!” ### Make changes to the “Hello World” homepage 1. Change the “Hello World!” text to “Hello Gatsby!” and save the file. If your windows are side-by-side, you can see that your code and content changes are reflected almost instantly in the browser after you save the file. 3. Now you can make your changes a little more visible. Try adding style to the code in ``` src/pages/index.js ``` . ``` javascript import React from "react" export default function Home() { return <div style={{ color: `purple`, fontSize: `72px` }}>Hello Gatsby!</div> } ``` You’ll see changes to the text — the text color will be purple and the font size will be larger. 3. Remove the font size styling, change the “Hello Gatsby!” text to a level-one header, and add a paragraph beneath the header. ``` javascript import React from "react" export default function Home() { return ( <div style={{ color: `purple` }}> <h1>Hello Gatsby!</h1> <p>What a world.</p> </div> ); } ``` 4. Add an image. (In this case, a random image from Unsplash). ``` javascript import React from "react" export default function Home() { return ( <div style={{ color: `purple` }}> <h1>Hello Gatsby!</h1> <p>What a world.</p> <img src="https://source.unsplash.com/random/400x200" alt="" /> </div> ) } ``` 5. Using page components Any React component defined in ``` src/pages/*.js ``` will automatically become a page. Let’s see this in action. You already have a ``` src/pages/index.js ``` file that came with the “Hello World” starter. Let’s create an about page. * Create a new file at ``` src/pages/about.js ```, add title and paragraph with teal color. ``` javascript import React from "react" export default function About() { return ( <div style={{ color: `teal` }}> <h1>About Gatsby</h1> <p>Such wow. Very React.</p> </div> ) } ``` * Navigate to http://localhost:8000/about/ Just by putting a React component in the ``` src/pages/about.js ``` file, you now have a page accessible at ``` /about ```. ![about](https://www.gatsbyjs.org/static/ff70fd3cbfd3a0e931b899ca245322fc/f1d1f/05-about-page.png) 6. Using sub-components Let’s say the homepage and the about page both got quite large and you were rewriting a lot of things. You can use sub-components to break the UI into reusable pieces. Both of your pages have ```<h1>``` headers — create a component that will describe a Header. * Create a new directory at ```src/components``` and a file within that directory called ```header.js```. * Add the following code to the new ```src/components/header.js``` file. ``` javascript import React from "react" export default function Header() { return <h1>This is a header.</h1> } ``` * Modify the ```about.js``` file to import the Header component. Replace the ```h1``` markup with ```<Header />```: ``` javascript import React from "react" import Header from "../components/header" export default function About() { return ( <div style={{ color: `teal` }}> <Header /> <p>Such wow. Very React.</p> </div> ) } ``` In the browser, the “About Gatsby” header text should now be replaced with “This is a header.” But you don’t want the “About” page to say “This is a header.” You want it to say, “About Gatsby”. ![header](https://www.gatsbyjs.org/static/ff64a1f15ebbe5e1f1aad740d0686ff7/321ea/06-header-component.png) #### What are “props”? Earlier, you defined React components as reusable pieces of code describing a UI. To make these reusable pieces dynamic you need to be able to supply them with different data. You do that with input called “props”. Props are (appropriately enough) properties supplied to React components. * Head back to ```src/components/header.js``` and make the following change: ``` javascript import React from "react" export default function Header(props) { return <h1>{props.headerText}</h1> } ``` * Head back to ``` src/pages/about.js``` and make the following change: ``` javascript import React from "react" import Header from "../components/header" export default function About() { return ( <div style={{ color: `teal` }}> <Header headerText="About Gatsby" /> <p>Such wow. Very React.</p> </div> ) } ``` You should now see your “About Gatsby” header text again! * If you had passed another prop to your ```<Header /> ```component, like so… ``` javascript <Header headerText="About Gatsby" arbitraryPhrase="is arbitrary" /> ``` you would have been able to also access the arbitraryPhrase prop: ```{props.arbitraryPhrase}```. * To emphasize how this makes your components reusable, add an extra ```<Header />``` component to the about page, add the following code to the ```src/pages/about.js``` file, and save. ``` javascript import React from "react" import Header from "../components/header" export default function About() { return ( <div style={{ color: `teal` }}> <Header headerText="About Gatsby" /> <Header headerText="It's pretty cool" /> <p>Such wow. Very React.</p> </div> ) } ``` ![reusable](https://www.gatsbyjs.org/static/439851d3a4ba8a727b4c07abefce54a9/321ea/08-duplicate-header.png) And there you have it A second header — without rewriting any code — by passing different data using props. ## Step 2: Layout components Layout components are for sections of your site that you want to share across multiple pages. For example, Gatsby sites will commonly have a layout component with a shared header and footer. Other common things to add to layouts are a sidebar and/or navigation menu. #### Creating layout components Now let’s move on to learning about layout components. To get ready for this part, add a couple new pages to your project: an about page and a contact page. `src/pages/about.js` ```jsx= import React from "react" export default function About() { return ( <div> <h1>About me</h1> <p> I’m good enough, I’m smart enough, and gosh darn it, people like me! </p> </div> ) } ``` `src/pages/contact.js` ```jsx= import React from "react" export default function Contact() { return ( <div> <h1>I'd love to talk! Email me at the address below</h1> <p> <a href="mailto:me@example.com">me@example.com</a> </p> </div> ) } ``` It would be nice if the content of the two new pages were centered like the index page. And it would be nice to have some sort of global navigation so it’s easy for visitors to find and visit each of the sub-pages. You’ll tackle these changes by creating your first layout component. #### Create your first layout component :+1: 1. Create a new directory at ``` src/components ``` 2. Create a very basic layout component at ``` src/components/layout.js ``` `src/components/layout.js` ```jsx= import React from "react" export default function Layout({ children }) { return ( <div style={{ margin: `3rem auto`, maxWidth: 650, padding: `0 1rem` }}> {children} </div> ) } ``` 3. Import this new layout component into your ``` src/pages/index.js ``` page component: `src/pages/index.js` ```jsx= import React from "react" import Layout from "../components/layout" export default function Home() { return ( <Layout> <h1>Hi! I'm building a fake Gatsby site as part of a tutorial!</h1> <p> What do I like to do? Lots of course but definitely enjoy building websites. </p> </Layout> ); } ``` But try navigating to ``` /about/ ```, or ``` /contact/ ```. The content on those pages still won’t be centered. 4. Import the layout component in ``` about.js ``` and ``` contact.js ``` (as you did for ``` index.js ``` in the previous step). The content of all three of your pages is centered thanks to this single shared layout component! #### Add a site title :smiley: 1. Add the following line to your new layout component: `src/components/layout.js` ```jsx= import React from "react" export default function Layout({ children }) { return ( <div style={{ margin: `3rem auto`, maxWidth: 650, padding: `0 1rem` }}> <h3>MySweetSite</h3> {children} </div> ) } ``` #### Add navigation links between pages :smile: Copy the following into your layout component file: `src/components/layout.js` ```jsx= import React from "react" import { Link } from "gatsby" const ListLink = props => ( <li style={{ display: `inline-block`, marginRight: `1rem` }}> <Link to={props.to}>{props.children}</Link> </li> ) export default function Layout({ children }) { return ( <div style={{ margin: `3rem auto`, maxWidth: 650, padding: `0 1rem` }}> <header style={{ marginBottom: `1.5rem` }}> <Link to="/" style={{ textShadow: `none`, backgroundImage: `none` }}> <h3 style={{ display: `inline` }}>MySweetSite</h3> </Link> <ul style={{ listStyle: `none`, float: `right` }}> <ListLink to="/">Home</ListLink> <ListLink to="/about/">About</ListLink> <ListLink to="/contact/">Contact</ListLink> </ul> </header> {children} </div> ) } ``` And there you have it! A three page site with basic global navigation. ## Step 3: Styling with Gatsby We’ll talk about one of the various methods of modularizing CSS to tackle styling in a component-oriented way. ### global css file * Create a .css file in your new project: ``` cd src mkdir styles cd styles touch global.css ``` * add backgeound color on global css file * create ``` gatsby-browser.js``` file on src folder * Import your recently-created stylesheet in the ```gatsby-browser.js``` file: ``` import "./src/styles/global.css" ``` ### CSS Modules A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. #### Build a new page using CSS Modules :grinning_face_with_star_eyes: In this section, you’ll create a new page component and style that page component using a CSS Module. First, create a new Container component. 1. Create a new directory at src/components and then, in this new directory, create a file named container.js and paste the following: `src/components/container.js` ```jsx= import React from "react" import containerStyles from "./container.module.css" export default function Container({ children }) { return <div className={containerStyles.container}>{children}</div> } ``` You’ll notice you imported a CSS module file named container.module.css. Let’s create that file now. 2. In the same directory (`src/components`), create a `container.module.css` file and copy/paste the following: `src/components/container.module.css` ```jsx= .container { margin: 3rem auto; max-width: 600px; } ``` You’ll notice that the file name ends with `.module.css` instead of the usual `.css.` This is how you tell Gatsby that this CSS file should be processed as a CSS module rather than plain CSS. 3. Create a new page component by creating a file at `src/pages/about-css-modules.js`: `src/pages/about-css-modules.js` ```jsx= import React from "react" import Container from "../components/container" export default function About() { return ( <Container> <h1>About CSS Modules</h1> <p>CSS Modules are cool</p> </Container> ) } ``` Now, if you visit http://localhost:8000/about-css-modules/ and see your page how it looks #### Other CSS options Gatsby supports almost every possible styling option - [Typography.js](https://www.gatsbyjs.org/packages/gatsby-plugin-typography/) - [Sass](https://www.gatsbyjs.org/packages/gatsby-plugin-sass/) - [JSS](https://www.gatsbyjs.org/packages/gatsby-plugin-jss/) - [stylus](https://www.gatsbyjs.org/packages/gatsby-plugin-stylus/) - [PostCSS](https://www.gatsbyjs.org/packages/gatsby-plugin-postcss/) ## Step 4: Data in Gatsby Data in Gatsby sites can come from anywhere: APIs, databases, CMSs, local files and other data sources of all flavors. Gatsby’s data layer that is powered by GraphQL lets you pull data from these (and any other source) directly into your components — in the shape and form you want. ### Introducing GraphiQL GraphiQL is the GraphQL integrated development environment (IDE). It’s a powerful (and all-around awesome) tool you’ll use often while building Gatsby websites. You can access it when your site’s development server is running—normally at `http://localhost:8000/___graphql` Try opening GraphiQL and play with your data! ![](https://i.imgur.com/t6Q9vdm.gif) The GraphiQL Explorer enables you to interactively construct full queries by clicking through available fields and inputs without the repetitive process of typing these queries out by hand. ### Source plugins Source plugins fetch data from their source. E.g. the filesystem source plugin knows how to fetch data from the file system. Add [gatsby-source-filesystem](https://www.gatsbyjs.org/packages/gatsby-source-filesystem/?=file%20system) and explore how it works. First, install the plugin at the root of the project: `npm install --save gatsby-source-filesystem ` Then add it to your `gatsby-config.js`: ```jsx= module.exports = { plugins: [ { resolve: `gatsby-source-filesystem`, options: { name: `src`, path: `${__dirname}/src/`, }, }, ], } ``` Save that and restart the gatsby development server. Then open up GraphiQL again. In the explorer pane, you’ll see allFile and file available as selections: ![](https://i.imgur.com/Yq3GkZn.png) Click the `allFile` dropdown. Position your cursor after `allFile` in the query area, and then type `Ctrl + Enter`. This will pre-fill a query for the `id` of each file. Press “Play” to run the query: ![](https://i.imgur.com/XCdvOCa.png) In the Explorer pane, the `id` field has automatically been selected. Make selections for more fields by checking the field’s corresponding checkbox. Press “Play” to run the query again, with the new fields: ![](https://i.imgur.com/uJOkHD4.png) Alternatively, you can add fields by using the autocomplete shortcut (`Ctrl + Space`). This will show queryable fields on the `File` nodes. ![](https://i.imgur.com/SG4eXVS.png) Try adding a number of fields to your query, press `Ctrl + Enter` each time to re-run the query. You’ll see the updated query results: ![](https://i.imgur.com/a36cLEj.png) The result is an array of `File` “nodes” (node is a fancy name for an object in a “graph”). Each `File` node object has the fields you queried for. ### Build a page with a GraphQL query Create a new file at `src/pages/my-files.js` with the `allFile` GraphQL query you just created: ```jsx= import React from "react" import { graphql } from "gatsby" import Layout from "../components/layout" export default function MyFiles({ data }) { console.log(data) return ( <Layout> <div>Hello world</div> </Layout> ) } export const query = graphql` query { allFile { edges { node { relativePath prettySize extension birthTime(fromNow: true) } } } } ` ``` The `console.log(data)` line is highlighted above. It’s often helpful when creating a new component to console out the data you’re getting from the GraphQL query so you can explore the data in your browser console while building the UI. If you visit the new page at `/my-files/` and open up your browser console you will see something like: ![](https://i.imgur.com/jnvXGF7.png) The shape of the data matches the shape of the GraphQL query. Add some code to your component to print out the File data. ```jsx= import React from "react" import { graphql } from "gatsby" import Layout from "../components/layout" export default function MyFiles({ data }) { console.log(data) return ( <Layout> <div> <h1>My Site's Files</h1> <table> <thead> <tr> <th>relativePath</th> <th>prettySize</th> <th>extension</th> <th>birthTime</th> </tr> </thead> <tbody> {data.allFile.edges.map(({ node }, index) => ( <tr key={index}> <td>{node.relativePath}</td> <td>{node.prettySize}</td> <td>{node.extension}</td> <td>{node.birthTime}</td> </tr> ))} </tbody> </table> </div> </Layout> ) } export const query = graphql` query { allFile { edges { node { relativePath prettySize extension birthTime(fromNow: true) } } } } ` ``` And now visit http://localhost:8000/my-files … 😲 ![](https://i.imgur.com/Y3qM6uv.png) ### Transformer plugins Often, the format of the data you get from source plugins isn’t what you want to use to build your website. The filesystem source plugin lets you query data about files but what if you want to query data inside files? To make this possible, Gatsby supports transformer plugins which take raw content from source plugins and transform it into something more usable. For example, markdown files. Markdown is nice to write in but when you build a page with it, you need the markdown to be HTML. Add a markdown file to your site at `src/pages/sweet-pandas-eating-sweets.md `(This will become your first markdown blog post) and learn how to transform it to HTML using transformer plugins and GraphQL. ```md --- title: "Sweet Pandas Eating Sweets" date: "2017-08-10" --- Pandas are really sweet. Here's a video of a panda eating sweets. <iframe width="560" height="315" src="https://www.youtube.com/embed/4n0xNbfJLR8" frameborder="0" allowfullscreen></iframe> ``` Once you save the file, look at `/my-files/` again—the new markdown file is in the table. This is a very powerful feature of Gatsby. Source plugins can live-reload data. `gatsby-source-filesystem` is always scanning for new files to be added and when they are, re-runs your queries. Add a transformer plugin that can transform markdown files: ``` npm install --save gatsby-transformer-remark ``` Then add it to the `gatsby-config.js` like normal: ```jsx module.exports = { plugins: [ { resolve: `gatsby-source-filesystem`, options: { name: `src`, path: `${__dirname}/src/`, }, }, `gatsby-transformer-remark`, ], } ``` Restart the development server then refresh (or open again) GraphiQL and look at the autocomplete: ![](https://i.imgur.com/DCFULAX.png) Select `allMarkdownRemark` again and run it as you did for `allFile`. You’ll see there the markdown file you recently added. Explore the fields that are available on the `MarkdownRemark` node. ![](https://i.imgur.com/XbZHJ78.png) ### Create a list of your site’s markdown files in `src/pages/index.js` Now you’ll have to create a list of your markdown files on the front page. Like many blogs, you want to end up with a list of links on the front page pointing to each blog post. With GraphQL you can query for the current list of markdown blog posts so you won’t need to maintain the list manually. Like with the `src/pages/my-files.js` page, replace `src/pages/index.js` with the following to add a GraphQL query with some initial HTML and styling. ```jsx= import React from "react" import { graphql } from "gatsby" import Layout from "../components/layout" export default function Home({ data }) { console.log(data) return ( <Layout> <div> <h1 style={{ display: "inline-block", borderBottom: "1px solid black" }} > Amazing Pandas Eating Things </h1> <h4>{data.allMarkdownRemark.totalCount} Posts</h4> {data.allMarkdownRemark.edges.map(({ node }) => ( <div key={node.id}> <h3 style={{ marginBottom: "1rem" }}> {node.frontmatter.title}{" "} <span style={{ color: "#bbb" }}>— {node.frontmatter.date}</span> </h3> <p>{node.excerpt}</p> </div> ))} </div> </Layout> ) } export const query = graphql` query { allMarkdownRemark { totalCount edges { node { id frontmatter { title date(formatString: "DD MMMM, YYYY") } excerpt } } } } ` ``` Now the frontpage should look like: ![](https://i.imgur.com/YPUQUcr.png) But your one blog post looks a bit lonely. So let’s add another one at `src/pages/pandas-and-bananas.md` ```md --- title: "Pandas and Bananas" date: "2017-08-21" --- Do Pandas eat bananas? Check out this short video that shows that yes! pandas do seem to really enjoy bananas! <iframe width="560" height="315" src="https://www.youtube.com/embed/4SZl1r2O_bY" frameborder="0" allowfullscreen></iframe> ``` ![](https://i.imgur.com/mv0GLAP.png) ## Step 5: Programmatically create pages from data You could continue to create pages by placing React components in src/pages. However, you’ll now learn how to programmatically create pages from data. Gatsby is not limited to making pages from files like many static site generators. Gatsby lets you use GraphQL to query your data and map the query results to pages—all at build time. Let’s get started. #### Creating slugs for pages A ‘slug’ is the unique identifying part of a web address, such as the `/tutorial/part-seven` part of the page `https://www.gatsbyjs.org/tutorial/part-seven/`. It is also referred to as the ‘path’ but we will use the term ‘slug’ for consistency. Creating new pages has two steps: 1. Generate the “path” or “slug” for the page. 2. Create the page. To create your markdown pages, you’ll learn to use two Gatsby APIs: [onCreateNode](https://www.gatsbyjs.org/docs/node-apis/#onCreateNode) and [createPages](https://www.gatsbyjs.org/docs/node-apis/#createPages). To implement an API, you export a function with the name of the API from `gatsby-node.js`. So, here’s where you’ll do that. In the root of your site, create a file named `gatsby-node.js`. Then add the following. ```javascript= exports.onCreateNode = ({ node }) => { console.log(node.internal.type) } ``` This `onCreateNode` function will be called by Gatsby whenever a new node is created (or updated). Stop and restart the development server. As you do, you’ll see quite a few newly created nodes get logged to the terminal console. In the next section, you will use this API to add slugs for your Markdown pages to `MarkdownRemark` nodes. Change your function so it now only logs `MarkdownRemark` nodes. ```javascript= exports.onCreateNode = ({ node }) => { if (node.internal.type === `MarkdownRemark`) { console.log(node.internal.type) } } ``` You want to use each markdown file name to create the page slug. So `pandas-and-bananas.md` will become /pandas-and-bananas/. But how do you get the file name from the `MarkdownRemark` node? To get it, you need to traverse the “node graph” to its parent `File` node, as `File` nodes contain data you need about files on disk. To do that, you’ll use the [getNode()](https://www.gatsbyjs.org/docs/node-api-helpers/#getNode) helper. Add it to `onCreateNode`’s function parameters, and call it to get the file node: ```javascript= exports.onCreateNode = ({ node, getNode }) => { if (node.internal.type === `MarkdownRemark`) { const fileNode = getNode(node.parent) console.log(`\n`, fileNode.relativePath) } } ``` After restarting your development server, you should see the relative paths for your two markdown files print to the terminal screen. ![](https://i.imgur.com/v6ESUYJ.png) Now you’ll have to create slugs. As the logic for creating slugs from file names can get tricky, the `gatsby-source-filesystem` plugin ships with a function for creating slugs. Let’s use that. ```javascript= const { createFilePath } = require(`gatsby-source-filesystem`) exports.onCreateNode = ({ node, getNode }) => { if (node.internal.type === `MarkdownRemark`) { console.log(createFilePath({ node, getNode, basePath: `pages` })) } } ``` The function handles finding the parent `File` node along with creating the slug. Run the development server again and you should see logged to the terminal two slugs, one for each markdown file. Now you can add your new slugs directly onto the `MarkdownRemark` nodes. This is powerful, as any data you add to nodes is available to query later with GraphQL. So, it’ll be easy to get the slug when it comes time to create the pages. To do so, you’ll use a function passed to your API implementation called [createNodeField](https://www.gatsbyjs.org/docs/actions/#createNodeField). This function allows you to create additional fields on nodes created by other plugins. Only the original creator of a node can directly modify the node—all other plugins (including your `gatsby-node.js`) must use this function to create additional fields. ```javascript= const { createFilePath } = require(`gatsby-source-filesystem`) exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { const slug = createFilePath({ node, getNode, basePath: `pages` }) createNodeField({ node, name: `slug`, value: slug, }) } } ``` Restart the development server and open or refresh GraphiQL. Then run this GraphQL query to see your new slugs.Restart the development server and open or refresh GraphiQL. Then run this GraphQL query to see your new slugs.Restart the development server and open or refresh GraphiQL. Then run this GraphQL query to see your new slugs. ```graphql= { allMarkdownRemark { edges { node { fields { slug } } } } } ``` Now that the slugs are created, you can create the pages. #### Creating pages In the same `gatsby-node.js` file, add the following. ```javascript= const { createFilePath } = require(`gatsby-source-filesystem`) exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { const slug = createFilePath({ node, getNode, basePath: `pages` }) createNodeField({ node, name: `slug`, value: slug, }) } } exports.createPages = async ({ graphql, actions }) => { // **Note:** The graphql function call returns a Promise // see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise for more info const result = await graphql(` query { allMarkdownRemark { edges { node { fields { slug } } } } } `) console.log(JSON.stringify(result, null, 4)) } ``` You’ve added an implementation of the [createPages](https://www.gatsbyjs.org/docs/node-apis/#createPages) API which Gatsby calls so plugins can add pages. As mentioned in the intro to this part of the tutorial, the steps to programmatically creating pages are: 1. Query data with GraphQL 2. Map the query results to pages The above code is the first step for creating pages from your markdown as you’re using the supplied graphql function to query the markdown slugs you created. Then you’re logging out the result of the query which should look like: ![](https://i.imgur.com/9x0i4uA.png) You need one additional thing beyond a slug to create pages: a page template component. Like everything in Gatsby, programmatic pages are powered by React components. When creating a page, you need to specify which component to use. Create a directory at `src/templates`, and then add the following in a file named `src/templates/blog-post.js`. ```javascript= import React from "react" import Layout from "../components/layout" export default function BlogPost() { return ( <Layout> <div>Hello blog post</div> </Layout> ) } ``` Then update `gatsby-node.js` ```javascript= const path = require(`path`) const { createFilePath } = require(`gatsby-source-filesystem`) exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions if (node.internal.type === `MarkdownRemark`) { const slug = createFilePath({ node, getNode, basePath: `pages` }) createNodeField({ node, name: `slug`, value: slug, }) } } exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions const result = await graphql(` query { allMarkdownRemark { edges { node { fields { slug } } } } } `) result.data.allMarkdownRemark.edges.forEach(({ node }) => { createPage({ path: node.fields.slug, component: path.resolve(`./src/templates/blog-post.js`), context: { // Data passed to context is available // in page queries as GraphQL variables. slug: node.fields.slug, }, }) }) } ``` Restart the development server and your pages will be created! An easy way to find new pages you create while developing is to go to a random path where Gatsby will helpfully show you a list of pages on the site. If you go to `http://localhost:8000/sdf`, you’ll see the new pages you created. ![](https://i.imgur.com/V0FqldI.png) Visit one of them and you see: ![](https://i.imgur.com/GO1B1z8.png) Which is a bit boring and not what you want. Now you can pull in data from your markdown post. Change `src/templates/blog-post.js` to: ```javascript= import React from "react" import { graphql } from "gatsby" import Layout from "../components/layout" export default function BlogPost({ data }) { const post = data.markdownRemark return ( <Layout> <div> <h1>{post.frontmatter.title}</h1> <div dangerouslySetInnerHTML={{ __html: post.html }} /> </div> </Layout> ) } export const query = graphql` query($slug: String!) { markdownRemark(fields: { slug: { eq: $slug } }) { html frontmatter { title } } } ` ``` And… ![](https://i.imgur.com/9UJvlWp.png) Sweet! The last step is to link to your new pages from the index page. Return to `src/pages/index.js`, query for your markdown slugs, and create links. ```javascript= import React from "react" import { Link, graphql } from "gatsby" import Layout from "../components/layout" export default function Home({ data }) { return ( <Layout> <div> <h1 style={{ display: "inline-block", borderBottom: "1px solid black" }} > Amazing Pandas Eating Things </h1> <h4>{data.allMarkdownRemark.totalCount} Posts</h4> {data.allMarkdownRemark.edges.map(({ node }) => ( <div key={node.id}> <Link to={node.fields.slug} style={{ textDecoration: "none", color: "inherit" }} > <h3 style={{ marginBottom: "1rem" }}> {node.frontmatter.title}{" "} <span style={{ color: "#bbb" }}>— {node.frontmatter.date}</span> </h3> <p>{node.excerpt}</p> </Link> </div> ))} </div> </Layout> ) } export const query = graphql` query { allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) { totalCount edges { node { id frontmatter { title date(formatString: "DD MMMM, YYYY") } fields { slug } excerpt } } } } ` ``` And there you go! A working, albeit small, blog! ## What is SEO? Search engine optimization is the process of growing the quality and quantity of website traffic by increasing the visibility of a website or a web page to users of a web search engine. ### SEO with Gatsby Gatsby can help your site rank and perform better in search engines. Using Gatsby makes your site fast and efficient for search engine crawlers, like Googlebot, to crawl your site and index your pages. Some advantages, like speed, come out of the box and others require configuration. ### Adding an SEO Component Every site on the web has basic meta-tags like the title, favicon or description of the page in their ``<head>`` element. This information gets displayed in the browser and is used when someone shares your website, e.g. on Twitter. You can give your users and these websites additional data to embed your website with more data — and that’s where this guide for a SEO component comes in. At the end you’ll have a component you can place in your layout file and have rich previews for other clients, smartphone users, and search engines. ### What is a Progressive Web App? “Progressive web app” (PWA) is both a general term for a new philosophy toward building websites and a specific term with an established set of three explicit, testable, baseline requirements. As a general term, the PWA approach is characterized by striving to satisfy the following set of attributes: - Responsive - Connectivity independent - App-like-interactions - Fresh - Safe - Discoverable - Re-engageable - Installable - Linkable As a specific term, websites can be tested against the following three baseline criteria to qualify as a PWA: - It must run under HTTPS. - It must include a Web App Manifest. - It must implement a service worker. PWAs are apps delivered through the web (as opposed to native apps, which are packaged and deployed through stores). As Alex Russell, who together with Frances Berriman coined the term PWA, said: they’re just websites that took all the right vitamins. ### How is a Gatsby site a Progressive Web App? Gatsby is designed to provide top-notch performance out of the box. It handles code splitting, code minification, and optimizations like pre-loading in the background, image processing, etc., so that the site you build is highly performant, without any kind of manual tuning. These performance features are a big part of supporting the progressive web app approach. Then there are the three baseline criteria for a site to qualify as a PWA.