Hexo Netlify CMS 静态博客管理与写作

引言

我们都知道,Hexo 是一个静态部署博客的框架,优点在于速度快,成本低(无需服务器),缺点在于繁琐,你每次更新文章都需要去改代码,再部署推送,修改配置也是如此,你不能像WordPress一样直接在后台修改配置并使它生效。

不过有很多教程可以让你无需繁琐的部署,只管推送代码,通过GitHub Actions,travis-ci,Vercel,Netlify 等都可以便捷的进行博客的部署,只管写代码然后推送就好,类似的教程有非常多,在此就不再重复介绍。那么,我们是否可以在此基础上,更加便捷的进行静态博客的写作和管理?答案是可以的。

我们可以通过将博客部署到 Netlify,并使用 Netlify cms 来做到这一点。

首先,我们来了解一下配置完之后可以做到哪些事情?

  • 在线新建,编辑,预览,删除博客文章
  • 支持文章草稿,工作流
  • 支持对博客图片的管理
  • 支持在线修改博客配置,例如对首页顶部图的修改,友链的修改

图片预览

在线演示

为了更加直观,原作者做了一个已经配置完毕的博客,你可以在线体验上述功能 👉点我查看

简单说明

下面我将会以 Hexo + NexT 主题做演示,并配置 Fluid 主题 的友链功能,达到在线编辑预览友链的目的,但此方法不仅仅只适用于 Fluid 主题 的友链功能,其他各类主题也可以通过此方法达到在线修改配置的目的,只要你配置完成,几乎可以修改所有配置项。包括但不限于以下类型的文件yml、yaml、toml、json、md、markdown、html具体请查看 👉Netlify cms 文档。

具体配置

Netlify cms 使用的前提条件是你必须将博客部署到 Netlify 上。因为网上有很多部署教程,这里不再重复。

可以部署到其他托管网站上,但需要自行修改

具体可以查看:

准备工作

在部署完成后,你需要开启 Identity

进入设置中:

Registration preferences 修改为 Invite only 此项为是否开启注册,默认是开启注册。修改为 Invite only 后表示仅受邀请的用户可以注册,当然此项你可以在自己注册完毕之后再行修改。

下滑找到 Git Gateway 并开启。

至此准备工作完成。

修改博客配置

在博客根目录中找到 _config.yml 并修改,这一步是跳过文件夹渲染,不然后面会出错:

