为什么使用 Strapi 而不使用 Contentful ?
Contentful 是一个 SaaS 服务(可以理解为公有云)的 CMS,这这意味着 CMS 的托管、安全性、性能、成本、定制等方面会受到诸多限制。目前公司各产品线官网的 CMS 基本使用的是 Contentful,从各方面体验来看至少存在下列问题:
构建时间较长且优化空间有限
由于目前各环境(包括本地、测试、生产)构建流程均是在前端使用gatsby-source-contentful
插件先在 Contentful 上拉取所需模块的内容,再将其进行打包构建。具体来说,获取数据的时间会受到以下几个因素的影响:
- 内容数量:当 Contentful 中的内容数量增加时,需要花费更多的时间来获取和处理数据。特别是在首次加载时,插件需要检索所有内容,并转换成 Gatsby 节点,这可能会花费一定的时间。
- 服务器响应时间:如果 Contentful 服务器响应较慢,可能会导致获取数据的时间变长。这取决于服务器的负载和网络连接的质量。比如,如果开发人员无法流畅的与 Contentful 服务器建立连接,则容易导致构建失败。
- 本地环境和硬件:使用者的本地开发环境或部署环境的性能和硬件配置也可能会影响数据获取的时间。较慢的硬盘驱动器或较低的内存容量可能会导致较长的加载时间。比如,开发人员使用的是 Windows 系统而不是 Mac 系统、Gitlab 所安装的服务器性能相对不高导致的触发的 CI/CD 流程执行速度较低。
虽然 Contentful 也提供直接请求接口返回的方法(包括 REST API 和 GraphQL API ),但受限于中国大陆地区特殊的网络环境和内容控制的法例,该方法需要在位于境外的 Contentful 服务器上拉取相关内容,且没有中国大陆地区的 CDN 节点,不能正规和流畅进行使用。
无论是开发人员启动项目进行开发或是推送新的git commit
触发 Gitlab CI/CD 流程进行构建,还是运营人员进行内容的编辑后保存触发 Webhook 进行构建,都受拉取所需模块的内容这一流程影响,优化空间有限,无法达到 0ms 运行时;运营人员进行内容的编辑后保存,进行包括拉取内容过程的构建及部署,需要等待至少几分钟,无法即时看到修改效果,大大降低工作效率及操作体验。
Strapi 提供 GraphQL API(需在服务端安装@strapi/plugin-graphql
插件),且由于是自托管 CMS(可以理解为私有化),可以不需要在前端的 Gatsby 项目使用gatsby-source-strapi
插件在构建时拉取内容而支持实时使用 GraphQL API 获取数据(一般在前端也需要安装 GraphQL API 相关插件,如graphql-request
,在 Gatsby 项目中有gatsby-source-graphql
但官方不建议使用),若不考虑营销的 SEO 需求,理论上可以将「构建时拉取内容」这一步骤进行完全省略。且 REST API 和 GraphQL API 的使用场景其实是互有补充(比如说,在获取当前文章的上一篇或下一篇文章的需求场景,REST API 需要多个接口进行异步请求及等待,而 GraphQL API 只需一个接口即可,例:
php
nextNews: newslist(
sort: "publishedAt:DESC"
pagination: { limit: 1 }
filters: { id: { lt: $currentNewsId } }
) {
data {
id
attributes {
title
}
}
}
),可根据实际情况灵活选用。
可定制度较低
Contentful 控制台操作界面原生仅支持英文,不支持包括中文在内的多语言界面设置,也不支持自定义管理面板,导致运营人员交互体验不够友好;Contentful 并非开源,不支持根据需要自定义服务端代码,导致开发人员对 CMS 的可改造程度受到限制;Contentful 的插件系统相比 Strapi 也并不够活跃,也并非完全开源。
价格成本较高且使用者所具有的权限较少
Contentful 当前价格(2023 年 8 月 7 日):
Strapi 当前价格(SELF-HOSTED 即自托管方案,2023 年 8 月 7 日):
从实际日常工作的使用体验来说,Contentful 免费社区方案只支持 5 个使用者账号,只支持两个区域的设置,会带来诸多内容管理上的不便之处;两个免费社区方案相比,Contentful 使用者所具有的权限相对较少。至于收费方案,Contentful 从 $300/month 起计且使用者仍不具备较多的权限,而 Strapi 需要根据具体需求咨询销售,但从 Strapi 的云方案从 $90/month 起计来看,Strapi 的总体收费计划也是相对较低。
其它
Strapi 是 Github 上目前 Star 数量最多的 CMS。
Strapi 具体配置
本地环境安装
在本地环境中安装 Strapi 项目可参考官方文档 docs.strapi.io/dev-docs/in... ,这里需要注意的是,大部分项目都需要多人协作,所以建议不要使用默认的轻量级的 SQLite 数据库,而是使用 MySQL 或 PostgreSQL。
Docker 容器部署
如需要使用 Docker 容器协助部署 Strapi 项目,可参考官方文档 docs.strapi.io/dev-docs/in... 。需要注意的是,如果使用的数据库是 SQLite 且数据库文件位于容器内,在每次部署新容器前需要注意数据的导出及导入。
使用中文界面语言
在项目的./src/admin/
目录下拷贝app.example.js
的代码,新建app.js
并对这两行
arduino
'zh-Hans',
'zh',
取消注释,可支持使用简体中文及繁体中文。之后在管理界面中左下角的用户名 -> 个人资料 -> 体验 -> 界面语言里可进行当前账号的界面语言设置。
创建及管理内容
可参照官网的 Quick Start Guide docs.strapi.io/dev-docs/qu... 中的 🛠 Part B: Build your content 进行诸如集合类型、条目、角色与权限、API 的创建、修改或调用。
REST API
使用 Strapi 提供的 REST API 可参照官方文档 docs.strapi.io/dev-docs/ap... 。需要注意的是,默认情况下,REST API 不会填充任何关系、媒体字段、组件或动态区域。如需上述字段,需要使用populate
参数 来填充特定字段。
GraphQL API
使用 Strapi 提供的 GraphQL API 需要安装@strapi/plugin-graphql
,具体使用可参照官方文档 docs.strapi.io/dev-docs/ap... 。在本地环境打开 http://localhost:1337/graphql 可帮助编写 GraphQL 的查询(Queries)与更新(Mutations)语句。
使用./config/server.js
文件进行服务器配置
url
字段可以进行服务器的公共 url 配置。可使用环境变量来进行诸如本地、测试、线上环境的区别配置,在执行 strapi start
或strapi develop
前可先执行诸如export NODE_ENV=production
的命令进行环境变量的改变。其它字段可参照文档 docs.strapi.io/dev-docs/co... 。
Nginx 代理的配置
大致分为「子域」及「子文件夹路径前缀统一」两种,需要在./config/server.js
中及 Strapi 服务所部署服务器的 Nginx 配置文件里根据具体选用哪种方案来进行配置。可参考官方文档 docs.strapi.io/dev-docs/de... 。
OSS 资源的 CDN 配置
可以在 Strapi Market 下的 Providers 清单里 market.strapi.io/providers 选用合适的插件进行安装,其中国内插件提供商目前有阿里云和七牛云;另外也可编写自定义插件结合诸如 MinIO 之类的私有化 OSS 服务,再自行选择 CDN 服务提供商。
阿里云插件
文档 market.strapi.io/providers/s... ,需要注意的是,该插件由社区开发者维护,而 Strapi 官方维护的插件包括 Amazon S3(境内服务器未验证是否可用)、Cloudinary(无境内服务器)在境内使用可能存在一定的问题,Local(本地服务器)不支持存储在 OSS 服务中。
使用阿里云插件进行 OSS 资源的 CDN 配置,需要注意如下几个关键操作:
- 开启阿里云 CDN 及 OSS 服务
- 配置静态资源域名在 OSS 服务中添加对应 Bucket
- 对新添加 Bucket 绑定静态资源域
- 添加 CDN 加速 OSS 服务的配置
- 添加新的 DNS 域名解析实例
- 添加 CNAME 解析绑定 CDN
- 开启若干个 CDN 缓存自动刷新的开关
- 为静态资源域名申请及配置 SSL 证书
解决媒体库 CSP 问题
需要在 ./config/middlewares.js
的strapi::security
中间件作如下扩展配置:
json
{
name: "strapi::security",
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
"connect-src": ["'self'", "https:"],
"img-src": [
"'self'",
"data:",
"blob:",
"dl.airtable.com", // strapi marketplace
"your.oss.com", // alioss images
],
"media-src": ["'self'", "data:", "blob:", "https://your.oss.com"],
upgradeInsecureRequests: null,
},
},
},
},
该扩展配置是基于 koa-helmet 的,Strapi 官方的配置可参考 docs.strapi.io/dev-docs/co... ,koa-helmet 配置可参考 helmetjs.github.io/#get-starte... 。
富文本编辑器
待续