All Articles

Gatsby Notes

1. Wordpress -> Jekyll -> Gatsby

开博也不算特别早,11年开始的,正好10年,当时基本上没什么选择:Godaddy + VPS + Wordpress。后来github搞出了免费的page,加上jekyll提供了不错的静态化工具,也就顺理成章换成了Jekyll + Github Page。第一次更换还算比较简单,Wordpress的旧post全部转换成静态html,所有资源都是内嵌的,然后放到jekyll的一个文件夹里就完事了,然后后续使用jekyll来编译md文件成静态html,后续的post也能便捷接续上。

断断续续也写了点关于jekyll blog的维护文章:Jekyll的安装

不过后续使用jekyll也遇到了一些问题:

  • ruby技术栈,不熟悉,导致要做一些customization很不方便
  • gem有的时候总是会遇到安装问题
  • jekyll的theme定了一个之后基本上就没办法换成其他的了(这个问题在gatsby上也有,后面会提供解决方法),然后我之前选的一款theme比较老,就导致了很多问题,比如说手机浏览不友好等
  • 一些比较现代化的website应该有的功能都没有,比如说浏览器兼容性等,其实主要还是因为上一条
  • 功能相对来说比较简单,毕竟jekyll真的是一款很纯粹的静态化站点工具

说到底,关键的问题还是技术栈,如果是基于node的话,很多问题其实我都可以自己解决。 于是今年就想换到node技术栈,看了下,其实也就gatsby比较强大点。

这里需要澄清一点:Gatsby是一个建站工具集,而不是Jekyll这样的静态站点工具。这两者是有本质区别的:

  • Jekyll只能用来做静态网站,也就是说将md内容构建成一系列的静态html内容,放到host上
  • Gatsby主要是用来做网站建设的,你需要什么类型的网站,静态的还是带后台数据库的,gatsby都可以帮你搞定,而不仅仅只是静态的CMS型的网站

可以看下WHY GATSBY了解下:

Gatsby enables developers to build fast, secure, and powerful websites using a React-based framework and innovative data layer that makes integrating different content, APIs, and services into one web experience incredibly simple.

Gatsby功能非常强大,对我来说有利有弊:

pros:

  • gatsby工具集、插件系统非常强大,各种客制化需求都可以自行满足
  • gatsby基于reactjs,要制作一些自己的组件非常容易上手
  • gatsby有大量现成的starter或theme等,几乎任何简单的需求都可以直接使用,不需要额外的开发
  • gatsby的工具集提供的功能都非常现代化,响应式页面、浏览器兼容性等都不在话下,建出来的站点功能完备

cons:

  • gatsby过于强大,很多东西存在但对我来说无用,反而可能会有维护负担(漏洞、版本升级等)
  • gatsby的graphql系统对我来说太复杂了,我只是要一个静态站点而已
  • gatsby需要上手时间来学习和了解里面的细节,它有自己的系统和API等,都是需要时间熟悉的,而不是像jekyll那样几个CLI命令就搞定一切了

Anyway,最后反正还是切到了Gatsby。不过因为wordpress之前转到jekyll的时候是通过生成一部分静态html直接存放在jekyll的repo里的方式进行的。到了gatsby这步就行不通了,gatsby是整站完全由CLI生成的,我简单研究了下,没找到像jekyll那时候的那种能兼容两种行为的模式。最后只能忍痛抛弃掉了转到jekyll之前的那部分博客内容,还好量不算特别大。

2. 选择Starter

要使用Gatsby开始建站,必然首先会需要选择一款Starter,在其基础上进行二次制作/设置/内容输出(什么?你说你想直接用gatsby基础库裸做一个站点?那你为什么不直接用react得了,gatsby一堆API那么复杂,何必呢)。选择Starter可以去Gatsby的官方站点:Gatsby Starter Library,然后用命令行工具来进行操作:

$ gatsby new {your-project-name} {link-to-starter}

不过实际上这个命令也就是帮你clone了一个repo出来而已,没啥意义,建议看我后面的第三点来进行初始化和repo管理。

我个人选的是:gatsby-starter-lumen。虽然没什么出彩的地方,但至少功能比较齐全,而且我看了看还有稳定的维护记录,不过应该也不能算是active了,到现在(20210905)仍旧用的是Gatsby的2.X的版本,Gatsby官方Release都已经是3.14.X了。如果现在还有人入坑的话,那建议还是要选一款支持v3以后Gatsby版本的Starter。

