使用 Gatsby.js 搭建静态博客 7 添加目录

前面说过基本功能已经添加完了,但是生成目录依然是我 TODO 的头号问题。今天终于把这个问题解决了,本来以为要自己解释 md 文件,没想到自带的插件就有这个功能我却没发现。生成目录获取目录数据生成目录首先要获取目录数据,此功能由插件 gatsby-transformer-remark 提供,请务必先安装。安装后在你需要获取目录的页面的 graphQL 查询代码中添加 tableOfContents。tableOfContents 后面的 pathToSlugField 用于生成锚点链接地址,默认值为当前文章的 slug。在例子中就把地址的前缀改成 md 文件提供的 path 了。这个位置就看你本来的地址怎么配置,如果本来就是 slug 则不用修改,直接写 tableOfContents 不用后面括号的部分。(不过我在实践中发现改了之后地址也不会变,原因未明,谷歌也搜索不到类似的情况) { markdownRemark(fields: { slug: { eq: $slug } }) { id excerpt html tableOfContents(pathToSlugField: “frontmatter.path”) frontmatter { title tags date(formatString: “MMMM DD, YYYY”) } } }接着你就能得到像这样的目录字符串:"<ul><li><a href="/2019-01-08-understand-mvvm/#%E5%89%8D%E8%A8%80">前言</a></li><li><a href="/2019-01-08-understand-mvvm/#mvvm-%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">MVVM 基本信息</a></li><li><a href="/2019-01-08-understand-mvvm/#mvvm-%E7%BB%93%E6%9E%84%E5%88%9D%E8%A7%81">MVVM 结构初见</a></li><li><p><a href="/2019-01-08-understand-mvvm/#mvvm-%E4%B8%8E-mvc-%E7%9A%84%E5%AF%B9%E6%AF%94">MVVM 与 MVC 的对比</a></p><ul><li><a href="/2019-01-08-understand-mvvm/#vue-%E7%9A%84-mvvm">Vue 的 MVVM</a></li><li><a href="/2019-01-08-understand-mvvm/#%E5%89%8D%E7%AB%AF-mvc">前端 MVC</a></li></ul></li><li><a href="/2019-01-08-understand-mvvm/#%E6%8B%93%E5%B1%95%EF%BC%9Areact-%E5%8F%AA%E6%98%AF-mvc-%E7%9A%84-v%EF%BC%9F">拓展:React 只是 MVC 的 V?</a></li><li><a href="/2019-01-08-understand-mvvm/#%E7%90%86%E8%A7%A3%E3%80%81%E4%BA%A4%E6%B5%81">理解、交流</a></li></ul>“参考链接:https://www.gatsbyjs.org/pack…注入锚点你可能觉得上面的字符串塞到网页就大功告成……嗯我当时也这么想。现在你即使有这么一个带 url 的目录,点击缺不会跳转到对应位置。因为 markdown 转换到 html 之后并没有注入锚点。为解决这个问题要引入一个新插件 gatsby-remark-autolink-headers。npm install –save gatsby-remark-autolink-headers安装后进行如下配置// In your gatsby-config.jsmodule.exports = { plugins: [ { resolve: gatsby-transformer-remark, options: { plugins: [gatsby-remark-autolink-headers], }, }, ],}如果是看过之前的教程的话一定知道我的事例项目用了 prismjs,prismjs 插件与 autolink 有迷之冲突,一定要把 autolink 放前,prismjs 放后:// good{ resolve: gatsby-transformer-remark, options: { plugins: [ gatsby-remark-autolink-headers, gatsby-remark-prismjs, ], },}// bad{ resolve: gatsby-transformer-remark, options: { plugins: [ gatsby-remark-prismjs, // should be placed after gatsby-remark-autolink-headers gatsby-remark-autolink-headers, ], },}添加成功后由 md 文件转换得到的 html 字符串里的标题就会都带上 id,这样锚链接就能正常使用啦!参考链接:https://www.gatsbyjs.org/pack…调整样式以下是我的样式代码,因为框架的全局样式对 ul 和 li 的影响挺大的,所以不少代码是用于修复的。另外是用媒体查询在大屏时把目录固定到左下角。.css-toc { color: $titleColor; padding: 15px; background: #fcfaf2; margin-bottom: 25px; > ul { padding-left: 16px; } ul { list-style-type: square; list-style-position: outside; margin-bottom: 0; p { vertical-align: top; display: inline-block; } } li { margin-bottom: 0; } li > p { margin-bottom: 0; } li > ul { margin-top: 0; }}@media screen and (min-width: 1045px) { .css-toc { position: fixed; bottom: 0; right: 0; width: 200px; max-height: 400px; overflow: scroll; font-size: 14px; li > ul { margin-left: 1rem; } }}完成效果图 ...

