为 Hugo 博客集成 Netlify CMS
为什么需要 Netlify CMS
Netlify CMS 主要是解决了,随时随地打开浏览器写markdown博客的问题,同时它自动处理了图片上传等问题。
简单来说:
Netlify CMS = web 版的 markdown 文件管理器 + 自动图片上传并插入markdown代码 + 在web浏览器写markdown并自动推送到git仓库构建 ....
编辑器可以在富文本(所见即所得)和 Markdown 方式之间切换。 Markdown模式没有语法高亮显示,编辑起来略不方便。同时,切到 Markdown编辑模式后,编辑器的那些按钮都变灰不可用了。
Netlify CMS 只是附加功能,你完全可以在本地直接打开 NeoVim 或者 Emacs 写博客,然后用 Git push 发布文章。
代码编辑器可以自动折叠和伸展,支持选择语言,同时还支持选择是 emacs
/ sublime
还是 vim
编辑模式.
插入图片也非常方便,只是有一点,对于 Hugo Page Bundles 是不支持的,因此图片只能是集中上传到一个目录下(也就是配置文件中指定的 media_folder
路径)。
上传文件存相对目录 和 page bundle 支持,官方正式文档里并没有说明有这个功能。后来老灯发现这些新功能在beta版已经可用了 (beta 版的文档里有说明)。
beta 版的(最新版代码)可以去这里取: https://www.jsdelivr.com/package/npm/netlify-cms
由于是开源的,因此也可以在这查看changelog
部署方法
需要创建一个admin
目录,里面放一个index.html
文件作为后台管理的入口。 由于这个文件实际上也是要deploy到静态博客的,因此,我们要放在Hugo的 static
目录下。
static/admin/index.html
内容如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Blog Manager</title>
<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>
</head>
<body>
<!-- Include the script that builds the page and powers Netlify CMS -->
<!-- https://www.jsdelivr.com/package/npm/netlify-cms -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/netlify-cms.min.js"></script>
</body>
</html>
static/admin/config.yml
内容如下:
# https://www.netlifycms.org/docs/add-to-your-site/
backend:
name: git-gateway
branch: main # Branch to update (optional; defaults to master)
squash_merges: true # beta feature
# when using the default proxy server port
# Run npx netlify-cms-proxy-server from the root dir of the repo
local_backend: true
# 编辑工作流程
publish_mode: editorial_workflow
# 全局静态文件上传目录
media_folder: "static/img/uploads" # Media files will be stored in the repo under images/uploads
public_folder: "/img/uploads" # The src attribute for uploaded media will begin with /images/uploads
media_folder_relative: true
collections:
- name: "post" # Used in routes, e.g., /admin/collections/blog
label: "Post" # Used in the UI
folder: "content/post" # The path to the folder where the documents are stored
path: '{{slug}}/index' # beta feature
media_folder: ''
public_folder: ''
# adding a nested object will show the collection folder structure
nested:
depth: 100 # max depth to show in the collection tree
summary: '{{title}}' # optional summary for a tree node, defaults to the inferred title field
# adding a meta object with a path property allows editing the path of entries
# moving an existing entry will move the entire sub tree of the entry to the new location
meta: { path: { widget: string, label: 'Path', index_file: 'index', hint: 'markdown文件路径, 对于page bundle, 如 "一级目录/二级目录/page-bundle目录/index.md", 只需要填写 "一级目录/二级目录/page-bundle目录",不
要忘记填写page-bundle目录' } }
create: true # Allow users to create new documents in this collection
slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
fields: # The fields for each document, usually in front matter
- {label: "Title", name: "title", widget: "string", hint: "文章标题"}
- {label: "Slug", name: "slug", widget: "string", required: false, hint: "Slug可以是目录,如 linux/archlinux, 此项会作为路径的功能可能会被 path meta 覆盖"}
- {label: "Comments", name: "comments", widget: "boolean", default: true, hint: "true 允许评论, false 禁止评论"}
- {label: "Draft", name: "draft", widget: "boolean", default: true, hint: "草稿不会 build"}
- {label: "Publish Date", name: "date", widget: "datetime"}
- {label: "Featured Image", name: "cover", widget: "image", required: false, hint: "封面图片"}
- {label: "Tags", name: "tags", widget: "list", required: false, "文章标签,用半角逗号分隔"}
- {label: "Body", name: "body", widget: "markdown", hint: "博客正文"}
注意,以上配置用于 Page bundle 模式写博客。如果设置了
slug , 则
slug一定要与
path` 的最后一部分("一级目录/二级目录/page-bundle目录" 中的 "page-bundle目录")相同,不然引入的图片路径就会不对。
这里的 comments
是老灯主题的自定义字段,表示文章是否允许评论。cover
字段也是主题里定义的,表示文章封面图。如果拿过去用,注意稍修改一下适配你自己的主题。
当前这个配置支持:
- 全局静态文件上传到
static/img/uploads
- 仅支持 page bundle 模式写文章(这也是老灯认为唯一适合的文件组织方式)
- 由于支持 page bundle,因此,文章图片上传也是上传到 page bundle 的目录。
- 支持 Netlify CMS 本地仓库模式
本地Git仓库模式
Working with a Local Git Repository https://www.netlifycms.org/docs/beta-features/#working-with-a-local-git-repository
简单启用,只需要在 config.yml
中添加 local_backend: true
即可。 然后 npx netlify-cms-proxy-server
启动 proxy 即可,它默认监听 8081
端口。 然后通过 hugo serve
启动,然后访问 http://localhost:1313/admin/ 即可。
如果要自定义端口,你需要在 Hugo 项目的根目录下新建一 .env
文件,内容如下:
PORT=8082
然后更新 config.yml
中的 local_backend
对象配置:
backend:
name: git-gateway
local_backend:
# when using a custom proxy server port
url: http://localhost:8082/api/v1
# when accessing the local site from a host other than 'localhost' or '127.0.0.1'
# allowed_hosts: ['192.168.0.1']
如果需要允许局域网其它电脑访问,可以添加 allowed_hosts
配置。
toubleshoot
关于配置
Bool类型的一定要写true
和 false
, 不要写成了字符串。不然后台会报错:
Error loading the CMS configuration Config Errors: 'collections[0].fields[4].required' should be boolean Check your config.yml file.
参考文档
https://zhuanlan.zhihu.com/p/56319868
https://www.netlifycms.org/docs/add-to-your-site/
https://www.netlifycms.org/docs/widgets/
https://www.netlifycms.org/docs/beta-features/#folder-collections-media-and-public-folder
https://www.netlifycms.org/docs/configuration-options/
其它
关于 Page Bundles 的支持问题,已经有人提issue了,见:
https://github.com/netlify/netlify-cms/issues/1697
https://github.com/netlify/netlify-cms/issues/513
Store Assets Relative to Content (Bundles) #1472
https://github.com/netlify/netlify-cms/issues/1472#issuecomment-557927885
Hi everyone ! Does anyone know if this feature is implemented? This is the only thing preventing us from using Netlify CMS in our project... and the documentation is not clear on what the option
media_folder_relative: true
allows to do. Thanks for the help :)
https://github.com/netlify/netlify-cms/issues/2696#issuecomment-614544868
Closing as media_folder_relative
was removed in favour of https://www.netlifycms.org/docs/beta-features/#folder-collections-media-and-public-folder
https://github.com/netlify/netlify-cms/issues/3227
https://github.com/netlify/netlify-cms/issues/1472#issuecomment-559376878
Latest code on master branch (not published yet to beta) lets you do:
slug: 'index'
path: '{{title}}/{{slug}}'
to save a file under title/index.md
for example.
Next step will be to store images with the content.