手把手带你入门 Gatsby

Gatsby 介绍

什么是 Gatsby

Gatsby 是一个基于 React ,用于搭建静态站点的开源框架,用于帮助 开发者构建运行速度极快的网站。能够说它是一个静态站点生成器,Gatsby 主要的应用的技术是 React 和 GraphQL。javascript

官网:https://www.gatsbyjs.org/css

为何选 Gatsby

Gatsby 能快速使用 React 生态系统来生成静态网站,它具有更高的性能,并且 Gatsby 的生态也很强大。html

当你想本身动手搭建我的博客时,考虑的是 SEO 要好,并且你不用理会数据库和服务器等复杂的部署设置,Gatsby 构建的网站为静态站点,你能够很轻松的将网站部署在不少服务上。Gatsby 不须要等待请求时生成页面,而是预先生成页面,所以网站的速度会很快。java

Gatsby 中运用了 React, react-router, Webpack 以及 GraphQL 等新技术,也跟随了技术潮流。node

GraphQL 介绍

上面咱们说到了 GraphQL,没了解的同窗可能不太清楚。react

GraphQL 是一种用于 API 的查询语言,是 Restful API 的替代品。

至于替代 Restful API 一说,我的以为如今 Restful API 占据绝对的主导地位,当前仍是很难被撼动的。由于目前来看,GraphQL 也有它的缺点。git

看到这里没学过 GraphQL 也不用怕,由于用到的很少并且 Gatsby 内置一个界面方便咱们操做。GraphQL 目前国外比较火,它做为一门新技术,即便不深刻咱们也能够了解一下。程序员

这里咱们固然要吹捧它的优势,上面的定义你可能会疑惑,API 不就是后端写好的接口吗,怎么还能查询?github

GraphQL 咱们把这个单词拆开的话是: Graph(图形或图表) + QL(Query Language),它是一种图形化的查询语言,描述客户端如何像服务端请求数据的语法规范。听起来模模糊糊,那它相对 Restful API 又解决了什么痛点呢?数据库

  1. 请求你所要的数据很少很多

相信多数人确定遇到过的场景,好比项目管理系统,进入某页面展现一个列表,列表上只需展现标题,但你请求返回的数据却多了其余信息,好比建立者、建立时间等。这些信息在这里是多余的,但它可能有它本身存在的理由,或许是其余场景须要返回这些信息,所以该接口就直接包含了全部数据。

这一点,GraphQL 能准确获取你想要的数据,很少很多,想要返回指定的什么数据,就返回什么数据。数据由应用来控制,而不是服务器。

  1. 获取多个资源只须要一个请求

GraphQL 查询不只可以得到资源的属性,还能沿着资源间引用进一步查询。典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 能够经过一次请求就获取你应用所需的全部数据。这样一来,即便是比较慢的移动网络链接下,使用 GraphQL 的应用也能表现得足够迅速。

  1. 描述全部的可能类型系统

GraphQL API 基于类型和字段的方式进行组织,而非入口端点。你能够经过一个单一入口端点获得你全部的数据能力。GraphQL 使用类型来保证应用只请求可能的数据,还提供了清晰的辅助性错误信息。应用可使用类型,而避免编写手动解析代码。

Gatsby 使用了 GraphQL,做为在本地管理资源的一种方式。

搭建项目

开始

  • 安装 Gatsby 脚手架
npm install -g gatsby-cli
  • 新建项目
gatsby new projectName:根据 starter 建立一个新项目
gatsby new gatsby-blog-demo https://github.com/gatsbyjs/gatsby-starter-hello-world

咱们这里使用官方最简单版本的 hello-world 模板进行开发,若是你直接使用

gatsby new gatsby-blog-demo

默认会使用 gatsby-starter-default 来新建项目

  • 运行项目
cd gatsby-blog-demo
gatsby develop

打开 localhost:8000,就能够看到输出了一句Hello world!

经常使用命令