January 31, 2019 · 2 min · jiezi

使用 Gatsby.js 搭建静态博客 6 评论系统

方案选择大家都知道 disqus 等第三方评论系统的存在。disqus 几年前还是挺好使的,但是现在已经是不存在的网站了。虽然国内也有类似的服务,但是免费档位有可能会有大篇幅的广告。不过其实最大的问题是:你的评论掌握在别人手上。作为一个博客都自己搭建的程序员,为什么要让数据落在别人手上呢?掌握自己的评论数据有两个方法:自建接口,储存评论数据,页面也是动态获取数据。使用接口在 github 仓库更新评论信息,然后重新生成包含最新评论的静态页面。官网推荐的是第二种方法,借助一个叫 staticman 的开源工具。推荐原因有 3:自己掌控数据服务崩溃时也能展示评论(针对第三方评论系统和上面动态获取评论的方案 1 的问题)staticman 集成了 akismet 过滤垃圾评论所以本文着重说明 staticman 的使用方法(如果想使用第一种方案可以依赖 strapi 框架)。因为我之前使用 staticman 本身的服务接口不能调通,但是本地测试可以,所以我决定部署自己的 staticman。部署自己的 staticmanstaticman 的原理就是使用 GitHub 接口把评论更新到你静态博客的仓库,触发博客重新部署,在页面生成评论。这样得到的博客页面包括评论部分都是完全静态的。对 GitHub 接口更新仓库感兴趣的话可以参考使用 Github API 更新仓库首先 clone staticman 的官方仓库。你可以先在本地测试运行,也可以直接部署到云端(需要免费服务的话依然推荐 heroku)。staticman 部署配置在生产环境,首先需要一个生产环境的配置文件 config.production.json。可以通过 cp config.sample.json config.production.json 生成配置文件。这个配置文件里面甚至自带文档,可以很清晰看出每个项目的作用。其中最重要的是两个配置项: githubToken: { doc: ‘Access token to the GitHub account being used to push files with.’, format: String, default: null, env: ‘GITHUB_TOKEN’ }, rsaPrivateKey: { doc: ‘RSA private key to encrypt sensitive configuration parameters with.’, docExample: ‘rsaPrivateKey: “—–BEGIN RSA PRIVATE KEY—–\nkey\n—–END RSA PRIVATE KEY—–”’, format: String, default: null, env: ‘RSA_PRIVATE_KEY’ },第一个 githubToken 用于获取修改你的仓库权限的 token,必须注意这个 token 不能泄漏,不然别人就能随便修改的你仓库了。第二个是用于加密留言中的邮箱。配置完毕推送到 heroku 或本地运行 npm start。(运行环境会根据 NODE_ENV 判断)staticman 应用于你的仓库发送以下 Get 请求http://your-staticman-url/v2/connect/GITHUB-USERNAME/GITHUB-REPOSITORYstaticman 推送配置在根目录创建 staticman.yml 文件,可以参考:https://github.com/eduardobou…PS. 如果将配置中的 moderation 设为 true,推送到仓库后不会直接合并而是先提出一个 PR。这个配置的目的是确定你传入到仓库的数据格式,对应的表格应该类似:<form method=“POST” action=“https://api.staticman.net/v2/entry/eduardoboucas/staticman/gh-pages/comments"> <input name=“options[redirect]” type=“hidden” value=“https://my-site.com”> <!– e.g. “2016-01-02-this-is-a-post” –> <input name=“options[slug]” type=“hidden” value=”{{ page.slug }}"> <label><input name=“fields[name]” type=“text”>Name</label> <label><input name=“fields[email]” type=“email”>E-mail</label> <label><textarea name=“fields[message]"></textarea>Message</label> <button type=“submit”>Go!</button></form>更新请求:POST https://api.staticman.net/v2/entry/{GITHUB USERNAME}/{GITHUB REPOSITORY}/{BRANCH}/{PROPERTY (optional)}功能完成至此,成功添加评论功能,整个博客的功能也几乎完善。对比之前被放弃的一个 wordpress 和一个 hexo,这次是我第一次从基本模板开始自己添加功能做出来的静态博客,来之不易,希望珍惜,接下来要做的就是继续优化功能和 UI,坚持更新了。 ...

