JAMStack 实践:使用 Gatsby & Notion 构建站点

2019-12-12#总结#JAMStack#Gatsby#notion

JAMStack

我很讨厌这种概念含糊不清的新生词汇。但是当你想要交流的时候,又必须给它一个名称。本文不打算用过多的篇幅介绍 JAMStack。下面是有用的链接&引用,可以帮助你更好的理解这种理念。

技术雷达 vol 21

许多年前从手机原生开发兴起的后端即服务开发模式,现在在Web开发上变得流行起来。我们将这种集合了静态站点生成和利用第三方API进行客户端渲染的框架被称为JAMstack(JAM代表JavaScript,API 和 Markup),例如Gatsby.js。这种方式之所以能给用户提供丰富的体验,主要依靠的是API和SaaS。因为HTML不管是在网页浏览器中还是在构建时渲染,它的部署模型和全静态生成的网站是一样的,共同的好处是服务端的攻击面很小,而使用很少的资源可以获得极好的性能。事实上,像这种在部署上对内容发布网络(CDN)非常友好的技术,我们开玩笑想把它称为CDN优先应用程序。

https://jamstack.org/

https://jamstack.wtf

定性的来说它是一种开发架构,由 Netlify 的提出并且实现,同样 Netlify 也提供部分对应的服务。

Gatsby

关于 Gatsby 的介绍,上一篇文章中有提到一些,这里不再赘述。

bookmark

技术雷达 vol 21

Gatsby.js是一个用于编写JAMstack架构风格网络应用的框架。应用的一部分在构建时生成并且以静态站点的形式进行部署。剩余的功能以渐进式网络应用的方式进行实现并运行在浏览器中。这些应用无需服务端代码即可运行。通常来说,渐进式网络应用会通过调用第三方API,或者现成的SaaS解决方案实现内容管理等功能。在Gatsby.js的例子中,所有的客户端和构建代码都是用React编写。框架包含了一些优化来让程序运行得更快。它将代码与数据分离来最大程度地减少加载时间,并且通过在应用内跳转时预先加载资源来提高性能。接口通过GraphQL进行调用并且通过一些插件来简化和现有服务的集成。

bookmark

广而告之

📢 GatsbyJS 简体中文文档目前正在翻译中,欢迎大家加入翻译小组 🎉 🎉 🎉

Notion

Notion 引入了 block-styled 的编辑模式。万物皆 block 的理念贯穿于整个应用中。当你使用 Notion 时,会有一种玩乐高、我的世界的感觉。这种 block 的模式能激发使用者的创造力。sspai 上一堆 Notion 吹,这里我就不吹了。

喜欢 Notion 的人,大都不会吝啬他的溢美之词。下面是 Jamie(notion-py 作者) 的彩虹🌈屁。

Notion was no longer just a productivity tool. It was now a general-purpose widget-rich responsive UI layer and data store that could serve as a dashboard, control panel, task manager, or a CRM system with mail-merge. It’s the holy grail of API-lovers: a central system, with a great UI and flexible schemas, into which all-the-things can be integrated.

我非常赞同 Jamie 的观点,这也是我喜欢 Notion Database 的原因 ,程序员懂得都懂。

Database 是 Notion 2.0 推出的功能,在此之前 Notion 跟其它的笔记软件比起来并没有太大的优势。

Notion Database 提供了数据存储服务 & API(非官方)。至此为止 JAMStack 的要素齐全了。

  • [x] Javascript —— gatsby
  • [x] API —— notion
  • [x] Markup —— gatsby

让我们看看这些东西混在一起,能起什么样的化学反应。下面是我基于 Notion 的数据服务造的一些轮子。

  • gine-blog —— 个人博客

block-styled 的编辑器写作体验很好。Database 可以结构化地组织数据。公开页面,即可享受图床服务。在 Notion 中我通过 Database 来组织博文,gine-blog 在 build 时,会拉取 Notion Database 中的数据,构建出一个静态站点。博客托管在 Netlify 上,每当我写完文章后,我只需要向 Netlify 发用一个 POST 请求,告诉它重新构建我的站点,既可以完成文章的发布。为此我还写了个 Chrome 的插件,它可以帮助我发送 POST 请求(构建站点),在 Notion 中完成一站式的操作:从写作到发布,我都无需离开 Notion 页面。

  • phos —— PWA 音乐播放器

网易云灰掉的歌(还有越来越臃肿的 app),让我转投了 Spotify 。但是 Spotify 也没法完全解决版权问题。流媒体服务带来便利的同时,也让我们失去了很多自由。自建仿佛是最好的出路,于是乎便有了这个项目。Notion Database 存储歌曲数据,PWA 提供跨平台的使用体验。其中绝大部分歌曲直接使用网易云的音源,对于网易云没有版权的歌曲,可以使用 youtube 音源替换,都没有的可以去找一些网络资源,然后上传到 notion 的音乐表中。 《跳舞的梵谷》 这张专辑是我在网易云买的,下载 ncm 后转码为 mp3 上传到 Notion 表中。