这里介绍 Gatsby 的几个经常使用命令:

  • gastby develop:开启热加载开发环境
  • gastby build:打包到 public 下,构建生产环境用的优化过的静态网站所需的一切静态资源、静态页面与 js 代码
  • gatsby serve:在打包以后,启动一个本地的服务,供你测试刚才"gatsby build"生成的静态网页

GraphiQL

打开http://localhost:8000/__graphql,就会看到 GraphQL 的调试界面,这里能够查看全部的数据、以及调试 query 语句是否返回相应的数据。能够直接在左侧点击选中,就能够自动生成 query 语句。

可能出现的警告

若是运行后你的控制台出现:

React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work.

能够这样解决:

npm install @hot-loader/react-dom

在根目录下新建gatsby-node.js

exports.onCreateWebpackConfig = ({ getConfig, stage }) => {
  const config = getConfig()
  if (stage.startsWith('develop') && config.resolve) {
    config.resolve.alias = {
      ...config.resolve.alias,
      'react-dom': '@hot-loader/react-dom'
    }
  }
}

再从新启动项目,就能够消除这个警告

项目结构

├── .cache
├── public
├── src
|  └── pages            // 该文件夹下的文件会被映射为路由
|     └── index.js
├── static              // 静态资源
├── .prettierignore
├── .prettierrc
├── gatsby-config.js    // 基本配置文件
├── LICENSE
├── package.json
├── README.md
└── yarn.lock

Gatsby 配置文件

这里最初始的模板只有一个配置文件,通常项目中都会有 4 个配置文件

gatsby-config.js

基本配置文件。整个 Gatsby 站点的配置文件。能够在里面配置网站的相关基本信息。

gatsby-node.js

node 相关配置文件。这个文件只会在 build 期间运行一次,好比动态建立一些页面。

gatsby-browser.js

客户端相关配置。一些浏览器相关的 API 经过在这个文件里去实现,好比一些监听路由变化,注册 serviceWorker 等等。

gatsby-ssr.js

服务端渲染相关配置文件。使用 Gatsby 的服务端渲染 API 自定义影响服务端渲染的默认设置。

建立页面

路由页

咱们在 pages目录下建立一个文件about.js,则对应的路由路径为/about

import React from 'react'

const About = () => {
  return <div>about me</div>
}

export default About

打开http://localhost:8000/about,显示的是咱们刚刚建立的页面

404 页面

pages目录下的文件名便是路由路径,但有一个比较特殊,当匹配不到路径时,Gatsby 会跳转到 404 页面,若是咱们在 pages 下建立文件名404.js,会使用咱们自定义的 404 页面。当前咱们随便输入一个不存在的页面路径:http://localhost:8000/test,页面就会报错。

咱们新建一个文件 404.js

import React from 'react'

const About = () => {
  return <div>404 页面不存在</div>
}

export default About

再随便输入一个路径,显示出该页面:

Gatsby 会确保将 404 页面构建为 404.html,默认状况下会为咱们建立此页面,在该页面也列出了网站上的全部页面路由连接,咱们能够经过单击Preview custom 404 page看咱们刚才建立的 404 页面。

那咱们想直接跳转到咱们自定义的 404 页面啊,还要咱们点击才跳转。缘由是处于开发环境,即当使用 gatsby develop时,Gatsby 使用默认的 404 页面覆盖咱们自定义的 404 页面,但其实是已经生效了。

咱们能够打包,启动一个本地的服务,模拟处于线上环境来看,这个时候才是直接显示咱们自定义的 404 页面。

gatsby build
gatsby serve

而后打开http://localhost:9000/test(任意路径),就能跳转到咱们自定义的 404 页面了

建立布局组件

  1. 建立一个新目录 src/components
  2. 在上面的目录中建立一个布局组件文件 src/components/layout.js:
import React from 'react'

export default ({ children }) => (
  <div style={{ margin: `3rem auto`, maxWidth: 650, padding: `0 1rem` }}>{children}</div>
)
  1. src/pages/index.js中,加入 Layout 组件,