skip_render: admin/*

在博客 source 文件夹中,创建 admin 文件夹,并新建两个文件 index.htmlconfig.yml

index.html 中添加以下内容:

<!doctype html>
<html>

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="x-UA-Compatible" content="IE=Edge">
<meta name="apple-mobile-web-app-status-bar-style" content="white" />
<script type="text/javascript" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
<title>Fl0w3r</title>
</head>

<body>
<script defer="true" src="https://cdn.jsdelivr.net/npm/netlify-cms@2/dist/netlify-cms.js"></script>
</body>

</html>

因为涉及到 Jsdelivr 加速,所以我选择把两个 js 源文件下载到 theme\next\source\js 中:

<!doctype html>
<html>

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="x-UA-Compatible" content="IE=Edge">
<meta name="apple-mobile-web-app-status-bar-style" content="white" />
- <script type="text/javascript" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
+ <script type="text/javascript" src="js/netlify-identity-widget.js"></script>
<title>Fl0w3r</title>
</head>

<body>
- <script defer="true" src="https://cdn.jsdelivr.net/npm/netlify-cms@2/dist/netlify-cms.js"></script>
+ <script defer="true" src="js/netlify-cms.js"></script>
</body>

</html>

config.yml 中添加以下折叠内容:

backend:
name: git-gateway # https://github.com/netlify/netlify-cms
branch: main # 要更新的分支(可选;默认为主分支)

# This line should *not* be indented
publish_mode: editorial_workflow

# This line should *not* be indented
media_folder: "source/images/uploads" # 媒体文件将存储在图片/上载下的Repo中。
public_folder: "/images/uploads" # 上传的媒体的src属性将以/images/uploads开头。

site_url: https://www.myql.xyz # 网站网址
display_url: https://www.myql.xyz # 显示网址

locale: "zh_Hans" # 语言环境 https://github.com/netlify/netlify-cms/tree/master/packages/netlify-cms-locales/src

collections: # https://www.netlifycms.org/docs/configuration-options/#collections
- name: "posts" # 在路由中使用,例如:/admin/collections/blog。
label: "Post" # 在用户界面中使用
folder: "source/_posts" # 存储文件的文件夹的路径。
create: true # 允许用户在这个集合中创建新的文件。
fields: # 每份文件的字段,通常是前面的内容。
- {
label: "顶部图",
name: "banner_img",
widget: "image",
required: false,
}
- {
label: "文章封面",
name: "index_img",
widget: "image",
required: false,
}
- { label: "文章排序", name: "sticky", widget: "number", required: false }
- { label: "标题", name: "title", widget: "string" }
- {
label: "发布日期",
name: "date",
widget: "datetime",
format: "YYYY-MM-DD HH:mm:ss",
dateFormat: "YYYY-MM-DD",
timeFormat: "HH:mm:ss",
required: false,
}
- {
label: "更新日期",
name: "updated",
widget: "datetime",
format: "YYYY-MM-DD HH:mm:ss",
dateFormat: "YYYY-MM-DD",
timeFormat: "HH:mm:ss",
required: false,
}
- { label: "标签", name: "tags", widget: "list", required: false }
- { label: "分类", name: "categories", widget: "list", required: false }
- { label: "关键词", name: "keywords", widget: "list", required: false }
- { label: "摘要", name: "excerpt", widget: "list", required: false }
- { label: "内容", name: "body", widget: "markdown", required: false }
- {
label: "永久链接",
name: "permalink",
widget: "string",
required: false,
}
- {
label: "评论",
name: "comments",
widget: "boolean",
default: true,
required: false,
}

- name: "pages"
label: "Pages"
files:
- file: "source/about/index.md"
name: "about"
label: "关于"
fields:
- { label: "标题", name: "title", widget: "string" }
- { label: "内容", name: "body", widget: "markdown", required: false }
- {
label: "评论",
name: "comments",
widget: "boolean",
default: true,
required: false,
}

# 如果你不是fluid主题,请删除以下配置,或者对文件路径及字段进行修改
# - name: "settings"
# label: "settings"
# files:
# - file: "source/_data/fluid_config.yml"
# name: "fluid"
# label: "fluid主题配置"
# editor:
# preview: true # 是否开启编辑预览
# fields:
# - label: "首页"
# name: "index"
# widget: "object"
# collapsed: true # 是否折叠显示
# fields:
# - label: "顶部图"
# name: "banner_img"
# widget: "image"
# - label: "高度"
# name: "banner_img_height"
# widget: "number"
# - label: "文章页"
# name: "post"
# widget: "object"
# collapsed: true
# fields:
# - label: "顶部图(默认)"
# name: "banner_img"
# widget: "image"
# - label: "高度"
# name: "banner_img_height"
# widget: "number"
# - label: "文章封面图(默认)"
# name: "default_index_img"
# widget: "image"
# - label: "归档页"
# name: "archive"
# widget: "object"
# collapsed: true
# fields:
# - label: "顶部图"
# name: "banner_img"
# widget: "image"
# - label: "高度"
# name: "banner_img_height"
# widget: "number"
# - label: "分类页"
# name: "category"
# widget: "object"
# collapsed: true
# fields:
# - label: "顶部图"
# name: "banner_img"
# widget: "image"
# - label: "高度"
# name: "banner_img_height"
# widget: "number"
# - label: "标签页"
# name: "tag"
# widget: "object"
# collapsed: true
# fields:
# - label: "顶部图"
# name: "banner_img"
# widget: "image"
# - label: "高度"
# name: "banner_img_height"
# widget: "number"
# - label: "关于页"
# name: "about"
# widget: "object"
# collapsed: true
# fields:
# - label: "顶部图"
# name: "banner_img"
# widget: "image"
# - label: "高度"
# name: "banner_img_height"
# widget: "number"
# - label: "友链页面"
# name: "links"
# widget: "object"
# collapsed: true
# fields:
# - label: "顶部图"
# name: "banner_img"
# widget: "image"
# - label: "高度"
# name: "banner_img_height"
# widget: "number"
# - label: "项目"
# name: "items"
# widget: "list"
# fields:
# - {
# label: "网站名称",
# name: "title",
# widget: "string",
# required: false,
# }
# - {
# label: "网址描述",
# name: "intro",
# widget: "string",
# required: false,
# }
# - {
# label: "网站地址",
# name: "link",
# widget: "string",
# required: false,
# }
# - {
# label: "网站图片",
# name: "avatar",
# widget: "image",
# required: false,
# }

请注意,这里我对 Fluid 主题进行了配置,例如 banner_imgindex_img 等项目,不能正常使用请删除。如果你不是 Fluid 主题,请根据实际情况对 source\admin\config.yml 配置进行修改。

参考文章