January 18, 2019 · 1 min · jiezi

使用 Gatsby.js 搭建静态博客 1 关键文件

原文地址:https://ssshooter.com/2018-12…静态博客之前也有搭建过,不过使用 Hexo 一键生成的,其实当时也有考虑过 Gatsby,不过这个框架搭建博客入门还是比较难的,前置知识点包括 react 和 graphQL。这个系列的文章记录的就是这个博客搭建中需要注意的点。此博客使用 gatsby-starter-blog 作为框架,后续自己添加功能。在安装 gatsby cli 后运行此指令即可以 gatsby-starter-blog 为模板创建博客。gatsby new gatsby-blog https://github.com/gatsbyjs/gatsby-starter-blog项目创建后文件夹结构基本如下(有区别是因为这是我搭建好的截图,也有可能是 starter 的版本升级)其中最为重要的是 gatsby-node.js、/src/templates/blog-post.js 以及 gatsby-config.js。gatsby-node.js页面创建逻辑大部分都在 gatsby-node.js,打开文件可以看到类似代码:// 页面创建函数exports.createPages = ({ graphql, actions }) => { const { createPage } = actions return new Promise((resolve, reject) => { const blogPostTemplate = path.resolve(src/templates/blog-post.js) // 查询 md 文件构建页面 // 此处查询使用的是 graphql,这也是 Gatsby 入门门槛较高的原因之一 // 不过其实这是一个比 sql 更容易理解的查询语言 resolve( graphql( { allMarkdownRemark(limit: 1000) { edges { node { frontmatter { path } } } } } ).then(result => { if (result.errors) { reject(result.errors) } // 遍历查询结果生成页面 result.data.allMarkdownRemark.edges.forEach(({ node }) => { const path = node.frontmatter.path // 生成单个页面的函数 createPage({ path, // 页面路径 component: blogPostTemplate, // 页面使用的模板 // 这是注入上下文变量,注入后可以在模板页面中使用变量 // 变量可以使用于 graphql 查询和 jsx 编写 context: { path, }, }) }) }) ) })}/src/templates/blog-post.js此处只是一个举例,其他模板文件和页面文件的结构都类似,所以这里使用 /src/templates/blog-post.js 说明文件结构。(另外放在 /src/pages/ 的 js 文件都是会转换为页面的)这类文件两部分:第一部分:export default BlogPostTemplate这是页面视图的组件,跟普通 jsx 一样,不过上面有说到:createPage 函数是可以注入参数到模板文件的。而这些参数就在 this.props.pageContext 中。另外,下面将会提到的页面查询函数所得的数据在 this.props.data。第二部分:export const pageQuery// 注意其中 $slug,这也是被页面创建函数注入的上下文变量,没有前缀,直接使用即可export const pageQuery = graphql query BlogPostBySlug($slug: String!) { site { siteMetadata { title author } } markdownRemark(fields: { slug: { eq: $slug } }) { id excerpt html frontmatter { title tags date(formatString: "MMMM DD, YYYY") } } }查询函数大概长这样,简单来说 graphql 就是把你需要的数据填入你的请求,然后返回给你,光说不易理解,自己玩一把就能立刻明白!更方便的是,在项目开发环境运行后,还会自带一个 graphql 查询页面:http://localhost:8000/___graphql一定要注意右上角是自带文档的!遇到数据结构懵逼的时候,在文档查一下就 ok 啦(你甚至可以 ctrl 点击 query 中的字段名直接跳转到对应文档,实在方便得不能再方便了,好评!)页面中的查询函数返回的结果会注入到 this.props.data,跟普通属性一样照常使用即可。gatsby-config.jsgatsby-config.js 看名字就知道这是 Gatsby 的配置文件。使用 starter 建立项目已经自带了不少插件,但在我的搭建过程中仍然有一些需要自己添加的。这里是 Gatsby 的插件库,遇到什么需求可以优先在此处搜索。总结结合这三个重要文件,便是 Gatsby 的应用结构:读取设置和插件 -> 调用创建页面前查询所需资源 -> 创建页面,把查询到的参数注入到模板 -> 进行模板本身的查询 -> 填入数据 -> 成功生成一个页面整个流程大部分都是使用循环生成所有页面。此系列下一篇将会是分页相关的详细说明,这是我初始化之后第一个加上的功能(是的, starter 是不带分页的…)。参考链接: https://www.gatsbyjs.org/docs… https://www.gatsbyjs.org/docs… ...

December 10, 2018 · 2 min · jiezi