import React from 'react'
import Layout from '../components/layout'

export default function Home() {
  return <Layout>Hello world!</Layout>
}

这样就让总体页面居中了,这里都是 React 的基本操做

设置 CSS 样式

Gatsby 中样式可使用多种形式,普通的 import './xxx.css咱们就不说了。

使用全局样式

咱们向网站添加全局样式的最直接的方法之一就是使用全局 .css 样式表。

在 src 目录下新建文件夹styles,添加一个 global.css 文件

html {
  background-color: #f5f5f5;
}
  • 在目录下建立 gatsby-browser.js 中,将样式文件导入
import "./src/styles/global.css"

重启本地服务,就发现页面背景变为浅灰色了。

使用 CSS Module 为组件设置样式

CSS Module 能够减小全局污染、防止命名冲突和样式的覆盖。

CSS Module 实现原理是:将全部模块化的类名,修改成成惟一的名称,即添加一些不重复的前缀或后缀。这样使得项目中,不一样人员编写的样式不会出现覆盖和冲突。
  1. 建立 CSS 文件 src/styles/index.module.css
.title {
  color: red;
}
.text {
  color: blue;
}

用法以下:src/pages/index.js

import React from "react"
import Layout from "../components/layout"
import styles from "../styles/index.module.css"

export default function Home() {
  console.log(styles)
  return (
    <Layout>
      <h1 className={styles.title}>Hello World</h1>
      <div className={styles.text}>Test</div>
    </Layout>
  )
}

运行结果:

输出 styles,能够看到被导入处理的结果:


若是将其与 CSS 文件进行比较,你会发现每一个格式如今都是导入对象中指向长字符串的键(key),例如 title 指向 index-module--title--1i-Wh。 这些样式名称是 CSS 模块生成的。 保证它们在你的网站上是惟一的。 并且因为必须导入它们才能使用这些类,因此对于在任何地方使用这些 CSS 样式都没问题。

其余处理 CSS 的方式

使用 css 样式就点到为止了,其余的好比 Sass 等;还有 CSS in JS 的方式,好比 Emotion, Styled Component。能够去官网查看相应支持的 Gatsby 插件,就可使用了。

获取 Gatsby 中的数据

创建网站时,您可能须要重用一些经常使用的数据——好比公用的网站标题、做者信息等,咱们不可能在每一个页面都加,因此咱们把标题存储在一个位置,而后从其余文件引用该位置就好了,更改的时候也只能更改这一处地方。

这些经常使用数据的存放位置就是 gatsby-config.js 文件中的 siteMetadata 对象。打开这个文件,写入代码:

module.exports = {
  /* Your site config here */
  siteMetadata: {
    title: `Title from siteMetadata`,
    author: 'jacky'
  },
  plugins: [],
}

重启服务

使用页面查询

编辑 src/pages/about.js

import React from 'react'
import { graphql } from 'gatsby'

// GraphQL 获取的数据,会当作参数传递到页面组件中
// 数据的形式是 { errors, data },没有错误则不会有 errors
const About = ({ data }) => {
  console.log(data.site.siteMetadata.title)
  return (
    <div>
      <h1>Title: {data.site.siteMetadata.title}</h1>
      <p>author: {data.site.siteMetadata.author}</p>
      <div>about me</div>
    </div>
  )
}

export default About

export const query = graphql`
  query {
    site {
      siteMetadata {
        title
        author
      }
    }
  }
`

而后就拉出数据了

其中,GraphQL 查询语句是:

{
  site {
    siteMetadata {
      title,
      author
    }
  }
}

你可能会懵逼, site 是哪里来的,这数据格式怎么是这样,这就是 GraphQL 查询语句了,咱们能够打开 Gatsby 内置的 GraphQL 调试界面 http://localhost:8000/__graphql

这里的site即为咱们gatsby-config.js写的站点配置。

