iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
0

前一篇文章,我們成功的建立了環境,今天我們要來添加一些靜態資料到專案中,並用這些資料來創建一些頁面。

將資料添加到主題中

首先,我們在 Gatsby-theme-events 目錄下建立一個 data 資料夾,並在資料夾中新增一支 YAML 檔,名稱為 events.yml,裡面放一些示範用的數據。

- name: ModernWeb 2020
  location: online
  start_date: 2020-10-12
  end_date: 2020-10-16
  url: https://modernweb.tw/

- name: JSDC 2020
  location: online
  start_date: 2020-10-17
  end_date: 2020-10-17
  url: https://2020.jsdc.tw/

YAML 是一種可讀性高,用來表達資料序列化的格式。其意思表示 “Yet Another Markup Language” ( 仍是一種標記語言 )。YAML - Wiki

這時你的資料夾結構應該會如下圖所示

https://ithelp.ithome.com.tw/upload/images/20201004/20109495J0WA7VKp7H.png

而我們要讀取剛剛新增的 YAML 檔的資料,必須有幾支套件來協助我們,
分別為 gatsby-source-filesystem 與 gatsby-transformer-yaml,所以我們在終端機中輸入以下指令

yarn workspace gatsby-theme-events add gatsby-source-filesystem gatsby-transformer-yaml

安裝完後,我們要為 gatsby-theme-events 添加一些設定,所以我們需要建立一支 gatsby-config.js 檔,並在裡面匯出我們剛剛安裝的外掛,程式碼就如下面範例所示。

module.exports = {
  plugins: [
    {
      resolve: "gatsby-source-filesystem",
      options: {
        path: "data",
      },
    },
    {
      resolve: "gatsby-transformer-yaml",
      options: {
        typeName: "Event",
      },
    },
  ],
}

新增完後,我們開啟 gatsby-theme-events 工作區的開發伺服器

yarn workspace gatsby-theme-events develop

接著,我們輸入 http://localhost:8000/__graphql 來看看是否有成功讀取剛剛新增的資料,進入到畫面後,我們選取 allEvent > nodes > name 後 ( 如下圖 ),再用快捷鍵 Ctrl + Enter 來 Query 看看結果是否是我們所預期的。

https://ithelp.ithome.com.tw/upload/images/20201004/20109495asFAoKS8HA.png

這時,讀者們的畫面應該要如下圖般,撈出剛剛我們新增的資料。

https://ithelp.ithome.com.tw/upload/images/20201004/20109495NsaiZIP3eO.png

使用 onPreBootstrap 來預防錯誤

我們完成上面的步驟後,接下來,我們在 gatsby-theme-events 工作區中建立 Gatsby-node.js 檔,並在裡面新增以下程式碼

const fs = require("fs")

exports.onPreBootstrap = ({ reporter }) => {
  const contentPath = "data"

  if (!fs.existsSync(contentPath)) {
    reporter.info(`creating the ${contentPath} directory`)
    fs.mkdirSync(contentPath)
  }
}

這段程式碼我們引入了 nodeJS 的 File System,來幫助我們確認到 data 資料夾是否存在,因為我們安裝的套件 gatsby-source-filesystem 在主題啟動時會去讀取 data 資料夾,而如果它並不存在的話,會引發錯誤,所以為了預防此種情境發生,我們就需要用 onPreBootstrap API 來檢查,如果發現沒有 data 資料夾,就直接創建一個。

動態創建頁面

我們要用資料來動態的建立頁面,需要做到以下幾點

  1. 自定義類型
  2. 為我們自定義的類型建立一個解析器
  3. 查詢自定義類型並作錯誤處理

自定義類型

接下來我們會用 createTypes 來創建我們自定義的 Event 類型,並用 @dontInfer 來明確定義,讓 Gatsby 不要對這個類型做推斷,接著將 name、location、startDate、endDate、url 等自訂的欄位創建資料,並且多創立一個 slug ,我們會用它來做路由。

於是我們在 gatsby-node.js 中,新增以下這段

exports.sourceNodes = ({ actions }) => {
  actions.createTypes(`
    type Event implements Node @dontInfer {
      id: ID!
      name: String!
      location: String!
      startDate: Date! @dateformat @proxy(from: "start_date")
      endDate: Date! @dateformat @proxy(from: "end_date")
      url: String!
      slug: String!
    }
  `)
}

若對這邊概念有點模糊的讀者,可以試著閱讀 Gatsby.js - createTypes

對自定義欄位做解析

接著,我們要使用 createResolvers API 與 正規表示法 ( Regular Expression ) 來為 Slug 做一些處理,例如統一小寫、特殊符號過濾等等,經過處理後,再將處理後的值回傳並新增到我們自定義的 Event 類型的欄位中。

createResolvers 中,我們先定義根目錄為 / ,並新增一個函式來幫助我們做 slug 的解析,最後在 Event 類型中新增它 ( Slug )

exports.createResolvers = ({ createResolvers }) => {
  const basePath = "/"
  const slugify = str => {
    const slug = str
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, "-")
      .replace(/(^-|-$)+/g, "")
    return `/${basePath}/${slug}`.replace(/\/\/+/g, "/")
  }
  createResolvers({
    Event: {
      slug: {
        resolve: source => slugify(source.name),
      },
    },
  })
}

同樣的,我們將以上程式碼新增到 gatsby-node.js 中,接著再重啟開發伺服器後,我們重新 Query 看看資料是否如我們預期中的運行。

query MyQuery {
  allEvent {
    nodes {
      name
      slug
      startDate(formatString: "MMMM DD YYYY")
      endDate(formatString: "MMMM DD YYYY")
    }
  }
}

經由以上的 Query ,我們能得出以下的結果

https://ithelp.ithome.com.tw/upload/images/20201004/20109495DscvPshgbs.png

各位讀者可以看到,紅框處就是我們上面程式碼正確執行的結果,也就是我們明天動態建立頁面時,每個頁面的路由。

正規表示法常用來作字串的搜尋、替換、過濾等,是非常好用的工具,有興趣的讀者可以搜尋看看唷。正規表示法 - Wiki

今天的內容可能會對一些讀者來說比較吃力,若感覺較吃力的讀者可以先照著範例往下做,等我們的主題建置都完成後,再回頭來看看,可能會有不同的感受唷!

參考資料

Gatsby - building a Theme


上一篇
[Day 18] - 建立屬於自己的主題 ( 一 )
下一篇
[Day 20] - 建立屬於自己的主題 ( 三 )
系列文
雖然你不是木村拓哉,但它也可以讓你變很行 - Gatsby.js30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言