Gatsby精粹,面向未來的blog

緣起

我原先是使用的hexo的,這裏我們從hexo ==> Gatsby的原因如下:

  1. 都是靜態頁面框架,SEO,部署等,靜態頁面的優勢
  2. 使用現代化框架開發 —— React ,可以不斷的迭代
  3. 社區資源成熟,目前Gatsby的插件已經非常成熟 鏈接
  4. 性能強悍,相比其他的靜態頁面框架,Gatsby的性能比較出衆
  5. GraphQL 來請求數據, 靈活 優雅,待會介紹

install

安裝全局 gastby 命令行,通過這個初始化腳手架。
yarn global add gastby-cli

script

  • develop
  • build
  • serve

結構-範式

├── content
├── gatsby-browser.js
├── gatsby-config.js // 主要配置文件
├── gatsby-node.js // 視圖層配置
├── package.json
├── public
├── src
    ├── components // 組件
    ├── pages // 頁面文件
    ├── templates // 模版文件

Gatsby 採用約定式路由,page文件夾要注意,全都是採用小寫命名,例如:

about.js ==> http://localhost/about/

另外在生產頁面的時候 createPage 可以手動設置路由,但是還是建議遵守約定

Data

數據層,Gatsby 使用的是Graphql,文檔

Gatsby 是自帶 圖像調試界面的

http://localhost:8000/___graphql

___graphql

🔥蕾絲 這樣的一個界面,稍後講解他的簡單使用

⚠️注意:可以通過右邊的Query
查詢參數,方便的一批~

在Gatsby中的數據分爲2種

  1. 文件數據
  2. 配置數據

通過插件實現

gatsby-source-filesystem讀本地文件列表,