依次点击左边的sitesiteMetadata,而后有咱们刚才写的title,author字段 供咱们选择,在点击的同时,中间的框会生成查询语句,最后点击运行按钮,会输出查询结果。

当你后面须要获取更多复杂嵌套数据的时候,能够直接在这个界面找和点击,自动生成查询语句就好了。

由咱们本身写的查询语句也知道,上面咱们介绍 GraphQL 的时候说的一个特色,获取数据很少很多,即咱们能够选择想要的数据,好比我就想获取标题不想获取做者

export const query = graphql`
  query {
    site {
      siteMetadata {
        title
      }
    }
  }
`

使用非页面组件查询(静态查询)

这里注意,咱们须要区分两种方式的查询,上面的例子的查询方式,只适用于页面查询,便是在src/pages下的路由界面,若是在非页面组件下进行 GraphQL 查询,则不能用上面的方式,应该使用 StaticQuery 组件或者 useStaticQuery hook

// 页面查询
export const query = graphql`
    query{ ... }
`

好比咱们建立一个组件src/components/header.js

  • StaticQuery
import React from 'react'
import { graphql, StaticQuery } from 'gatsby'

const Header = () => (
  <StaticQuery
    query={graphql`
      query {
        site {
          siteMetadata {
            author
          }
        }
      }
    `}
    render={data => {
      const {
        site: { siteMetadata },
      } = data
      return <div>这是Header组件,做者是:{siteMetadata.author}</div>
    }}
  />
)

export default Header

或者使用 useStaticQuery 方式

  • useStaticQuery
import React from "react"
import { useStaticQuery, graphql } from "gatsby"

const Header = () => {
  const data = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            author
          }
        }
      }
    `
  )
  return <div>这是Header组件,做者是:{data.site.siteMetadata.author}</div>
}

export default Header

而后在src/pages/index.js中引入 Header 组件

import React from 'react'
import Layout from '../components/layout'
import Header from '../components/header'
import styles from '../styles/index.module.css'

export default function Home() {
  return (
    <Layout>
      <Header />
      <h1 className={styles.title}>Hello World</h1>
      <div className={styles.text}>Test</div>
    </Layout>
  )
}

运行结果以下:

插件

gatsby-source-filesystem

这个是 Gatsby 的数据源插件,即经过该插件将各方面的数据转换为本地可以经过 GraphQL 提取的内容,用于设置项目的文件系统。

  • 安装插件
npm install --save gatsby-source-filesystem
  • 在 gatsby-config.js 文件配置
module.exports = {
  siteMetadata: {
    title: `Title from siteMetadata`,
    author: 'jacky',
  },
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`, // 名称,能够用来过滤
        path: `${__dirname}/src/`, // 文件路径
      },
    },
  ],
}

重启服务

打开http://localhost:8000/__graphql,关注allFilefile两个可选项。

咱们点击 allFile这个可选项,依次选择以下图

这里咱们要知道,咱们要查询的数据基本在edges.node下,节点 node是图(graph)中一个对象的特殊称呼,每一个 File 节点都包含了你要查询的字段。

咱们选择的id,relativePath,name字段都对应咱们 src目录下建立的文件, 还有不少其余字段可选择,由此可知咱们建立的 7 个文件的各类信息。

既然这里能查询出来,说明咱们组件里面也能查出来而后使用数据,好比你能够从组件中查询出来作个文件列表。

这个相比传统的 React 项目就挺厉害了,不用作什么复杂的工做,就能轻松拿下这些数据。Gatsby 比较强大的就是它的生态了,不少插件都配好了,更多插件能够看官网的插件库介绍:https://www.gatsbyjs.org/plug...

gatsby-transformer-remark

这个是数据转换插件,咱们用 Gatsby 作我的博客的话,它可必不可少。如今咱们程序员写博客基本是用 markdown 语法了,作一个博客的话,不可缺乏的就是对 markdown 语法的解析。

  • 安装插件