渐进策略:网易云 > youtube > 购买数字音频 / 下载网络资源上传到 Notion

写 Phos 时,我意识到数据服务+PWA 离线应用的模式非常讨人喜欢,即它没有隐私和版权的问题,并且是跨平台的。就好比多年前的本地播放器,它虽然没有集成云服务,无法多端同步。但是它就是一个纯粹的播放器,做它份内的事情,绝不越界。

$$ 服务 = 数据 + 应用 $$

我希望未来的服务可以像这样拆分,服务不再跟服务商耦合(现在的服务商即掌握数据又掌握应用的发布),数据是自己的,原始数据是对用户可见的。可以有多个数据服务商,可以有多个应用。我选择我喜欢的,不是非要去吃某一陀屎。

我以为我发现了什么了不得的新趋势,搜索一番。原来我们的李爵士在十年前就提出了这样的观点:

Raw Data Now!

后来发展成了 Solid 项目,感兴趣的可以看一看。Solid 似乎是一种反商业模式的模式,可能很难取得大的进展。不过我喜欢这种愿景。

https://www.youtube.com/watch?v=OM6XIICm_qo

https://zh.wikipedia.org/zh-cn/Solid_(%E7%BD%91%E7%BB%9C%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96%E9%A1%B9%E7%9B%AE)

实践

看了上面这么多,基于 Notion 开发应用是种怎样的体验?为什么不自己试一试一下呢。

下面的实践,会引导读者构建一个展示博文&书单的站点,它可以作为个人博客的基础。

前置技能

  • 掌握基本的 Javascript + HTML + CSS
  • 接触过 React 开发

开发环境

  • node
  • npm / yarn

新手包

Notion API 尚未正式推出(已经鸽了好几年了),可以使用非官方的 API(基于 Web 版网络请求的封装)。我为 Notion 的 Database 专门写了API Wrapper —— notabase,它可以让你使用 Javascript 与 Notion Database 中数据交互。然后基于 notabase 构建了数据源插件 —— gatsby-source-notion-database,方便在 Gatsby 中使用。

这里有一个stater 可以帮你快速搭建起开发环境。

  • 通过 gatsby-cli 快速搭建 starter

如果你已经安装了 gatsby-cli ,可以使用下列命令,快速获取 starter。


gatsby new my-gatsby-notion-site https://github.com/mayneyao/gatsby-starter-notion
  • 或者先获取源码,然后再安装依赖。

git clone https://github.com/mayneyao/gatsby-starter-notion
cd gatsby-starter-notion
yarn // or npm install

安装完依赖后, yarn develop 会在你本机的 8000 端口,开启一个开发服务器。访问 http://localhost:8000 我们会看到一个类似这样的站点。

https://gatsby-stater-notion.netlify.com/

至此为止,一个用 Notion 和 Gatsby 搭建的站点就诞生了🎉 。

这篇文章不打算一步一步的教你怎么用 Gatbsy,关于如何使用 gatbsy 你应该去查阅它的官方文档。

https://www.gatsbyjs.com/docs/quick-start/

下面我会介绍建站过程中几个重要的步骤。

建立数据库

在 Notion 中建立 Database 页面,可以理解为 Notion 中的一个 Database page 映射数据库中的一张表。在此之前你需要构思下 schema 该如何设计,不用太过谨慎,Notion 的 Database 是十分灵活的,后面怎么修改都可以,不必考虑数据之间的约束和完整性,这使得你可以快速地验证想法。

这里有个模板,你可以克隆到自己的 Notion 中。

https://www.notion.so/mayne/gatsby-starter-notion-2c5e3d685aa341088d4cd8daca52fcc2

此页面包含了2张表格

  • posts —— 文章表
  • title —— 文章标题
  • tags —— 文章标签
  • books —— 文章可能关联了某本图书
  • status —— 文章状态。一个 idea,或者正在写,或者已经发布。
  • publish_date —— 发布时间
  • books —— 书单表
  • title —— 图书标题
  • cover —— 图书封面
  • status —— 状态。在读,已读,未读。
  • comment —— 如何评价这本书
  • posts —— 和这本书有关联的文章。

文章表书单表是相互关联的,例如我看了《流畅的 Python》这本书,我有一些感悟,因此我写了一遍赞美 Python 的文章。

连接 Notion & Gatsby

// gatsby-config.js
{
  resolve: `gatsby-source-notion-database`,
  options: {
    sourceConfig: [
      {
        name: 'posts',
        table: 'https://www.notion.so/4b50defc60ce4e89a6539f511d9d946f?v=8e71dde4479040b5a3e6ca0d91d3d8e6',
        cacheType: 'html'
      },
      {
        name: 'books',
        table: 'https://www.notion.so/4ae9328e650945eb9adbd882b3b453d3?v=0966bdbd0645437cbcc62e6a933e241c',
        cacheType: 'static'
      }
    ]
  }
},

