前言
- 又研究了下这玩意,终于大概理解咋回事了。
- gatsby它自带的graphql会先收集项目的一些信息,然后做成graphql服务,包括各种文件之类,比如用插件搞得markdown或者图片文件,都是这种模式,被收集到gatsby的graphql架构中。
- 在编写页面时,可以通过它提供的组件或者api查询graphql中存放的数据,从而渲染出来。
- 在gatsby-node中可以做一些node上的动态渲染操作。
- 在最后build时,graphql架构会转换成静态数据,然后生成静态网站。如果需要ssr的话,也可以同构ssr出来,这方面没去研究。
- 在我查阅资料研究时,还发现了个吊炸天的cms serverless网站,真的太牛b了,gatsby结合这种cms网站搭建起来速度会快很多。那个网站叫contentful,配合gatsby插件,只要写个壳甚至连壳都不用写就可以轻松造网站了。
- 安装不说了,直接看上一篇,这篇说基本使用。
Pages
- 首先,这里路由和next以及umi类似,都是page下的文件是一个路由,可以新在pages下新增2个页面,一个index.tsx,一个page2.tsx,然后访问localhost:8000以及localhost:8000/page2,就是page下的page2.tsx可以看见页面。
- 然后就是跳转,gatsby提供了link,我看老版本gatsby跳转还要装个插件
import { Link } from "gatsby"
...
<Link to="/">page1</Link>
- 这样就可以完成跳转了。使用代码跳转借助它提供的navigate
<button onClick={() => navigate("/")}>page1</button>
图片功能
- 图片导入有3种,一种直接放到static文件夹下,一种直接进行引入,一种借助于插件进行优化,前2种没啥说的,直接说最后一种。
- 图片我们借助于插件,插件再上一篇有。我们配置的gatsby-source-filesystem插件的图片目录为src下images,首先找个图片放到该目录下,然后试着渲染出来。
- 我找了个test.jpg放置目录下。
- 使用gatsby的graphql api进行查找:
const data = useStaticQuery(graphql`
query {
file(relativePath: { eq: "test.jpg" }) {
childImageSharp {
fluid {
base64
aspectRatio
src
srcSet
sizes
}
}
}
}
`)
{
"data": {
"file": {
"childImageSharp": {
"fluid": {
"base64": "data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEEAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAHVyMrpkAF//8QAGxAAAQQDAAAAAAAAAAAAAAAAAQADEUECEjH/2gAIAQEAAQUCcMAZwtpT/ar/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPwGH/8QAHBAAAgAHAAAAAAAAAAAAAAAAAAECAxESMXKR/9oACAEBAAY/Ai6LBVM4TdhH/8QAHBAAAgIDAQEAAAAAAAAAAAAAAREAIUFhcTHw/9oACAEBAAE/Ib80TfIZalCDzFM0TqfHk9fimoyEHE//2gAMAwEAAgADAAAAECcv/8QAFhEAAwAAAAAAAAAAAAAAAAAAAAER/9oACAEDAQE/EE6Q/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAECAQE/EE2N/8QAHRABAAICAgMAAAAAAAAAAAAAAQARITFBcVFh8P/aAAgBAQABPxC+cyXCqwfeI+IAlstrwdJBJRNdJveVD7IA2XO7aiRQK6Z//9k=",
"aspectRatio": 2,
"src": "/static/2a7e115bd768aad419526e39bd9f6c75/3b31f/test.jpg",
"srcSet": "/static/2a7e115bd768aad419526e39bd9f6c75/f836f/test.jpg 200w,\n/static/2a7e115bd768aad419526e39bd9f6c75/3b31f/test.jpg 370w",
"sizes": "(max-width: 370px) 100vw, 370px"
}
}
}
},
"extensions": {}
}
import Img from "gatsby-image" // to take image data and render it
<Img
fluid={data.file.childImageSharp.fluid}
alt=""
/>
- 可以发现图片已经渲染出来了,而且还有非常牛b的预渲染模糊以及延迟加载,比直接甩静态文件强多了。怪不得我看国外那些medium等网站的图片延迟渲染感觉都用的一个东西。估计就是gatsby搞的或者用Cloudinary云端服务,也是gatsby网站上推荐使用的。
MARKDOWN
- 处理markdown文件需要安装gatsby-transformer-remark插件。还有个mdx插件,有需要自己研究,本篇不写了。
- 这个markdown的处理模式是这样:
- 先造个template做模板,然后md文件上标注meta信息,最后通过gatsby-node完成转换。
- 首先安装完毕后再插件里把这玩意加上。
- 同时还需要配置filesystem存放markdown的文件夹:
{
resolve: "gatsby-source-filesystem",
options: {
name: "content",
path: `${__dirname}/src/docs`,
},
},
---
title: yehuozhili
date: 2020-09-08
path: /markdownpage
---
This is my first Gatsby post written in Markdown!
## h1
hello
- this is test
- 前面这个是固定语法,然后制作template:
- 在src下建立templates,然后做个markdown的壳:
import React from "react"
import { graphql } from "gatsby"
export default function Template({ data }: { data: any }) {
const { markdownRemark } = data // data.markdownRemark holds your post data
const { frontmatter, html } = markdownRemark
return (
<div className="blog-post">
<h1>{frontmatter.title}</h1>
<h2>{frontmatter.date}</h2>
<div
className="blog-post-content"
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
)
}
export const pageQuery = graphql`
query($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
date(formatString: "MMMM DD, YYYY")
path
title
}
}
}
`
- 其中pageQuery会导出给node模块使用,拿到的md元数据直接在template壳里渲染。
- 下面编写node部分:
const path = require(`path`)
exports.createPages = async ({ actions, graphql }) => {
const { createPage } = actions
const result = await graphql(`
{
allMarkdownRemark {
edges {
node {
frontmatter {
path
}
}
}
}
}
`)
if (result.errors) {
console.error(result.errors)
}
//这个查询为了拿到文件系统中提供的所有markdown匹配路径,然后通过createPage传递path渲染模板
result.data.allMarkdownRemark.edges.forEach(({ node }) => {
createPage({
path: node.frontmatter.path,
component: path.resolve(`src/templates/index.tsx`),
})
})
}
- 然后去访问http://localhost:8000/markdownpage
- 可以看见Markdown文件已经完美渲染了。
- 下面看一下markdown怎么渲染图片。一般那种src直接写地址就不说了,渲染图片分为模板渲染和markdown内部渲染。
- 模板渲染需要markdown上添加字段:
---
title: yehuozhili
date: 2020-09-08
path: /markdownpage
featuredImage: ../images/test.jpg
---
import React from "react"
import { graphql } from "gatsby"
import Img from "gatsby-image" // to take image data and render it
export default function Template({ data }: { data: any }) {
const { markdownRemark } = data // data.markdownRemark holds your post data
const { frontmatter, html } = markdownRemark
let featuredImgFluid = frontmatter.featuredImage.childImageSharp.fluid
return (
<div className="blog-post">
<h1>{frontmatter.title}</h1>
<h2>{frontmatter.date}</h2>
<Img fluid={featuredImgFluid} />
<div
className="blog-post-content"
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
)
}
export const pageQuery = graphql`
query($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
date(formatString: "MMMM DD, YYYY")
path
title
featuredImage {
childImageSharp {
fluid(maxWidth: 800) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
`
- 这样就渲染出来了。这个适合每个markdown搞个背景图片什么的。
- 下面看一下行内如何渲染,行内需要安装gatsby-remark-images,然后配置插件。
- 需要配置为transformer的子插件:
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 800,
},
},
],
},
},
- 在markdown内,即可使用正常的markdown引入图片方式引入资源:
![YEHUOZHILItest](../images/test.jpg)
404页面
- 只要pages下搞个404.tsx就可以作为404页面。
- 默认情况下,开发模式会用它的404代替你的自定义404,不过可以上面有个按钮可以点击预览你的404,打包后就是以你的404为准。
Layout
- 基本上数据都打通了,其实只要我们搭个壳就行了,gatsby有个好用的插件叫gatsby-plugin-layout,这玩意相当于给匹配到路由的组件外套了层。
- 写在layout的组件会在满足条件时总是显示。
- layouts index.tsx:
import React, { PropsWithChildren } from "react"
function App(props: PropsWithChildren<{}>) {
console.log(props)
return (
<div>
layout
{props.children}
</div>
)
}
export default (props: PropsWithChildren<{}>) => <App {...props}></App>
- 可以访问不同页面看一下,每个页面都会显示这个。
- 对于不同路由显示不同的壳,可以在props中进行判断,props中可以拿到路由信息,甚至可以使用gatsby-node来控制layout的context。
代码