# 用 Gatsby.js 透過 GraphQL 讀取 Markdown 架設靜態網站 ###### tags: `Gatsby` #### Gatsby 主要的技術為 React Stack、PWA、GraphQL,是一個靜態網頁產生器,可以類比為 WordPress,但資源度來說還落差很大。但 Gatsby 優點為使用的技術較新,透過 PWA 可以實作離線瀏覽,以及讓網頁速度非常快,並因為是靜態網站,可以直接在開源網站 (GITHUB) 架站。 ### 1.安裝 Gatsby.js cli ```shell= npm install --global gatsby-cli ``` ##### 下載版型,這邊使用預設版型,要更多可參考官網[連結](https://www.gatsbyjs.com/starters/?v=2) ```shell= gatsby new testing https://github.com/gatsbyjs/gatsby-starter-default ``` ##### 啟動方式 ```shell= gatsby develop ``` ### 2.安裝讀取 Markdown 套件 ```shell= npm install --save gatsby-source-filesystem npm install --save gatsby-transformer-remark ``` ##### 將安裝的套件加入 gatsby-config.js,此檔案專門用來放 plugins 與一些站台的 metaData ```javascript= module.exports = { siteMetadata: { title: `Gatsby Default Starter`, description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`, author: `@gatsbyjs`, }, plugins: [ `gatsby-plugin-react-helmet`, { resolve: `gatsby-source-filesystem`, options: { name: `images`, path: `${__dirname}/src/images`, }, }, `gatsby-transformer-sharp`, `gatsby-plugin-sharp`, { resolve: `gatsby-plugin-manifest`, options: { name: `gatsby-starter-default`, short_name: `starter`, start_url: `/`, background_color: `#663399`, theme_color: `#663399`, display: `minimal-ui`, icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site. }, }, { resolve: 'gatsby-source-filesystem', options: { path: `${__dirname}/src/pages`, name: 'pages', } }, `gatsby-transformer-remark` ], } ``` ### 3.建立 Markdown 與模板 #### 在 src>pages 內建立 markdown 資料夾,在此篇建立兩個不同 markdown 頁面,以及在 src>pages 內建立 templates 資料夾,以及兩個 js 檔案。在兩者的關係中,模板可以把它比擬成一個 html 檔案,markdown 則是一個資料庫。 * ##### markdown > index.md ```javascript= --- path: '/markdown' //連結位置 template: 'src/templates/index.js' //讀取的模板位置 title: 'My page' --- ``` * ##### markdown > index2.md ```javascript= --- path: '/markdown/index2' template: 'src/templates/index2.js' title: 'My test page2' date: '2020/12/7' --- ``` * ##### templates > index.js ```javascript= import React from 'react'; import { graphql } from "gatsby" import Helmet from 'react-helmet'; import SEO from "../components/seo" //html 部分寫在這 export default function Template({data}) { const {markdownRemark: page} = data; return ( <> <SEO title={page.frontmatter.title} /> <div> <h1>{page.frontmatter.title}</h1> </div> </> ) } export const pageQuery = graphql` //依據我的路徑,去拿取不同 markdown 的資料 query($path: String!) { markdownRemark(frontmatter: { path: { eq: $path } }) { html frontmatter { path title } } } ` ``` * ##### templates > index2.js ```javascript= import React from 'react'; import { graphql } from "gatsby" import Helmet from 'react-helmet'; import SEO from "../components/seo" export default function Template({data}) { const {markdownRemark: page} = data; return ( <> <SEO title={page.frontmatter.title} /> <div> <h1>{page.frontmatter.title}</h1> <h1>{page.frontmatter.date}</h1> </div> </> ) } export const pageQuery = graphql` query($path: String!) { markdownRemark(frontmatter: { path: { eq: $path } }) { html frontmatter { path title date } } } ` ``` ### 4.自動在首頁生成 Markdown 連結 #### 尋找 gatsby-node.js 這隻檔案,若沒有可以自行創建,但名稱必須相同,這隻用來撰寫創建頁面,將各頁面的初始化都先創建。 * ##### gatsby-node.js ```javascript= const path = require('path'); exports.createPages = ({boundActionCreators, graphql}) => { const {createPage} = boundActionCreators; //這邊只需取得路徑與模板做初始化動作 return graphql(`{ allMarkdownRemark { edges { node { html id frontmatter { path template } } } } }`) .then(res => { if (res.errors) { return Promise.reject(res.errors); } //將所有Markdown頁面都創建 res.data.allMarkdownRemark.edges.forEach(({node}) => { createPage({ path: node.frontmatter.path, component: path.resolve(node.frontmatter.template) }) }) }) } ``` #### 到首頁 (src>pages>index.js) 撰寫入口連結 ```javascript= import React from "react" import { Link } from "gatsby" import Layout from "../components/layout" import Image from "../components/image" import SEO from "../components/seo" const IndexPage = ({data}) => ( <Layout> <SEO title="Home" /> <h1>Hi people</h1> <p>Welcome to your new Gatsby site.</p> <p>Now go build something great.</p> <h2>Index</h2> {data.allMarkdownRemark.edges.map(page => ( <Link key={page.node.id} to={page.node.frontmatter.path}> {page.node.frontmatter.title} </Link> ))} </Layout> ) export const pageQuery = graphql` query IndexQuery { allMarkdownRemark(limit: 10) { edges { node { id frontmatter { title path } } } } } ` export default IndexPage ``` ### 5.優化:將專案內原只能讀取單一圖片改成動態讀取圖片 #### 調整 components > image.js 的 graphQL 寫法,將所有圖片都載出,再做filter。 * ##### image.js ```javascript= import React from "react" import { useStaticQuery, graphql } from "gatsby" import Img from "gatsby-image" const Image = ({fileName}) => { const data = useStaticQuery(graphql` query { //sourceInstanceName是資料夾名稱 allFile(filter: {extension: {regex: "/(jpg)|(jpeg)|(png)/"}, sourceInstanceName: {eq: "images"}}) { edges { node { childImageSharp { fluid(maxWidth: 300, quality: 50) { originalName ...GatsbyImageSharpFluid } } } } } } `) let image=data.allFile.edges.filter(x=>x.node.childImageSharp.fluid.originalName===fileName).map(x=>x.node.childImageSharp.fluid) if (!image?.[0]) { return <div>Picture not found</div> } return <Img fluid={image?.[0]} /> } export default Image ``` #### 讀取圖片範例 ```javascript= <Image fileName="gatsby-astronaut.png"/> ```