JAMstack
什么是 JAMstack
JAMstack 是一种现代制作网站方法,提供更好的性能,更高的安全性,更低的扩展成本以及更好的开发人员体验。其中的 JAM 代表了 JavaScript, API & Markup
:
- JavaScript - 通过 JavaScript 处理动态功能,不限使用哪个框架或库
- API - 服务器端操作被抽象为可重用的 API,并使用 JavaScript 通过 HTTPS 访问,可以是第三方服务或自定义的功能
- Markup - 网站是作为静态 HTML 文件提供的。可以使用静态站点生成器(static site generator)从源文件(例如 Markdown)生成
A modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup
JAMstack 有很多好处:
- 更快的性能 - 通过 CDN 提供预先构建的标记文件和资源文件(assets)
- 更安全 - 无需担心服务器或数据库的漏洞
- 更便宜 - 托管静态文件很便宜甚至免费
- 更好的开发体验 - 前端开发人员可以专注于前端,不必依赖于传统的一体化架构
- 可扩展性 - 如果产品在传播时突然拥有许多活跃用户,CDN 将无缝补齐所需资源
JAMstack 的最佳做法:
- 使用 CDN - 提供了更好的性能和更轻松的可扩展性
- 原子部署 - 每个部署都是站点的完整快照,可保证全球网站版本的一致
- 缓存失效 - 上传新构建的版本后,CDN 使缓存无效,可使新版本即时生效
- 版本控制 - 把代码放到 Git,可记录每个文件的历史更改,方便协作和追溯
- 自动构建 - 当需要新构建时,webhooks 会通知服务器,构建后实时更新 CDN 和站点
如何构建
静态站点生成器
大部分 JAMstack 静态网站都需要静态站点生成器,我们可以根据我们的需求随便选一个。之前博客中介绍的 Jekyll 就是 SSG 之一,还有 Gatsby 之类的,更多静态站点生成器可以查看这里 👈
部署平台
选择可以部署的平台,比如 Github Pages 或者 Netlify(看清楚了,不是网飞 Netflix 😳) 等,更多平台可以参考这里 👈
动态部分
静态网站不是真的就是静态的,你可以通过一些服务来进行动态数据的传输。下面举几个例子:
- 自定义函数 - 可以抽象函数为可复用的 API,如 AWS lambda functions or Netlify Functions
- 自定义数据 - 很多场景你需要存储一些数据,可以用到 FaunaDB Serverless GraphQL
- 评论功能 - 提供评论功能,如 disqus 或者 gitalk 等
- 还有很多其他功能模块,比如搜索、支付、在线聊天等,更多可以参考这里 👈
我们可以在官方网站找到一些示例,也可以找到丰富多彩的 JAMstack 主题 👈
headless CMS
JAMstack 静态网站可以通过 CMS(Content Management System) 内容管理系统来进行管理,比如无头(headless) CMS。当 CMS 上触发某个变动时,会重新自动构建新的网站版本并将其部署为静态资源。
那么问题来了,headless CMS 与传统的 CMS 到底有啥区别呢?
传统的 CMS 内容管理方法是将所有内容集中在一起,包括内容、图片和其他一些资源,这使得内容构建和展示完全耦合,比如 Wordpress,Drupal,Joomla 等。虽然传统上它们都是 CMS,每次提供服务时都必须与网站一起托管和构建。但 headless CMS 不在乎将内容投放到何处,它不再附加到前端,并且可以在任何平台上查看内容。这种方法的优点很大,并且可以与 JAMstack 站点一起使用,与传统站点相比,JAMstack 站点更安全,更方便地进行扩展。如 Strapi、Ghost、Jekyll Admin 等,更多可以参考这里 👈
Jekyll + Strapi 实战
之前有说过我的博客用的站点生成器就是 Jekyll,这里我介绍下如何用 Strapi headless CMS 来为站点提供 API 数据支持。大体上其实分为三个步骤:
- 安装和配置 Strapi,启动
- 启动 Jekyll 站点
- 通过一些依赖和配置,让 Jekyll 能正常调用到 Strapi 提供的 API
一、安装和配置 Strapi
Strapi 直接可以参考官网的安装步骤,已经巨详细了,一般情况下这里都不会有什么问题,但是有几个地方需要注意下,我们首先需要安装:
yarn create strapi-app my-project --quickstart
# or
npx create-strapi-app my-project --quickstart
--quickstart
参数这里会默认用到轻便的 SQLite 数据库,你可以不使用该参数,但是会要求你选择所需的数据库,并且在你使用上述命令构建前,就必须让它能够在本地运行。比如 MongoDB,你可以参照这里来进行安装和选择。
安装完成后会自动开启 Strapi 项目,这时候需要你在打开的网页中注册 Administrator 用户,它将拥有所有的访问和操作权限。之后便可以去创建 Content Type,具体可以参照官网步骤。
需要注意的是,默认情况下,Strapi 会通过权限来管控发布的 Content Type,也就是说你需要为你所创建的 Content Type 来下放权限,可以在 Roles & Permissions
菜单中为他们勾选对应的操作权限,如 find、findone 等。而且在你创建了比如名为 Restaurant 的 Content Type 时,会自动创建对应路由来访问数据,比如 http://localhost:1337/restaurants
,如果没有权限的话将返回 403:
二、启动 Jekyll 站点
这个就没什么说了,我们把项目启动即可,可以直接参考下之前的博客 👈
三、配置 Jekyll 使其能访问 Strapi API
我们这里使用了 jekyll-strapi 插件,具体配置方式如下,首先在 gemfile 添加对应 gem:
# If you have any plugins, put them here!
group :jekyll_plugins do
gem "jekyll-feed", "~> 0.6"
gem "jekyll-strapi", "~> 0.1"
end
安装这些 gem,然后将他们添加到 _config.yml
配置文件中:
gem install jekyll-strapi
# _config.yml
plugins:
- jekyll-feed
- jekyll-strapi
之后我们运行 bundle
来安装这些依赖,剩下的我们需要做一些数据访问的配置:
# _config.yml
strapi:
# Your API endpoint (optional, default to http://localhost:1337)
endpoint: http://localhost:1337
# Collections, key is used to access in the strapi.collections
# template variable
collections:
# Example for a "posts" collection
posts:
# Collection name (optional). Used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
type: posts
# Permalink used to generate the output files (eg. /posts/:id).
permalink: /posts/:slug/
配置之后,我们就可以访问到全局变量 strapi,并且通过 strapi.collection.posts
来访问到我们所创建的 posts 数据,如果我们在模板中使用的话,可以参考下面:
<div class="home">
<h1 class="page-heading">Posts</h1>
{ %- if strapi.collections.posts.size > 0 -% }
<ul class="post-list">
{ %- for post in strapi.collections.posts -% }
<li>
<span class="post-meta"> by </span>
<h3>
<a class="post-link" href="">
</a>
</h3>
<!-- Display an excerpt of the article -->
<p>
</p>
</li>
{ %- endfor -% }
</ul>
{ %- endif -% }
</div>
这里有个地方需要注意的是,在我们如上配置了之后,试着启动 Jekyll 项目时,可能会发现有个报错: The Strapi server sent a error with the following status: 404. Please make sure it is correctly running.
。感谢这里提供了帮助,试着把 Jekyll 和插件版本升级之后就可以了:
gem "jekyll", "~> 3.8.5"
[...]
group :jekyll_plugins do
gem "jekyll-feed", "~> 0.12"
# github 这里的参数确保了最新修复 bug 的版本,而这个 bug 就是 Can't convert fixnum into String
gem 'jekyll-strapi', github: 'strapi/jekyll-strapi'
end
上面这些步骤我们其实还只是配置了首页,在我们能够正常访问到 strapi api 获取数据的前提下,我们接下来要为他们创建详情页,首先我们在 _layouts
目录下新建 post.html
来创建模板,配置项我们需要稍作修改:
# _config.yml
strapi:
# Your API endpoint (optional, default to http://localhost:1337)
endpoint: http://localhost:1337
# Collections, key is used to access in the strapi.collections
# template variable
collections:
# Example for a "posts" collection
posts:
# Collection name (optional). Used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
type: posts
# Permalink used to generate the output files (eg. /posts/:id).
permalink: /posts/:slug/
layout: post.html
# Generate output files or not (default: false)
output: true
我们可以看到只是新增了 layout 和 output 选项,就是为了要让 Jekyll 利用指定模板自动去为 post 生成新的详情页。重启 Jekyll 项目后,我们可以在 _site
目录下看到自动生成的新目录 posts
,里面就包含了自动生成的页面。这样之后,我们就可以访问详情页啦。
以上只是列举一些关键步骤,更多的细节和配置可以直接参考这篇文档 👈
参考连接
- New to JAMstack? Everything You Need to Know to Get Started
- What is a Headless CMS? By Chris Coyier
- Building a static blog using Jekyll and Strapi By Pierre Burgy
Gitalking ...