本文首发于 https://blog.datapipeline.com/create-blog-by-using-gastby/
博客搭建有许多的方案可供选择。我们使用了 Gatsby 搭建博客。这篇博客总结了 Gatsby 的一些好处以及开发过程中遇到的一些问题和解决方式。
优点
1. 基于组件开发
Gatsby 使用的是基于 React 组件的开发。基于组件的开发更容易模块化和封装应用。更简单地给博客添加、修改功能。
2. 支持离线访问
博客页面在离线是也能访问。(当然,前提是已经访问过此页面)
3. 自动化响应式图片
对于页面中使用到的图片,Gatsby 会自动生成多种分辨率的图片,并在不同设备上使用相应大小的图片。
4. 由模糊到清晰加载图片
图片加载会先显示一个模糊的轮廓图片,在显示原图。(从 Medium 和 Facebook 开始逐渐流行的显示方式)
5. 灵活
Gatsby 使用了插件系统,并且提供了 许多插件。通过插件可以实现许多功能。
灵活选用技术方案
- 可以使用 JavaScript 或 TypeScript
- 灵活选用 CSS 技术方案:CSS、Sass、CSS Modules、CSS in JavaScript 等
比如对于 CSS class 名称冲突的问题,BEM 是一个很好的解决方式。但是我很不喜欢这种方式,因为写起来太麻烦了。Gatsby 比较灵活,我可以使用 CSS Modules,直接把 header.css
改成 header.module.css
就可以了。如果你喜欢用一些 CSS in JavaScript(例如:styled-components
、glamor
),也可以灵活配置。
灵活的文件结构
- 可以把 Markdown 文件放到
contents/
目录下,也可以放到/src/pages/
下 - 可以把博客相关的 Sketch 文件放到此目录下,如果某张图片需要修改,就不会有找不到源文件的烦恼
灵活的内容读写和转化
- 可以给博客添加 tags
- 可以给每篇博客设定一个主色调
- 可以建一个作者列表页
如何搭建
安装 Gatsby CLI:
npm install --global gatsby-cli
Starter Kit
gatsby new [SITE_DIRECTORY] [URL_OF_STARTER]
# 例如:
# gatsby new blog https://github.com/gatsbyjs/gatsby-starter-blog
Gatsby 官网上有 许多 Starter。搭建博客的话推荐使用功能齐全一些的 starter。也可以使用 本博客使用到的 starter。具体的功能可以直接参考代码实现。
目前,用
gatsby new some-starter-kit
基本过程就是 git forksome-starter-kit
,然后再用npm install
(或yarn install
)的安装依赖(相关源代码)。也完全可以手动 fork 一个 starter-kit。
Gatsby 基础架构
Markdown 只是其中的一种源,Gatsby 还支持很多其他源,包括数据库、WordPress、API 等,甚至可以从 medium 上获取数据。
Gatsby 基本目录结构
├── gatsby-config.js <--- Gatsby 配置(标题、插件等)
├── package.json
└── src
├── html.jsx <--- 定义基础的 html, head 等
├── pages
│ ├── index.jsx <--- 首页
| ├── about.jsx <--- about 页面
│ └── posts <--- 具体的博客
│ ├── 01-01-2017
│ │ └── index.md
│ ├── 01-02-2017
│ │ └── index.md
│ └── 01-03-2017
│ └── index.md
├── templates <--- 模板(博客模板等)
│ └── post.jsx
│
└── layouts <--- 页面布局(可以包含 header/footer 等部分)
└── index.jsx
Markdown 格式规范化
Update: Prettier 现已支持格式 Markdown 文件,推荐直接使用 Prettier 进行格式化。
Markdown 中许多语法都支持多种形式,比如对于无序列表元素,可以使用 -
,*
和 +
。对于多人协作的博客,规范化博客内容能保值一致性,也有助于增加可读性。同时,我们的博客排版规范大致使用 中文文案排版指北。为了让排版更加方便,能自动格式化的地方尽量自动化。
我们使用了 remark 格式化 Markdown 文件,同时写了一个插件 remark-pangu
自动在中英文间添加空格。在每次 git commit
前,都会自动对 Markdown 文件进行格式化。具体处理方式如下。
npm install --save-dev husky lint-staged remark-cli remark-frontmatter remark-pangu
# 或者使用 Yarn
# yarn add --dev husky lint-staged remark-cli remark-frontmatter remark-pangu
在 package.json
的 scripts
部分添加:
"scripts": {
"precommit": "lint-staged",
}
husky 可以让你在 npm scripts 里写 Git hooks。所以以上配置会在每次 commit 前运行一次
lint-staged
命令。
同时添加 lint-staged
字段到 package.json
里:
"dependencies": {
},
"lint-staged": {
"src/**/*.{md,markdown}": [
"remark --output --config",
"git add"
]
},
"scripts": {
}
lint-staged 可以让你对 Git staged 文件运行命令。
例如: Git staged 有两个文件:src/pages/post-a/index.md
和src/pages/post-b/index.md
,在git commit
时,lint-staged
会运行以下命令:
remark --output --config /Users/.../src/pages/post-a/index.md
git add /Users/.../src/pages/post-a/index.md
remark --output --config /Users/.../src/pages/post-b/index.md
git add /Users/.../src/pages/post-b/index.md
remark 命令中,
--output
后不加参数会覆盖源文件,--config
搜索配置文件(rc 文件或 package.json 中的remarkConfig
字段)。
--config
配置其实 默认就是开启的,这里加上只是为了让--output
能正确使用。--output
后面可以加路径,表示格式化或保存的路径,也可以不加,不加则覆盖源文件。如果这里不加上--config
,组lint-staged
的命令会变成:
remark --output /Users/.../src/pages/post-a/index.md
会将输入文件(
/Users/.../src/pages/post-a/index.md
)指定为 output 路径,出问题。所以加了一个实际没什么作用的--config
。
在 package.json
中添加一个 remarkConfig
字段,添加 remark 配置和需要的插件:
{
// ...
"remarkConfig": {
"settings": {
"bullet": "*", // 无序列表使用 `*`
"listItemIndent": "1" // 嵌套的列表元素使用 1 个空格
// 更多配置可以查看:
// <https://github.com/wooorm/remark/blob/master/packages/remark-stringify/readme.md#processorusestringify-options>
},
"plugins": [
"remark-frontmatter", // 因为我们有用到 Front Matter,所以需要这个插件
"remark-pangu"
]
}
}
package.json
中实际不支持注释,以上只是为了说明而添加的注释,使用时要将注释去掉。
lint-staged
只能对 Git staged 文件运行命令,如果要对所以 Markdown 文件进行一次格式化,可以使用以下命令:
./node_modules/.bin/remark ./src --output
最终效果:
不足之处
🐛 bugs…
还不是很完善,经常会遇到 bug。我在搭建的过程中就遇到了几个 bug(service worker bug、Prism bug)。不过这也是一步步完善的过程。
🔍 搜索
如果想做一个搜索所有博客内容的功能,就比较难实现。因为是静态网页,没有数据存储。但也不是不可以,可以使用类似于 Algolia 的第三方服务实现。
🌅 生成的图片名称
目前默认 build 之后的图片名称都是用 hash 来命名,例如 4e1d67ed07986e3edb3dcefd709b478c-6f08c.png
。如果能保留原文件名称会更具可读性一些,例如 datapipeline.e1d67ed0.png
。
参考资料: