刚开始想要在GitHub Pages上搭建一个博客网站的时候, 我的需要的只是一个可以帮我将普通文本文件转化为 HTML 的框架,比如已经和 GitHub Pages 深度集成的 Jekyll,但是带着探索新技术的心,我还是选择了更加新潮的 Gatsby.
Gatsby is a blazing-fast static site generator for React.
从 GitHub 上简洁的介绍可以看到,这是一个用于快速构建静态网站的框架,并且是使用使用的是React.js. 由于工作中使用过 React,当我看到连 React 的官网都是用 Gatsby 搭建的时候,我决心尝试一下这个框架.
跟着官方文档https://www.gatsbyjs.org/docs/,可以很容易地搭建出 Gatsby 的开发环境, 如果之前使用过 Node.js,应该可以很容易的上手.
npm install --global gatsby-cli
gatsby new gatsby-site
cd gatsby-site
gatsby develop
Gatsby 提供了几个默认的 starter 用于从模板中快速搭建一个网站,虽然 starter 都比较简单,但是对理解 Gatsby 的使用方法有很大帮助.
gatsby new [SITE_DIRECTORY] [URL_OF_STARTER_GITHUB_REPO]
gatsby new blog https://github.com/gatsbyjs/gatsby-starter-blog
Gatsby 的基本目录结构如下:
├── gatsby-config.js
├── package.json
└── src
├── html.jsx
├── pages
│ ├── index.jsx
│ └── posts
│ ├── 01-01-2017
│ │ └── index.md
│ ├── 01-02-2017
│ │ └── index.md
│ └── 01-03-2017
│ └── index.md
├── templates
│ └── post.jsx
│
└── layouts
└── index.jsx
pages 目录
在这个目录下的 React Component 会自动转化为静态页面,URL 路径由文件名决定,如src/pages/index.js
会转化为domain/
,而src/pages/about.js
会转化为domain/about/
.
templates 目录
pages 目录可以直接构造新页面,而当有许多类似的页面时,直接在 pages 页面创建会需要做许多重复的工作,
这时可以在 templates 目录下创建一个模板用于包装,然后使用 GraphQL 将所需要的数据放入这个模板,从而自动生成多个类似的页面.
Layouts 目录
这个目录下包含了一个 React Component(非必须的),它是网站中所有页面的公共容器,可以在这里定义网站的导航条和脚注.
html.js 文件
这个文件定义了整个网站最基本的 HTML 结构,可以在这个文件里面自定义<head>
中的内容.
Gatsby 支持了许许多多的插件,我想这才是许多人选择 Gatsby 的原因.在网站中加入新的插件支持需要以下两个步骤(以gatsby-transformer-json
为例):
npm install --save gatsby-transformer-json
module.exports = {
plugins: [`gatsby-transformer-json`],
};
说到构建博客网站,一个重要的点就是要将网站页面逻辑和博客文本内容分离,这样在写博客时不用关心页面的具体渲染逻辑,我想没有人想在写文章的时候还要想着怎么去调整页面的 CSS 吧. Markdown 是一种轻量级的文本标记语言,它的特点是可以通过简单的标记语法让文本内容具有一定的格式. 在 Gatsby 中使用 Markdown 生成页面需要一下几个步骤:
这是通过gatsby-source-filesystem
插件完成的
npm i --save gatsby-source-filesystem
gatsby-config.js
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/path/to/markdown/files`,
name: "markdown-pages",
},
},
];
这是通过gatsby-transformer-remark
插件完成的,这个插件会读取 Markdown 文件,
将其中元数据部分(metadata)转化为frontmatter
,将内容部分转化为 HTML.
npm i --save gatsby-transformer-remark
gatsby-config.js
plugins: [`gatsby-transformer-remark`];
在src/templates/
目录下为转换后的 Markdown 数据创建模板文件,定义生成的 html 页面的具体内容和样式.
import React from "react";
export default function Template({
data, // this prop will be injected by the GraphQL query below.
}) {
const {markdownRemark} = data; // data.markdownRemark holds our post data
const {frontMatter, html} = markdownRemark;
return (
<div className="blog-post-container">
<div className="blog-post">
<h1>{frontmatter.title}</h1>
<h2>{frontmatter.date}</h2>
<div
className="blog-post-content"
dangerouslySetInnerHTML={{__html: html}}
/>
</div>
</div>
);
}
export const pageQuery = graphql`
query BlogPostByPath($path: String!) {
markdownRemark(frontmatter: {path: {eq: $path}}) {
html
frontmatter {
date(formatString: "MMMM DD, YYYY")
path
title
}
}
}
`;
需要注意的点:
Gatsby 提供了强大的Node.js API,
它们可以在gatsby-node.js
文件中使用.下面将会示范如何使用createPages
API 来创建页面.
const path = require("path");
exports.createPages = ({boundActionCreators, graphql}) => {
const {createPage} = boundActionCreators;
const blogPostTemplate = path.resolve(`src/templates/blogTemplate.js`);
return graphql(`
{
allMarkdownRemark(
sort: {order: DESC, fields: [frontmatter___date]}
limit: 1000
) {
edges {
node {
excerpt(pruneLength: 250)
html
id
frontmatter {
date
path
title
}
}
}
}
}
`).then(result => {
if (result.errors) {
return Promise.reject(result.errors);
}
result.data.allMarkdownRemark.edges.forEach(({node}) => {
createPage({
path: node.frontmatter.path,
component: blogPostTemplate,
context: {}, // additional data can be passed via context
});
});
});
};
gatsby-config.js
文件 export 的每个函数boundActionCreators
和graphql
createPage
创建页面