用GatsbyJs快速开发博客站

4,018 阅读8分钟

这段时间业务线很忙,刚刚清静下来,很少有时间静下心深入研究一些新东西,想来想去,就使用一个web框架gatsby.js吧,最近可以看看Dan的个人博客站,也是用gatsby做的,大家也可以fork他的仓库改改,github.com/gaearon/ove…

基本介绍

近年来,gatsby都比较火,特别是在国外,已经有44.5k的星数,由于它生成静态网站有很多优秀的特性,这让它拥有了非常高的人气。

作为一个web框架的优势:

  1. 对于markdown文件有着近乎完美的支持
  2. 速度极快,体现在加载/刷新的方方面面,几乎用上了静态站所有的优化手段
  3. 主题不少
  4. 折腾余地大
  5. 良好支持SEO

而我们选择它,是想做一个自己的博客站,而gatsby作为框架有很高的灵活度: 它可以很简单,配好md解析,加个主题就像模像样。同时还可以深入折腾,因为他本身是SPA,动静结合不冲突,基于react/graphQL/webpack等我们熟悉的技术栈和开发模式,并且可以添加ts支持/SSR支持等,能持续拿来练手~

最后要达到的目标:开发完成后,后续只需要把自己新写的MD文档放入对应文件夹中,提交到github即可更新博客站!

初始环境配置

第一步,下一个全局cli

npm install -g gatsby-cli

可以用这条命令查看一下npm安装的全局包是否存在gatsby-cli

npm list --depth=0 -global

查看一下可用的命令 gatsby --help

直接用官方配置拉取项目

gatsby new [项目名] https://github.com/gatsbyjs/gatsby-starter-hello-world

cd [项目名]

gatsby develop

这个时候项目就已经拉下来,并启动了一个最简单的静态站

这时候可以打开 http://localhost:8000 在浏览器窗口查看界面

同时再打开 http://localhost:8000/___graphql 一个增强版的graphiql(帮助你查类型发graphQL) 如下图⤵️

目录结构说明

|-- /public  // 打包后生产出的静态网站文件
|-- /content  // 也可以叫其他名字,一般放入MD等文件的地方
|-- /src
    |-- /pages      // 页面文件(这里面的文件都会被作为路由存在)
    |-- /templates  // 模板文件
|-- /static      
|-- /types       // 存放ts类型定义
|-- gatsby-config.js  //最重要的文件,里面需要做很多配置
|-- gatsby-node.js  //
|-- gatsby-ssr.js // ssr的专用文件,可以不建立
|-- gatsby-browser.js // 浏览器api的相关调用,可以不建立

pages文件夹下是约定路由的,所有的文件都会被框架打包时根据相对路径和文件名字解析成路由, 另外一种创建路由的方式就是gatsby-node文件中利用createPages这个API,一会会讲到

ts支持(可跳过这段)

如果要增加ts支持(这里练手用) 输入yarn add typescript gatsby-plugin-ts 记得在根目录配置一下 tsconfig.json 如下⤵️

这样你在graphiQl中的每一次查询,都会智能生成其ts类型

添加MD文档

下一步我们可以添加MD文档

我习惯在content文件夹中新建一个blog文件夹,里面放入所有的MD文档,格式如下

---
path: "/blog/firstblog"
date: "2020-07-02"
title: "第一篇博客"
tags: ["瞎聊"]
---

# 我的第一篇博客

我的第一篇博客。。。。

每篇MD文档都要在前面加上三横线包裹的属性识别块,里面的属性自定义,一般我会写上上面这几个属性,特别是path,我会在后面把它手动作为真实路由(如果有不喜欢手动声明路径的也可以通过添加节点映射路径)

PS:书写MD文档一定要规范,代码块里面每一行前都要有4个缩进

插件配置

插件统一在顶层目录中的gatsby-config.js文件里面的plugin中配置

安装 gatsby-source-filesystem // 可检索提取项目中的Md和YML/YMAL等文件,注意要配置其path包含放MD文件的位置

安装 gatsby-transformer-remark // 可对提取的MD类文件解析成json等格式的数据源

上面两个是对MD处理的必备插件⤴️

(可选,尽量安装)安装gatsby-plugin-catch-links // 使浏览器在本地页面导航时不会刷新整个页面,跟SPA一样

(可选,尽量安装)安装gatsby-remark-images // 处理MD等引用的图片的,可能需要gatsby-plugin-sharp支持

gatsby-config.js文件参考⤵️

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-ts`,
      options: {
        tsLoader: {
          logLevel: 'warn',
        },
        forkTsCheckerPlugin: {
          eslint: true,
        },
        fileName: `types/graphql-types.ts`,
        codegen: true,
        codegenDelay: 250,
      }
    },
    'gatsby-plugin-catch-links',
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content/blog`, //这个地址要指到MD文件的地址,这样才能被graphql服务识别
        name: `blog`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content/assets`,
        name: `assets`,
      },
    },
    'gatsby-plugin-sharp', // 深度压缩、裁切image的必备库(不特别设置gatsby-remark-images就没用)
    {
      resolve: 'gatsby-transformer-remark',
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              maxWidth: 590,
              linkImagesToOriginal: false,
            },
          },
          `gatsby-remark-prismjs`, //这个稍后会说到
        ]
      }
    },
  ],
}

解析MD文件

添加MD的模板文件:我们在src下的templates文件夹新建一个blog.tsx文件

export interface ITemplate {
  data: { markdownRemark: MarkdownRemark};
}

import React from "react";
import { graphql } from "gatsby";
import "./blog.css";
import { MarkdownRemark } from "../../types/graphql-types";
export default function Template({
  data, // this prop will be injected by the GraphQL query below.
}: ITemplate) {
  const { markdownRemark } = data // data.markdownRemark holds your post data
  const { frontmatter, html } = markdownRemark
  return (
    <div className="blog-post-container" style={{ margin: `3rem auto`, maxWidth: 650, padding: `0 1rem` }} >
      <div className="blog-post" >
        <h1>{frontmatter && frontmatter.title}</h1>
        <h2>{frontmatter && frontmatter.date}</h2>
        <div
          className="blog-post-content"
          dangerouslySetInnerHTML={{ __html: html||"" }}
        />
      </div>
    </div>
  )
}

同时在gatsby-node文件中利用createPages加上页面解析

exports.createPages = async ({ actions, graphql, reporter }) => {
  const { createPage } = actions;
  const blogPostTemplate = require.resolve(`./src/templates/blog.tsx`);
  const result = await graphql(`
    {
      allMarkdownRemark {
        edges {
          node {
            frontmatter {
              path
            }
          }
        }
      }
    }
  `)

  // Handle errors
  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
    return
  }

  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.frontmatter.path, //这是md文档中三横线包裹的path属性
      component: blogPostTemplate,
      context: {
        // additional data can be passed via context
      },
    })
  })
}

添加页面级请求

上面的模板文件已经配置的比较完善了,但是还缺一项,他的数据来源!

在最开始的http://localhost:8000/___graphql中我们可以选择页面级请求pageQuery,参照示范代码书写,blog.tsx模板文件就是页面级的,我们可以接着导出一个query作为数据源。

接上,同一个模板文件下(blog.tsx)除了默认导出页面级组件 还要导出一个常量query,值设置为带有graphql标签的模板,并在两个反引号之间进行查询:

markdownRemark是查询单个MD文件的字段,传入path变量后,用eq: $path来确定是哪个文件

export const query = graphql`
  query($path: String!) {
    markdownRemark(frontmatter: { path: { eq: $path } }) { 
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        path
        title
      }
    }
  }