npm install --save gatsby-transformer-remark
  • 在 gatsby-config.js 文件配置
module.exports = {
  /* Your site config here */
  siteMetadata: {
    title: `Title from siteMetadata`,
    author: 'jacky',
  },
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`, // 名称,能够用来过滤
        path: `${__dirname}/src/`, // 文件路径
      },
    },
    `gatsby-transformer-remark`,
  ],
}

重启服务

这个插件添加了 allMarkdownRemark 和 markdownRemark 两个数据字段

  • 新建 md 文件

src下建立_posts目录,添加一个first-blog.md文件

---
title: "个人第一篇博客"
date: "2020-06-21"
tags: "React"
categories: "React系列"
---

## 这是第一篇博客的标题

first blog 的内容 1

若是博客不是本身搭建的,而是直接上某平台写的话,对上面这段语法就可能不太了解,在 md 文件开头的 --- 包裹的是 frontmatter(前言),而后在里面能够添加文章的各类关键词信息。

而后咱们就能够在http://localhost:8000/__graphql查询到咱们写的 md 文件的详情信息了

咱们稍微再改动,建立多两个 md 文件

second-blog.md

---
title: "个人第二篇博客"
date: "2020-06-22"
tags: "Vue"
categories: "Vue系列"
---

## 这是第二篇博客的标题

second blog 的内容 2

third-blog.md

---
title: "个人第三篇博客"
date: "2020-06-23"
tags: "React"
categories: "React系列"
---

## 这是第三篇博客的标题

third blog 的内容 3

再次查询数据,把咱们刚刚添加的文章数据都拿下来了

既然 GraphQL 能拿到数据,说明咱们也能把它放到页面展现出来。

新建文件src/pages/blog.js,咱们作一个博客目录汇总:

import React from 'react'
import Layout from '../components/layout'
import { graphql } from 'gatsby'

const Blog = ({ data }) => {
  return (
    <Layout>
      <h1>博客目录</h1>
      <div>
        {data.allMarkdownRemark.edges.map(({ node }) => {
          return (
            <div
              key={node.id}
              style={{
                border: '1px solid #000',
                margin: '10px',
                padding: '10px',
              }}
            >
              <h2>{node.frontmatter.title}</h2>
              <div>分类{node.frontmatter.categories}</div>
              <div>标签:{node.frontmatter.tags}</div>
              <div>发布时间:{node.frontmatter.date}</div>
            </div>
          )
        })}
      </div>
    </Layout>
  )
}

export default Blog

export const query = graphql`
  query {
    allMarkdownRemark {
      edges {
        node {
          id
          frontmatter {
            tags
            title
            date
            categories
          }
        }
      }
    }
  }
`

打开http://localhost:8000/blog,博客目录就展现出来了:

但有个问题,每篇博客的信息确实能拿出来,可是咱们要连接啊,便是点击博客标题,进入博客详情页面,便是文章路径,因此接下来咱们将建立页面。

利用数据建立页面

gatsby-node.js

这个时候咱们就要创建gatsby-node.js文件了,这个配置文件里面的代码是 node 层相关的。

前面咱们说过 src/pages目录下的文件会所有渲染成路由,但若是咱们博客文章一篇篇的详情页要咱们本身建立一个 js 文件,这确定不合理了。

咱们会用到两个 API:

onCreateNode

每当建立新节点(或更新)时,Gatsby 都会调用 onCreateNode 函数。

gatsby-node.js写入代码:

exports.onCreateNode = ({ node }) => {
  console.log(node.internal.type)
}

重启服务,查看终端,你会发现打印出不少建立的节点:SitePage, SitePlugin, Site, SiteBuildMetadata, Directory, File, MarkdownRemark,咱们关注的只有MarkdownRemark,因而修改函数使其仅仅记录 MarkdownRemark 节点;咱们使用每个 md 文件的名称来做为路径,如要获取文件名称,你须要遍历一遍它的父节点 FileFile节点包含了咱们须要的文件数据。

exports.onCreateNode = ({ node, getNode }) => {
  if (node.internal.type === `MarkdownRemark`) {
    const fileNode = getNode(node.parent)
    console.log(`\n`, fileNode.relativePath)
  }
}

重启服务,查看终端,打印以下:

_posts/first-blog.md

 _posts/second-blog.md

 _posts/third-blog.md

相对路径出来,接下来咱们要建立路径,可使用gatsby-source-filesystem插件带的建立路径的函数

const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode }) => {
  if (node.internal.type === `MarkdownRemark`) {
    console.log(createFilePath({ node, getNode, basePath: `pages` }))
  }
}

重启服务,打印结果以下:

/_posts/first-blog/
/_posts/second-blog/
/_posts/third-blog/

接下来,向 API 传递一个函数createNodeField,该函数容许咱们在其余插件建立的节点里建立其余字段。

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, // 一般用 slug 一词表明路径
    })
  }
}

重启服务,打开http://localhost:8000/__graphql,就能查询到路径了

createPages

createPages 这个 API 用于添加页面。在建立页面以前,首先要有页面模板,这样建立页面就能指定所使用的模板了。

新建文件src/templates/blog-post.js

import React from 'react'
import Layout from '../components/layout'

export default () => {
  return (
    <Layout>
      <div>Hello blog post</div>
    </Layout>
  )
}

而后更改 gatsby-node.jscreatePages函数:

const path = require(`path`)

exports.createPages = async ({ graphql, 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: {
        slug: node.fields.slug,
      },
    })
  })
}

重启服务,随便输入一个路径,跳转到默认的 404 页面,就会看到自动生成三篇博客的路径了,点击任一篇,跳转的是咱们刚建立的 blog-post.js组件。

咱们要的是显示博客内容,因此咱们须要对模板文件再进行改造:

import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../components/layout'

export default ({ 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
      }
    }
  }
`

上面是动态变量查询的写法,GraphQL 的语法,能够看看 (https://graphql.org/learn/que...

完成以后,好比我点击第二篇博客,就能够正确进入页面并显示内容了

为了更完善,咱们给 blog 目录页面添加可跳转的连接,加入 slug查询字段, 增长 Link跳转,这个用法与 React 路由的 Link差很少一致,涉及不深的状况下暂且当成相同用法。

src/pages/blog.js

import React from 'react'
import Layout from '../components/layout'
import { graphql, Link } from 'gatsby'

const Blog = ({ data }) => {
  return (
    <Layout>
      <h1>博客目录</h1>
      <div>
        {data.allMarkdownRemark.edges.map(({ node }) => {
          return (
            <Link to={node.fields.slug} key={node.id}>
              <div
                style={{
                  border: '1px solid #000',
                  margin: '10px',
                  padding: '10px',
                }}
              >
                <h2>{node.frontmatter.title}</h2>
                <div>分类{node.frontmatter.categories}</div>
                <div>标签:{node.frontmatter.tags}</div>
                <div>发布时间:{node.frontmatter.date}</div>
              </div>
            </Link>
          )
        })}
      </div>
    </Layout>
  )
}

export default Blog

export const query = graphql`
  query {
    allMarkdownRemark {
      edges {
        node {
          id
          frontmatter {
            tags
            title
            date
            categories
          }
          fields {
            slug
          }
        }
      }
    }
  }
`

如今点击博客,就能跳转到对应页面了,虽然没作样式页面比较丑,但只要在src/_posts目录新建 md 文件,而后这里就能跟着自动刷新,算是一个超简易的博客了。

打包上线

中止开发服务,构建生产版本,把静态文件输出到 public 目录中

gatsby build

在本地查看生产环境版本,运行:

gatsby serve

接下来,就能够在localhost:9000访问咱们刚才作的网站了

本项目的 github 地址

至此,咱们教程就介绍到这里了。


相关文章
相关标签/搜索