这段时间业务线很忙,刚刚清静下来,很少有时间静下心深入研究一些新东西,想来想去,就使用一个web框架gatsby.js吧,最近可以看看Dan的个人博客站,也是用gatsby做的,大家也可以fork他的仓库改改,github.com/gaearon/ove…
基本介绍
近年来,gatsby都比较火,特别是在国外,已经有44.5k的星数,由于它生成静态网站有很多优秀的特性,这让它拥有了非常高的人气。
作为一个web框架的优势:
- 对于markdown文件有着近乎完美的支持
- 速度极快,体现在加载/刷新的方方面面,几乎用上了静态站所有的优化手段
- 主题不少
- 折腾余地大
- 良好支持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
},
})
})
}
添加页面级请求
上面的模板文件已经配置的比较完善了,但是还缺一项,他的数据来源!
接上,同一个模板文件下(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
在这里用自己的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…
如果有不足之处,还请在评论区指正