⤴Top⤴

JAMstack

博客分类: 前端

JAMstack

JAMstack

什么是 JAMstack

JAMstack 是一种现代制作网站方法,提供更好的性能,更高的安全性,更低的扩展成本以及更好的开发人员体验。其中的 JAM 代表了 JavaScript, API & Markup:

A modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup

JAMstack 有很多好处:

  1. 更快的性能 - 通过 CDN 提供预先构建的标记文件和资源文件(assets)
  2. 更安全 - 无需担心服务器或数据库的漏洞
  3. 更便宜 - 托管静态文件很便宜甚至免费
  4. 更好的开发体验 - 前端开发人员可以专注于前端,不必依赖于传统的一体化架构
  5. 可扩展性 - 如果产品在传播时突然拥有许多活跃用户,CDN 将无缝补齐所需资源

JAMstack 的最佳做法:

  1. 使用 CDN - 提供了更好的性能和更轻松的可扩展性
  2. 原子部署 - 每个部署都是站点的完整快照,可保证全球网站版本的一致
  3. 缓存失效 - 上传新构建的版本后,CDN 使缓存无效,可使新版本即时生效
  4. 版本控制 - 把代码放到 Git,可记录每个文件的历史更改,方便协作和追溯
  5. 自动构建 - 当需要新构建时,webhooks 会通知服务器,构建后实时更新 CDN 和站点

JAMstack 构建流程

如何构建

静态站点生成器

大部分 JAMstack 静态网站都需要静态站点生成器,我们可以根据我们的需求随便选一个。之前博客中介绍的 Jekyll 就是 SSG 之一,还有 Gatsby 之类的,更多静态站点生成器可以查看这里 👈

部署平台

选择可以部署的平台,比如 Github Pages 或者 Netlify(看清楚了,不是网飞 Netflix 😳) 等,更多平台可以参考这里 👈

动态部分

静态网站不是真的就是静态的,你可以通过一些服务来进行动态数据的传输。下面举几个例子:

  1. 自定义函数 - 可以抽象函数为可复用的 API,如 AWS lambda functions or Netlify Functions
  2. 自定义数据 - 很多场景你需要存储一些数据,可以用到 FaunaDB Serverless GraphQL
  3. 评论功能 - 提供评论功能,如 disqus 或者 gitalk 等
  4. 还有很多其他功能模块,比如搜索、支付、在线聊天等,更多可以参考这里 👈

我们可以在官方网站找到一些示例,也可以找到丰富多彩的 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 等,更多可以参考这里 👈

headless CMS

Jekyll + Strapi 实战

之前有说过我的博客用的站点生成器就是 Jekyll,这里我介绍下如何用 Strapi headless CMS 来为站点提供 API 数据支持。大体上其实分为三个步骤:

  1. 安装和配置 Strapi,启动
  2. 启动 Jekyll 站点
  3. 通过一些依赖和配置,让 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:

Restaurant

二、启动 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,里面就包含了自动生成的页面。这样之后,我们就可以访问详情页啦。

以上只是列举一些关键步骤,更多的细节和配置可以直接参考这篇文档 👈

参考连接

  1. New to JAMstack? Everything You Need to Know to Get Started
  2. What is a Headless CMS? By Chris Coyier
  3. Building a static blog using Jekyll and Strapi By Pierre Burgy