`

PS:常量的名称不叫query也行,因为Gatsby会graphql从文件中查找导出的graphql字符串,而不是特定的变量,但要注意的是每个文件只能有一个查询。

MD代码块高亮

代码块高亮我们可以配置PrismJS

www.gatsbyjs.org/packages/ga… 上面讲的比较详细,简单说gatsby-transformer-remark插件下配置gatsby-remark-prismjs,最后在gatsby-browser.js文件下引入css

require("prismjs/themes/prism-solarizedlight.css")

PS:prism本身提供多种代码高亮主题,可以换不同的css来实现

md其他的样式自定义的话我们可以写一个css文件来配置,我们查看它的属性节点中的classname对应写出css即可,不做详解

列表首页

到这一步,各路径下就有对应展示出的MD文档了,可以针对各个节点的classname书写一些自定义css变的更好看,目前还缺的是首页

我们一般是把首页设置成博客列表,有各个博客的标题和摘要,这里随便写一写

在Pages文件夹下新建index.tsx文件

interface IBlogIndexProps {
    data: { allMarkdownRemark: MarkdownRemarkConnection};
    // location: Location;
}

import React from "react"
import { graphql, Link } from "gatsby"
import { MarkdownRemark, MarkdownRemarkConnection } from "../../types/graphql-types"

const BlogIndex: React.FC<IBlogIndexProps> = ({ data }) => {
    return (
            <div>
                <h1> Let's Do Some Amazing Things </h1>
                <h4>{data.allMarkdownRemark.totalCount} Posts</h4>

                {data.allMarkdownRemark.edges.map(({ node }: { node: MarkdownRemark}) => (
                    <div key={node.id}>
                        <h3 style={{marginBottom: 5}}>
                            <Link to={node.frontmatter && node.frontmatter.path || ''}>{node.frontmatter && node.frontmatter.title}{" "}</Link>
                            <span style={{color: "#bbb"}}>
                                — {node.frontmatter && node.frontmatter.date}
                            </span>
                        </h3>
                        <p>{node.excerpt}</p>
                    </div>
                ))}
            </div>
    )
}

export const query = graphql`
    query {
      allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
        totalCount
        edges {
        node {
            id
            frontmatter {
                title
                date(formatString: "DD MMMM, YYYY")
                path
            }
            excerpt
        }
        }
    }
  }
`

export default BlogIndex

主题使用

主题使用可以有两种方式,一种是直接拉github别人的主题作为项目(其实就是直接白嫖别人的模板),另一种作为插件引入,可配置它生效的目录范围,比如一个网站有几个模块,某个路由下受该主题影响,同理可配置多主题。

(主题模块本来写了很多,想想还是删掉了,一切尽在自己探索)

部署上线

gatsby云可以直接连接自己的github,做可持续化的cicd

www.gatsbyjs.com/dashboard/s…

在这里用自己的github登录,网站可以识别自己的private私有库,接下来是傻瓜式操作,指定自己的gatsby仓库,自动构建即可。

(自己瞎玩的项目最好不要提交yarn.lock文件,之前用公司内网加载了一些包被yarn.lock记录了地址,部署的时候没找到...)

设置完以后,在preview里面会有固定的线上网址,以后只要在github提交了代码,几分钟后这个网站内容就会自动被更新

这是项目的线上地址 gatsbymguy.gtsb.io/

扩展

到目前为止,一个简陋的博客站就成了,以后写了博客直接把MD文件放入文件夹提交github即可。

但其实gatsby还有许许多多的功能和高级API值得了解,下面是几个引子

gatsby-node.js文件中的createResolvers 和 onCreateNode 两个高级API可以了解一下

gatsby-config.js文件中Mapping node types(映射节点)也很有意思,可以去尝试了解

gatsby-node.js文件中onCreateWebpackConfig这个API可以调度webpack打包过程,可以去看一下

还有很多繁琐的建站工作,如添加404页面,SEO,全局layout等等也比较简单,这里就不一一展开了

后续计划

打算初步扩展的功能有各种查询、在线编辑添加、开放评论等一些有意思的功能

这段时间抽了零碎时间摸索了一下这个框架,还是挺有意思的

一些资料

gatsby的官网 www.gatsbyjs.org/

中文站 www.gatsbyjs.cn/

推荐一个主题 github.com/maxpou/gats…

如果有不足之处,还请在评论区指正