query {
   allFile {
      edges {
        node {
          relativePath
          prettySize
          extension
          birthTime(fromNow: true)
        }
      }
    }

通過 gatsby-transformer-remark 讀 markdown 文件內容

const result = await graphql(
    `
      {
        allMarkdownRemark(
          sort: { fields: [frontmatter___date], order: DESC }
          limit: 1000
        ) {
          edges {
            node {
              fields {
                slug
              }
              frontmatter {
                date(formatString: "YYYY 年 MM 月 DD 日")
                title
                tags
              }
            }
          }
        }
      }
    `
  )

應該注意到了吧 我上面的 graphql 有稍許不同,我在獲取markdown的時候對他進行了排序,根據時間date 的倒序排序,
還吧時間格式化了以下,它能做的遠不止這些 還包括 sortfilterskiplimit 等參數對數據做處理. 詳情可看文檔

Gatsby 中的數據都是通過 Promise 來實現的, 例如要拿到上面的 markdown 文件內容

可以 通過 await 或者 直接 .then (res => { ... })

—— 下面是獲取配置數據 也就是 gatsby-config.js 的數據

query {
    site {
      siteMetadata {
        title
      }
    }

我的配置文件結構如👇

    module.exports = {
  siteMetadata: {
    title: `Ruoduan' Blog`,
    author: `Ruoduan`,
    description: `我的介紹...`,
    siteUrl: `https://github.com/Chad97`,
    keywords: 'react, 前端, python, js, ',
    },
  },
  plugins: [
    安裝的插件 配置
    ......
    
  ],
}

一目瞭然了吧 ~~

黑魔法

在Gatsby page 頁面中想要獲取數據只需要通過:👇

export const pageQuery = graphql`
  query {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC },
      ) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            date(formatString: "YYYY 年 MM 月 DD 日")
            title
            tags
            categories
          }
        }
      }
    }
  }
`

只需要 export 導出一個graphql 獲取到到數據就會就會掛載到當前頁面到 props 上,是不是很神奇 🚀🚀🚀

useStaticQuery

除了上面的方式 我們想在組件中拿到一些數據該怎麼辦呢?

Gatsby 有一種非常優雅的方式 ———— useStaticQuery

useStaticQuery 和 上面方式不同 這裏拿到的數據只存在於當前組件的 runtime,

例如下面一個組件 我要拿到所有文章標題

import { useStaticQuery, graphql } from "gatsby"
const data = useStaticQuery(graphql`
    query titleQuery {
      allMarkdownRemark {
        edges {
          node {
            frontmatter {
              title
            }
          }
        }
      }
    }
  `)
  
  const [titleData, setTitle] = useState(data.allMarkdownRemark.edges)
  useStaticQuery 必須放在組件開頭 ,也就是 數據變量之前

是不是有異曲同工之妙啊~ 👏 👏 👏

createPages

我們在面對一些重複的頁面比如 blog 文章詳情頁面 ,只是數據不一樣其他的一樣,
我們不可能每個markdown都創建一個 page 頁面,這時候 我們就需要使用createPages 創建頁面

createPage({
      path: post.node.fields.slug,
      component: blogPost,
      context: {
        slug: post.node.fields.slug,
        previous,
        next,
      },

三個參數:

  • path: 路由地址,我這裏使用的是文章標題

  • component: 模版

  • context: 傳遞到該頁面的數據

我這裏創建頁面是 利用 上面 獲取所有 markdown 的數據來創建文章詳情頁

    const result = await graphql(
    `
      {
        allMarkdownRemark(
          ...... 如上
      }
    `
  )
  // 獲取md數據
const posts = result.data.allMarkdownRemark.edges

const blogPost = path.resolve(`./src/templates/blog-post.js`)
  // 創建詳情頁
  posts.forEach((post, index) => {
    const previous = index === posts.length - 1 ? null : posts[index + 1].node
    const next = index === 0 ? null : posts[index - 1].node

    createPage({
      path: post.node.fields.slug,
      component: blogPost, 
      context: {
        slug: post.node.fields.slug,
        previous,
        next,
      },
    })
  })

Develop Tools

  • babel

.babelrc,然後 gatsby 安裝 babel-preset-gatsby,和我們平時沒有太大差別,只是安裝的包不同罷了

  • webpack

webpack 想要自定義配置

gatsby-node.js

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === "build-html") {
    actions.setWebpackConfig({
      module: {
        rules: [
          ......
        ],
      },
    })
  }
}

stage 有分爲:

  • develop
  • develop-html
  • build-javascript
  • build-html

Other

PWA 支持

yarn add gatsby-plugin-manifest gatsby-plugin-offline

plugins: [
  //...
  {
    resolve: `gatsby-plugin-manifest`,
    options: {
      name: `Destiny'Note`,
      short_name: `Destiny`,
      start_url: `/`,
      background_color: `#6b37bf`,
      theme_color: `#6b37bf`,
      display: `standalone`,
      icon: `src/images/icon.png`,
    },
  },
  `gatsby-plugin-offline` // 這個插件必須在 manifest 後面
]

proxy

兩種方式,

  1. gatsby-config.js 裏配 proxy,和 umi 或 webpack-dev-server 的類似
  2. gatsby-node.js 裏配 developMiddleware,手寫中間件

SEO

yarn add gatsby-plugin-react-helmet react-helmet

{
  siteMetadata: {
    // 這三個屬性必須要有
    title: `Destiny'Note`,
    author: `destiny`,
    description: `my own blog`,
    keywords: `react, graphql, gatsby`
  },
  plugins: [
    //...
    `gatsby-plugin-react-helmet`
  ]
}

在 src/components 下增加 seo.js 文件:

/**
 * SEO component that queries for data with
 *  Gatsby's useStaticQuery React hook
 *
 * See: https://www.gatsbyjs.org/docs/use-static-query/
 */

import React from "react"
import PropTypes from "prop-types"
import Helmet from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

function SEO({ description, lang, meta, title, tags }) {
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
            author
            keywords
          }
        }
      }
    `
  )

  const metaDescription = description || site.siteMetadata.description

  return (
    <Helmet
      htmlAttributes={{
        lang,
      }}
      title={title}
      tags={tags}
      titleTemplate={`%s | ${site.siteMetadata.title}`}
      meta={[
        {
          name: `description`,
          content: metaDescription,
        },
        {
          property: `og:title`,
          content: title,
        },
        {
          property: `og:description`,
          content: metaDescription,
        },
        {
          property: `og:type`,
          content: `website`,
        },
        {
          name: `twitter:card`,
          content: `summary`,
        },
        {
          name: `twitter:creator`,
          content: site.siteMetadata.author,
        },
        {
          name: `twitter:title`,
          content: title,
        },
        {
          name: `twitter:tags`,
          content: tags,
        },
        {
          name: `twitter:description`,
          content: metaDescription,
        },
      ].concat(meta)}
    />
  )
}

SEO.defaultProps = {
  lang: `zh-CN`,
  meta: [],
  description: `若端的技術博客`,
}

SEO.propTypes = {
  description: PropTypes.string,
  lang: PropTypes.string,
  meta: PropTypes.arrayOf(PropTypes.object),
  title: PropTypes.string.isRequired,
}

export default SEO

以上是我的示例🌰

然後把 seo 組件添加到各個 組件||模版 or 頁面中去

SEO-例子

每個頁面的 head meta title 的優化數據就是 傳入的數據

個性化 設置吧

還有一些 例如 typescript 支持什麼的 plugins哪裏搜索安裝就好了

我是用的一個 npm 包中 使用了 全局對象 如 :windows document 等。

gatsby develop 的時候是沒事的

gatsby build 就會報錯 !

Import breaks Gatsby Build : WebpackError: ReferenceError: Element is not defined

stack-overflow

是因爲 在打包的時候 runtime 並沒有 page 對象,解決這個問題有2中方案

  1. 在使用的地方 判斷當前 有沒有 document 對象,沒有的話就 null 不執行
typeof window !== 'undefined' &&  windows.open()

那如果是 我的npm 包中使用了呢? 總不能 改源碼吧,我就是遇到的這種情況,遇到這種情況就要 配置 webpack 忽略

// 忽略全局對象
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === "build-html") {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /xxx-xxxx/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

有些情況下 我們在 yarn add xxx 的時候會報錯

yarn add xxxx error “pngquant pre-build test failed”

  • Every time I install the package, I get the error pngquant pre-build test failed, macOS cannot install “libpng-dev”, only “libpng”

安裝 libpng 就好了 issues

部署

gatsby build

這裏就不多做 敘述了,不管是 GitHub Pages / Netlify … , 往上扔就可以了

這裏鏈一個 我的 部署方式: GitHub Hooks + nodejs 實現 自動化部署:https://juejin.im/post/5e19d47e6fb9a0300c54ce09

About

我的Gatsby Blog 地址 : http://new.ruocuan.cn

  • 求star ⭐️ 🙏🙏🙏

倉庫地址: https://github.com/Chad97/my-Gatsby-Blog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章