3. 如何管理你的repo

静态站点的repo管理建议如下:

  • 制作一个repo专门放gatsby相关内容,建议使用bitbucket制作一个单人用的private repo:Bitbucket
  • 制作一个单独的github page repo,来收取gatsby build出来的静态内容,作为静态站点的host:Github Pages

至于为什么要这么做:

  • 鸡蛋不同篮,保证安全,原始数据和静态站点尽量分开
  • 如果你的站点里有任何会导致版权争议之类的内容,也只会有github page repo被take down,而不会影响到你的原始数据
  • 务必保证你的原始数据一定要保存在一个private repo里,否则极容易被和page repo一起take down

因为我的原始数据repo是放在bitbucket的,就不能直接使用github的fork了。这里可以打开Bitbucket的import页面,使用import的方式,把你选择的Starter的github链接贴进去,这样就会在bitbucket里创建一个private repo,里面的内容是完全clone自github的。

为了后续接收原始starter repo里的改动(新功能及版本升级之类的维护等),建议不要直接在这个repo里的master分支进行任何改动,该repo的master分支上的所有内容必须保证无变动。后续所有starter的master发生的改动就可以直接pull过来。

在本地磁盘上clone刚才创建出来的bitbucket repo后,进入这个repo

  • 创建一个以你的站点命名的branch:xenojoshua.com
  • 在repo根目录创建同名文件夹:xenojoshua.com
  • 然后在里面创建一个Makefile来维护一些日常使用的命令
  • 此外,创建一个root文件夹,把所有你的客制化内容都放在这个文件夹内,文件夹的结构和外部starter的root文件保持一致,后续就可以使用脚本将这个文件夹下的内容全部复制到根目录,这样就能在保证starter不变的情况下,添加客制化的东西
  • 为了同步starter github原repo的内容,还需要添加一个remote,名字就叫sync,地址就是starter的github repo地址

原始数据repo和github page repo位置:

some_dir_on_disk /
                 | agreatfool.github.io / ...
                 | gatsby-starter-lumen / ...

原始数据repo文件结构:

gatsby-starter-lumen /
                     | content /
                               | pages    # starter自带的页面
                               | posts    # starter自带的范例posts
                     | src                # starter自带的组件等实现代码
                     | static /
                              | media     # starter自带的范例posts里用到的图片
                     | xenojoshua.com /
                                      | root /   # 所有内容都会在develop和build的时候覆盖到lumen根目录
                                             | content /
                                                       | pages
                                                       | posts /
                                                               | 2016 / ...
                                                               | 2017 / ...
                                                               | ...
                                                               | 2021 /
                                                                      | ...
                                                                      | 09 /
                                                                           | ...
                                                                           | gatsby-notes.md
                                             | src       # 客制化的组件代码,包括修改starter自带组件的一些行为
                                             | static /
                                                      | media /
                                                      | posts /
                                                              | 2016 / ...
                                                              | 2017 / ...
                                                              | ...
                                                              | 2021 /
                                                                     | ...
                                                                     | 09 /
                                                                          | ...
                                                                          | gatsby-notes / ... / *.jpeg
                                      | Makefile

Makefile:

sync将starter原repo里的改动同步过来:

sync:
	( \
		cd ..; \
		git checkout master -f; \
		git pull sync master --verbose; \
		git push origin master -f --verbose; \
		git checkout xenojoshua.com -f; \
		git rebase master; \
		git push origin xenojoshua.com -f; \
		cd xenojoshua.com; \
	)

develop在本地应用所有的变化,查看在xenojoshua.com文件夹下做的改动的效果:

