[sic]
A few days ago to chat with the old iron, an old iron said that I want to get a blog only by SEO search, want to return to once again that simple. Then I remembered my old blog.
Chatting online to find a good static blog frame available, after all, for a long time did not update the blog frame. As luck would have it, the first item I recommended to use in the article I read was Gatsby, which seems to be quite good after I read it on the official website. Later I learned that the React website is also built using this framework 😝.
I had some free time just a year ago, so I started working on it. From Jekyll, Hexo, octopress, and now Gatsby. Here is a little experience to share with you.
1. Initial project construction
Install project tools first:
npm i -g gatsby-cli
Copy the code
Generated projects:
npm new [your project name]
Copy the code
See package.json in the directory for the project commands.
Run the following command to see the basic blog site generated by the project tool.
gatsby develop
Copy the code
A brief description of the project structure:
Directories/Files | instructions |
---|---|
src/components | The directory where the component is placed |
src/pages | Directory of pages rendered in base mode (routing by filename) |
gatsby-config.js | Middleware configuration and website basic information configuration file |
gatsby-node.js | Render pages in advanced mode (generate routes based on path configuration) |
< Here’s what was added later > | |
src/queries | The Graphql query statement places the directory |
src/templates | Place directories of templates used to render pages in advanced mode |
static | A static file placement directory that is automatically merged into the publishing directory when publishing |
deploy.sh | A script to officially publish the site |
2. Modify the navigation bar
SRC /components/header/SRC /components/header /
Copy the code from the original file to index.jsx and modify it as appropriate.
. class Header extends React.Component {constructor(props) {
super(props)
this.state = {
currentMenu: 'home'
}
}
componentDidMount() {
const { pathname } = window.location
const extract = pathname.split('/') [1]
this.setState({ currentMenu: extract === ' ' ? 'home' : extract })
if (extract === ' ' || / ^ [0-9] + $/.test(extract)) {
this.setState({ currentMenu: 'home'})}else if (extract === 'about') {
this.setState({ currentMenu: 'about'})}else if (extract === 'blog' || extract.length === 24) {
this.setState({ currentMenu: 'blog'})}else {
this.setState({ currentMenu: 'null' })
}
}
render() {
const { siteTitle } = this.props
const { currentMenu } = this.state
return <div className="header">
<div className="container">
<ul>
<li className="site-title">
<h1><Link to="/">{siteTitle}</Link></h1>
</li>
<li className={currentMenu= = ='home' ? 'menu-item currentMenu' : 'menu-item'} >
<h3><Link to="/">Home</Link></h3>
</li>
<li className={currentMenu= = ='blog' ? 'menu-item currentMenu' : 'menu-item'} >
<h3><Link to="/blog">Blog</Link></h3>
</li>
<li className={currentMenu= = ='about' ? 'menu-item currentMenu' : 'menu-item'} >
<h3><Link to="/about">About</Link></h3>
</li>
</ul>
</div>
</div>}}...Copy the code
Added the state of the current menu for menu state management.
Ul > li is serialized horizontally, with the first being used as the site title and the others as menu items.
Note: 1. In the judgment part of the home page, the function of turning pages on the home page will be added later, so the numerical judgment is added. 2. In the judgment part of the post, prepare to use 24-bit random code as the address of each post. So in addition to the blog also added a random code length judgment.
The style section is just a matter of personal preference.
3. Blog list
As a blog, the most important or blog part, the blog part out first.
Previous blog posts were written using Markdown, and the markDown parsing tool was installed and configured first.
npm i gatsby-source-filesystem
npm i gatsby-transformer-remark
npm i gatsby-plugin-catch-links
Copy the code
Change the Gatsby plugin configuration to Gatsby -config.js:
. plugins: [ ... {resolve: 'gatsby-source-filesystem'.options: {
name: 'pages'.path: `${__dirname}/src/pages`}},'gatsby-transformer-remark'.'gatsby-plugin-catch-links'. ] .Copy the code
Once configured, you can either create an MD file in the SRC/Pages directory or create a directory and create an MD file in it. The Markdown parsing section is complete.
If you’ve followed the console prompt at startup, you know that you can do GraphiQL queries by visiting http://localhost:8000/___graphql.
Take a look at the blog header:
- path: '/ yp63Vswica5FHmJGE479XP5k' title: '1' static builds with Gatsby blog date: 2019-01-31 18:56:00 + 0800 comments: true categories : programing author : Sir0xbtags : [Gatsby, React] ---
Copy the code
This information is important, and it’s all fields that will be queried later.
Open http://localhost:8000/___graphql and type in the search criteria on the left:
{
allMarkdownRemark(sort: {fields: [frontmatter___date], order: DESC}) {
edges {
node {
id
html
frontmatter {
path
title
date
comments
author
tags
}
excerpt
}
}
}
}
Copy the code
When you see the query results, you can probably understand what each field means without too much explanation.
With a working query expression, we are ready to start rendering.
Remember when you revamped the menu and added a path /blog? Create a blog.js file in SRC /pages
import React from 'react'
import { Link, graphql } from 'gatsby'
const BlogPage = ({ data }) = > (
<div>
<h1>This is the blog page</h1>
{data.allMarkdownRemark.edges.map(post => (
<div key={ post.node.id} >
<h3>{post.node.frontmatter.title}</h3>
<small>Posted by {post.node.frontmatter.author} on {post.node.frontmatter.date}</small>
<br/>
<br/>
<Link to={post.node.frontmatter.path}>Read More</Link>
<br/>
<br/>
<hr/>
</div>
))}
</div>
)
export const pageQuery = graphql` { allMarkdownRemark(sort: {fields: [frontmatter___date], order: DESC}) { edges { node { id html frontmatter { path title date comments author tags } excerpt } } } } `
export default BlogPage
Copy the code
The logic behind Gatsby’s GraphiQL file query is to do the data query by exporting the pageQuery and injecting the results into the data of the current Component props.
After rebooting, click on menu Blog to see a list of all articles.
4. Blog preview
Click on the blog to find page 404. The reason is that there is no file corresponding to our 24-bit random code path found in SRC/Pages.
This is where the advanced rendering of the page comes in.
Let’s start with a template file SRC /templates/post.js for the blog preview
import React from 'react'
import { graphql } from 'gatsby'
import Layout from '.. /components/layout'
import SEO from '.. /components/seo'
import './style.css'
const Template = ({ data }) = > {
const post = data.markdownRemark
return <Layout>
<SEO title={post.frontmatter.title} />
<button
className="go-back"
onClick={()= > { window.history.back() }}
>Go back</button>
<div className="blog-post">
<h1>{post.frontmatter.title}</h1>
<h4>Posted by {post.frontmatter.author} on {post.frontmatter.date}</h4>
<div dangerouslySetInnerHTML={{__html: post.html}} ></div>
</div>
</Layout>
}
export const postQuery = graphql`
query BlogxxxPostByPath($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
path
title
author
date
}
}
}
`
export default Template
Copy the code
SRC /queries/ queryall.js. The query in the blog.js file is left untouched. (The blog.js file was later abandoned.)
Open the gatsby-node.js file.
const path = require('path')
const queryAll = require('./src/queries/queryAll')
exports.createPages = ({ boundActionCreators, graphql }) = > {
const { createPage } = boundActionCreators
return new Promise((resolve, reject) = > {
resolve(
graphql(queryAll).then(result= > {
if (result.errors) reject(result.errors)
// Generate a page based on the article ID
const postTemplate = path.resolve('./src/templates/post.js')
result.data.allMarkdownRemark.edges.forEach(({ node }) = > {
createPage({
path : node.frontmatter.path,
component : postTemplate
})
})
})
)
})
}
Copy the code
Restart the article and then click open, is it normal to render.
5. Add a page Turner
After years of blogging that many posts, it would be unfriendly to show them all at once.
The solution was to add a page-turner, starting with the Gatsby page-turner tool.
npm i gatsby-paginate
Copy the code
You can use the code provided in the Demo, or you can develop it yourself.
I prefer to have buttons of “Most”, “Last”, “Previous page” and “Next Page” both before and after, with at least two page numbers left in the lower part of the page number, at least two page numbers left in the higher part, and two page numbers left before and after the current page number.
So let’s implement the page Turner component first. src/components/Paginator/index.jsx
import React from 'react'
import { Link } from 'gatsby'
import './style.css'
const getRandomStr = (len = 15) = > {
let text = ' '
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (let i = 0; i < len; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}
const Paginator = ({ index, pageCount, relativeUrl }) = > {
let result = []
result.push(<Link key={getRandomStr()} to={relativeUrl}>{} '«'</Link>)
if (index <= 2) {
result.push(<Link key={getRandomStr()} to={relativeUrl}>{'<'}</Link>)}else {
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${index - 1} `} >{'<'}</Link>)}if (pageCount < 11) {
Object.keys(Array.from({ length: pageCount })).forEach((item, listIndex) = > {
result.push(
<Link
key={getRandomStr()}
className={listIndex + 1= = =index ? 'currentPage' :"'}to={` ${relativeUrl} / ${listIndex= = =0? ' ': listIndex + 1} `} >{listIndex + 1}</Link>)})}else {
if (index <= 5) {
// index + 2
Object.keys(Array.from({ length: index + 2 })).forEach((item, listIndex) = > {
result.push(
<Link
key={getRandomStr()}
className={listIndex + 1= = =index ? 'currentPage' :"'}to={` ${relativeUrl} / ${listIndex= = =0? ' ': listIndex + 1} `} >{listIndex + 1}</Link>
)
})
result.push(<span key={getRandomStr()}>.</span>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${pageCount - 1} `} >{pageCount - 1}</Link>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${pageCount} `} >{pageCount}</Link>)}else if (index >= pageCount - 4) {
// index - 2 hits the top
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} `} >1</Link>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} /2`} >2</Link>)
result.push(<span key={getRandomStr()}>.</span>)
// pageCount - (index - 2) + 1 = pageCount - index + 3
Object.keys(Array.from({ length: pageCount - index + 3 })).forEach((item, listIndex) = > {
let newIndex = listIndex + index - 3
result.push(
<Link
key={getRandomStr()}
className={newIndex + 1= = =index ? 'currentPage' :"'}to={` ${relativeUrl} / ${newIndex= = =0? ' ': newIndex + 1} `} >{newIndex + 1}</Link>)})}else {
// Index + 2 ~ index + 2
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} `} >1</Link>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} /2`} >2</Link>)
result.push(<span key={getRandomStr()}>.</span>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${index - 2} `} >{index - 2}</Link>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${index - 1} `} >{index - 1}</Link>)
result.push(<Link key={getRandomStr()} className="currentPage" to={` ${relativeUrl} / ${index} `} >{index}</Link>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${index + 1} `} >{index + 1}</Link>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${index + 2} `} >{index + 2}</Link>)
result.push(<span key={getRandomStr()}>.</span>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${pageCount - 1} `} >{pageCount - 1}</Link>)
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${pageCount} `} >{pageCount}</Link>)}}if (index === pageCount) {
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${pageCount} `} >{} '>'</Link>)}else {
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${index + 1} `} >{} '>'</Link>)
}
result.push(<Link key={getRandomStr()} to={` ${relativeUrl} / ${pageCount} `} >{} '»'</Link>)
return <div className="paginator">
{result}
</div>
}
export default Paginator
Copy the code
Note: because pagers may be used on the home page as well as the blog page, the relative path relativeUrl is passed in.
Rename or delete SRC /pages/blog.js. We are going to generate the blog page in an advanced way instead of using the original page.
Make a blog page rendering template with pagers. src/templates/posts.js
import React from 'react'
import Link from 'gatsby-link'
import Layout from '.. /components/layout'
import SEO from '.. /components/seo'
import Paginator from '.. /components/Paginator'
const Template = ({ pageContext }) = > {
const {
group,
index,
pageCount
} = pageContext
return <Layout>
<SEO title="Blog" />
<Paginator index={index} pageCount={pageCount} relativeUrl="/blog" />
{group.map(({ node }) => (
<div className="normal-homepage-item" key={node.id}>
<h3>{node.frontmatter.title}</h3>
<small>Posted by {node.frontmatter.author} on {node.frontmatter.date}</small>
<br/>
<br/>
<Link to={node.frontmatter.path}>Read More</Link>
<br/>
</div>
))}
<Paginator index={index} pageCount={pageCount} relativeUrl="/blog" />
</Layout>
}
export default Template
Copy the code
With a page Turner component, with a template, there’s no data.
Modify the gatsby – node. Js
const path = require('path')
const createPaginatedPages = require('gatsby-paginate')
const queryAll = require('./src/queries/queryAll')
exports.createPages = ({ actions, graphql }) = > {
const { createPage } = actions
return new Promise((resolve, reject) = > {
resolve(
graphql(queryAll).then(result= > {
if (result.errors) reject(result.errors)
// Generate a blog page flip
const PostsTemplate = path.resolve('./src/templates/posts.js')
createPaginatedPages({
edges : result.data.allMarkdownRemark.edges,
createPage : createPage,
pageTemplate : PostsTemplate,
pageLength : 10.pathPrefix : 'blog'
})
// Generate a page based on the article ID
const postTemplate = path.resolve('./src/templates/post.js')
result.data.allMarkdownRemark.edges.forEach(({ node }) = > {
createPage({
path : node.frontmatter.path,
component : postTemplate
})
})
})
)
})
}
Copy the code
Note: Since the Gatsby version is required to be higher than the default, I upgraded the Gatsby version to the highest. So there’s a change here. The original boundActionCreators became Actions.