gatsby-config.js 的 plugins 中,完成 gatsby-source-notion-database 数据源插件的配置。

cacheType

  • static

表格数据会转化成 graphql 节点 ,本地开发时可以在 http://localhost:8000/___graphql 中查看调试。

  • html

在 static 的基础上,将记录对应页面的 html 缓存下来(使用 Puppeteer 抓取页面 HTML )。可通过 html 字段访问。

  • dynamic

数据不会在 build 时候存储,仅记录表格 meta 信息,方便后续在页面中动态获取数据。

运行 yarn develop 时,gatsby-source-notion-database 会将指定 Notion Database 中的数据全部拉取下来,转化为 GraphQL 的数据节点。

探索 Gatsby 中的 GraphQL 数据

开发服务器开启后,我们可以在本地的 8000 端口,查看数据。访问 http://localhost:8000/___graphql

你不了解 GraphQL 也没有关系。通过与左边的 Explorer 交互,可以快速生成查询语句,查询出我们想要的数据。整个过程非常自然、简单。

下图中,查询出了所有已发布的文章数据,并且文章数据中包含了关联的书籍数据。这些信息适用于在列表页中展示。

我们可以通过 html 字段访问文章的 html 内容,在后面的文章详情页中会使用到它。

Untitled.png

query MyQuery {
  allPosts(filter: {status: {eq: "published"}}) {
    nodes {
      title
      tags
      status
      publish_date(fromNow: false)
      books {
        title
        slug
        cover
      }
    }
  }
}

数据 > UI

数据已经有了,接下来在页面中渲染出来。对于 React 用户来说,这一步是应该是轻车熟路了。

//src/pages/index.js

import React from "react"
import { graphql } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"
import PostItem from "../components/postItem"

const IndexPage = (props) => {
  const { data: { allPosts } } = props
  return (
    <Layout>
      <SEO title="My Posts" />
      {
        allPosts.nodes.map(node => <PostItem data={node} />)
      }
    </Layout>
  )
}

export default IndexPage
export const query = graphql`
  query {
    allPosts(filter: {status: {eq: "published"}}) {
      nodes {
        title
        tags
        status
        slug
        publish_date(fromNow: false)
        books {
          title
          slug
          cover
        }
      }
    }
  }
`

小结

至此为止,我们回顾一下整个过程。

  1. 在 Notion 中设计 Database 表格。
  2. 使用 gatsby-source-notion-database 数据源插件,将 Notion Database 中的数据转化为 GraphQL 节点数据。
  3. 在 GraphQL Explorer 中探索要想要查询的数据。构建出查询语句。
  4. 在 UI 构建中,使用查询语句,得到想要的数据,再将数据渲染成页面。

整体的过程就是这样子。如果你恰好是 Notion 用户,又了解前端开发。那么使用 Notion 作为 CMS,使用 Gatsby 构建现代化的站点,整个过程是水到渠成的。

总结

JAMStack 是 Serverless 中一种不错的实践。其最大的优势是降低了开发&运维成本。

如果是以前,我要搭建个人博客,我要先去买服务器,然后配置 LAMP,WordPress。一套折腾下来,人都累死。如果想要服务高可用,我需要掌握服务器/数据库运维、WordPress 配置等等一系列的知识,其中任何一环出现问题,都会让我的站点跑不起来。

而现在,服务器、数据库都不用我操心了,每一个 SaSS 服务都能保证高可用,这是付费的结果。将那些乱七八糟的"脏活"交给专业的人去做。这使得开发可以更加关注应用本身的设计,带来更好的使用体验,也能提高开发效率。这种趋势也十分符合 Unix 哲学和社会分工的理论。

Do One Thing and Do It Well

使用服务远比自建要好,除非服务达不到要求。这就跟造轮子一样,如果有现成的轮子,为什么不用呢?请把专门的事情交给专业的人去做。绝大多数公司都达不到 AWS 的体量,没必要什么都自己整一套,为什么不试试神奇的 AWS(或同类服务) 呢,是认为自己公司能活得比 AWS 更久嘛。

Serverless 的趋势对个人开发者是十分友好的。它降低了运维成本,提高了开发效率,从 idea 到产品,可以快速试错。专注精力投入到产品的设计和交互上,赢取更多用户的青睐。

参见

  1. 技术雷达 vol 21

https://assets.thoughtworks.com/assets/technology-radar-vol-21-cn.pdf

  1. gatsby-starter-notion 仓库

https://github.com/mayneyao/gatsby-starter-notion

  1. gine-blog

https://gine.me/

  1. Phos 仓库

https://github.com/mayneyao/phos

  1. notabase 仓库

https://github.com/mayneyao/notabase

  1. gatsby-source-notion-database 仓库

https://github.com/mayneyao/gatsby-source-notion-database