develop:
	( \
		cd ..; \
		pwd; \
		rm -rf ./content/posts/*; \
		rm -rf ./static/media/*; \
		cp -Rf ./xenojoshua.com/root/* ./; \
		yarn add gatsby-remark-table-of-contents gatsby-plugin-image; \
		yarn develop; \
	)

build制作发布用的静态站点:

build:
	( \
		cd ..; \
		pwd; \
		rm -rf ./public; \
		rm -rf ./content/posts/*; \
		rm -rf ./static/media/*; \
		cp -Rf ./xenojoshua.com/root/* ./; \
		yarn add gatsby-remark-table-of-contents gatsby-plugin-image; \
		yarn build; \
		git checkout .; \
		git clean -fd; \
	)

deploy将最新的发布内容提交到github page repo,发布上线:

deploy:
	( \
		cd ../../agreatfool.github.io; \
		pwd; \
		git fetch; \
		git checkout -f gatsby; \
		git pull origin gatsby; \
		cd ../gatsby-starter-lumen; \
		pwd; \
		cp -Rf ./public/* ../agreatfool.github.io/; \
		cd ../agreatfool.github.io/; \
		pwd; \
		git add .; \
		git commit -m "Save."; \
		git push origin gatsby; \
	)

4. Gatsby技术开发

刚才也说到了用gatsby的最主要的原因就是能开箱即用,基本上不需要做什么改动就可以建站,但实际上多多少少还是要做点调整的。我对lumen做的改动:

  • blockquote太丑了,改了下样式
  • Feed组件改了下时间的format,改为中国人的习惯格式
  • Author组件改为github链接
  • Meta组件改了下时间的format
  • 自制了Gallery组件:

下面就简单说下gatsby里的一些技术点,因为每个starter都会对基本的gatsby进行客制化,所以我说的不一定你用得上,但大致上的概念是不会变的。另,建议先通读下Official Tutorial

4.1 Config

  • root/config.js:站点的一些基本属性,url是什么,作者信息等,会被下面的gatsby配置文件加载,实际上就是gatsby-config.js的一部分
  • root/gatsby-config.js:其他基本可以忽略,主要是插件的配置

这里提一句如果要让_不再被转为斜体,需要修改gatsby-transformer-remark插件的配置,在options里添加:pedantic: false

4.2 Structure

准备知识:

lumen的代码文件:

root /
     | gatsby /
              | create-pages.js    # 实现 createPages API,创建tags、categories、分页posts等页面
              | on-create-node.js  # 实现 onCreateNode API
              | on-render-body.js  # 实现 onRenderBody API
     | src /
           | assets / scss / ...   # 样式代码文件
           | components / ...      # 所有页面组件代码文件
           | templates / ...       # 所有页面的模板代码文件
     | gatsby-browser.js           # gatsby web的入口,css等就在这里加载
     | gatsby-config.js            # gatsby 的配置
     | gatsby-node.js              # gatsby node的入口,后端进程入口
     | gatsby-ssr.js               # gatsby ssr的入口,离线渲染

4.3 Graphql

Gatsby用Graphql用得很重,所有的页面上的数据都是来自graphql的查询,即便是你写的md文件post内容,也是通过graphql查询获得的。

准备知识:Part 4: Query for Data with GraphQL

这里不准备讲太展开,这个话题有点大了,基本上读完tutorial的内容也就差不多了,更深入的就先不谈了。

建议先用develop命令把后端启起来,然后按Use GraphiQL to explore the data layer and write GraphQL queries里提到的,打开GraphiQL界面进行摸索,稍微看下就会了。

graphiql

图上左边会列出所有gatsby可用的查询内容,紫色的表示是查询条件,蓝色的表示是可以得到的返回数据,点击你需要的内容,UI会自动将点中的内容填充到中间的那段查询语句里,非常便捷。查询结果也可以直接在UI上看到,基本上免去了后面到代码里调试的麻烦,只要UI上你的语句是对的,结果是你想要的,照样贴到代码里就不会错了。

4.3.1 Page query

Graphql最主要有两种使用方法,一种叫page query

  • 主要应用在页面初始化的时候的查询,比如说你的blog,点击某一篇post的链接,打开的时候就会去查询对应的post数据
  • 这个查询是可以带参数的,这很重要

整个查询路径如下:

  • root/gatsby-node.js:启动服务器,会加载 gatsby/create-page.js
  • root/gatsby/create-page.js:会决定某个page的template,以及对应的page query的context:e.g source
  • root/src/templates/post-template.js:在对应的template文件中,在graphql查询中使用context带过来的参数,并在page组件中使用查询得到的结果:e.g source1 source2

4.3.2 Static query

Graphql另一种使用方法是static query

  • 可以在任何你想要进行查询的地方进行查询,不一定要像page query那样必须写在固定的地方遵照规定的流程
  • 但这类查询必须是完全静态的,意味着你不能在query中添加任何变量
  • 虽然写法比较自由,但实际应用范围反而很小

EOF