
1. 项目概述为什么选择这套“在线构建”方案最近几年静态博客又火了起来但玩法已经和十年前大不相同。以前我们可能是本地写好 Markdown运行hexo g生成静态文件再手动 FTP 传到服务器。现在这套流程显得有点“古典”了。今天我想分享的是一套我实践下来非常顺手的现代化静态博客部署方案Hexo Netlify-CMS Vercel并且是在线构建模式。简单来说这套方案的核心价值在于你只需要一个浏览器和一个 Git 仓库就能完成从写作、管理到部署、发布的完整流程完全摆脱本地开发环境的束缚。对于非技术背景的内容创作者或者像我这样懒得在每台电脑上都配 Node.js 环境的技术博主来说这简直是福音。它的工作流是这样的你在 Netlify-CMS 提供的友好后台里写文章、上传图片内容会自动提交到 GitHub 仓库Vercel 会监听这个仓库的变化一旦有新的提交就自动拉取代码、在线安装依赖、运行hexo generate命令构建静态站点最后将生成的 HTML/CSS/JS 文件部署到全球 CDN 上。对比传统的纯 Hexo 本地构建这套方案有几个明显的优势。首先是内容管理体验的飞跃。Netlify-CMS 提供了一个类似 WordPress 的图形化后台支持富文本编辑和 Markdown 双模式还能直接拖拽上传图片并自动处理路径这对不熟悉命令行和 Git 的协作者极其友好。其次是部署的极致简化与高性能。Vercel 不仅提供免费的自动化构建和部署其背后的全球边缘网络CDN能确保你的博客在全球任何地方都能快速打开。最后是真正的“随处可写”。你可以在办公室的电脑、家里的平板甚至手机浏览器上打开 CMS 后台写稿写完点击发布剩下的构建、部署全自动完成内容即刻上线。接下来我会把这套方案的搭建过程、核心配置、以及我踩过的一些坑毫无保留地拆解给你看。无论你是想给自己搭个新博客还是想为团队建立一个轻量级的内容发布系统这套组合拳都值得一试。2. 方案核心思路与工具选型解析2.1 为什么是 Hexo Netlify-CMS Vercel这个组合并非随意拼凑每个组件都承担着不可替代的角色共同构成了一个完整、高效且低成本的静态内容发布系统。Hexo是我们的静态站点生成器。选择它是因为其生态成熟、主题丰富、生成速度快并且对 Markdown 的支持非常友好。它负责最核心的“转换”工作将你写的 Markdown 文章、配置的模板主题编译成一堆纯粹的静态文件HTML, CSS, JS。这是整个系统的基石。Netlify-CMS是我们的内容管理后台。这是实现“在线构建”和“非技术友好”的关键。它是一个单页应用SPA可以直接嵌入你的站点或独立运行。它通过 OAuth 连接到你的 GitHub或 GitLab 等仓库提供一个直观的 UI 来创建、编辑、删除内容文件通常是.md文件。当你点击保存时它实际上是在背后帮你完成了一次git commit和git push。这样内容创作者完全不需要接触 Git 命令或本地文件系统。Vercel是我们的自动化构建与全球分发平台。它监听你的 Git 仓库。当 Netlify-CMS 推送了新内容即产生了新的 Git 提交Vercel 会立刻被触发。它会在其云端服务器上拉取你的仓库代码自动识别为 Hexo 项目或根据你的配置安装所有package.json里的依赖然后执行你预设的构建命令如hexo generate。构建成功后将生成的public文件夹内容部署到其全球边缘网络。Vercel 的智能 CDN、自动 HTTPS、以及近乎实时的部署速度让站点的访问体验和运维成本达到了极佳的平衡。这个工作流的精妙之处在于解耦和自动化。写作CMS、生成Hexo、部署Vercel三个环节通过 Git 这个中间桥梁串联各自独立又紧密协作实现了全流程的自动化。2.2 关键决策在线构建 vs 本地构建这是本方案与传统方式最根本的区别有必要深入聊聊。本地构建是经典模式你在自己的电脑上安装 Node.js、Hexo CLI、Git拉取博客源码安装主题依赖。写新文章时用编辑器打开source/_posts下的.md文件写完后再执行hexo g -d来生成并部署。这种方式要求你有一个配置好的本地环境且所有操作都依赖这台电脑。在线构建则是将“构建”这个环节从本地迁移到了云端Vercel。你的本地电脑甚至不需要安装 Node.js。你的 Git 仓库里存放的是博客的“源代码”Markdown 文章、主题文件、配置文件而不是构建后的“成品”HTML 文件。Vercel 的服务器充当了那个“构建机”每次有内容更新它都会从头开始执行一遍构建流程。在线构建的优势非常明显环境一致性避免了“在我电脑上好好的怎么部署就错了”的问题。Vercel 提供了干净、统一的构建环境。协作便利任何有 CMS 后台权限的人都可以发布内容无需向他要构建后的文件也无需担心他本地的环境问题。释放本地资源尤其是当你的博客很大、主题复杂时构建过程可能耗时较长且占用 CPU/内存。在线构建把这些消耗转移到了云端。当然它也有个小代价构建时间。每次发布需要等待 Vercel 完成拉取、安装、构建、部署的全过程通常需要1-3分钟而不是本地的几秒钟。但对于内容发布来说这个延迟是完全可接受的。注意在线构建意味着你的public文件夹不应该被提交到 Git 仓库通常已在.gitignore中忽略。因为每次构建都会重新生成它提交它只会造成冲突和冗余。3. 前期准备与项目初始化3.1 创建并配置 GitHub 仓库一切始于 Git 仓库。我推荐使用 GitHub因为它与 Netlify-CMS 和 Vercel 的集成最为顺畅。创建新仓库在 GitHub 上创建一个新的公开仓库Public例如my-hexo-blog。选择公开仓库是因为 Vercel 的免费计划对公开仓库支持最好且 Netlify-CMS 的 GitHub OAuth 集成也更简单。如果你坚持要私有仓库Vercel 的 Hobby 计划也支持但某些高级功能可能受限。本地初始化 Hexo可选但推荐为了更方便地进行首次主题安装和基础配置我建议先在本地进行一次初始化。# 在本地电脑上操作仅此一次 npm install -g hexo-cli hexo init my-hexo-blog cd my-hexo-blog npm install执行完后你会得到一个标准的 Hexo 项目结构。此时你可以先挑选并安装一个心仪的主题。比如安装流行的hexo-theme-fluidnpm install --save hexo-theme-fluid然后按照主题文档修改_config.yml文件。完成基础配置后请务必删除public文件夹如果已生成并确认.gitignore文件包含了public/、node_modules/等。关联并推送至 GitHub将本地初始化好的项目推送到你刚创建的 GitHub 仓库。git init git add . git commit -m Initial Hexo project with theme git branch -M main git remote add origin https://github.com/你的用户名/my-hexo-blog.git git push -u origin main至此你的博客源码已经安全地存放在 GitHub 上了。3.2 在 Vercel 上导入并部署项目接下来我们把“构建机”和“托管平台”设置好。登录 Vercel访问 vercel.com 使用你的 GitHub 账号登录。这步授权很重要它让 Vercel 能访问你的仓库。导入项目在 Dashboard 点击 “Add New…” - “Project”然后从列表中找到你刚创建的my-hexo-blog仓库点击 “Import”。配置构建参数这是关键一步。Vercel 通常能自动检测出 Hexo 项目但我们需要确认和微调。Framework Preset确保它选择的是 “Hexo”。如果没有自动识别可以手动选择或保留为 “Other”。Build Command填写hexo generate。这是告诉 Vercel 构建时执行的命令。Output Directory填写public。这是 Hexo 构建后生成的静态文件所在目录Vercel 会把这个目录的内容拿去部署。Install Command默认npm install即可。环境变量暂时跳过目前不需要额外设置直接点击 “Deploy”。部署过程会持续1-3分钟。期间Vercel 会拉取代码、安装依赖、执行构建命令。如果一切顺利部署完成后Vercel 会分配一个*.vercel.app的域名给你。点击这个链接你应该能看到一个基于你当前主题和内容的 Hexo 博客。这证明 Vercel 的自动化构建和托管已经成功。实操心得首次部署后建议你立即去仓库的source/_posts里修改一下hello-world.md文件然后提交。观察 Vercel 的 Dashboard你会看到一次新的构建自动被触发。这个“提交即部署”的自动化流程是后续一切便利的基础。4. 集成 Netlify-CMS打造图形化内容后台现在我们有了自动构建和托管的博客但写文章还得去改 GitHub 里的.md文件这不够友好。接下来接入 Netlify-CMS提供一个可视化后台。4.1 在项目中安装并配置 Netlify-CMSNetlify-CMS 本质上是一套前端文件我们需要把它放到我们博客的源码中并让 Hexo 能将其作为静态文件输出。创建 CMS 配置文件在你的 Hexo 项目根目录下创建一个名为static的文件夹如果不存在然后在static内创建admin文件夹。最后在admin文件夹里创建两个文件index.html和config.yml。 目录结构如下your-hexo-site/ ├── source/ ├── themes/ ├── static/ │ └── admin/ │ ├── index.html │ └── config.yml └── _config.ymlHexo 在构建时会将static目录下的所有文件原样复制到最终输出的public目录的根目录下。这样public/admin/index.html就能被访问到了。编写index.html这个文件是 Netlify-CMS 的入口页面内容几乎是固定的。!DOCTYPE html html head meta charsetutf-8 / meta nameviewport contentwidthdevice-width, initial-scale1.0 / titleContent Manager/title !-- 引入 Netlify CMS 的核心脚本 -- script srchttps://unpkg.com/netlify-cms^2.10/dist/netlify-cms.js/script !-- 对于中国大陆访问可以考虑使用下面的 CDN但需注意版本和稳定性 -- !-- script srchttps://cdn.jsdelivr.net/npm/netlify-cms^2.10/dist/netlify-cms.js/script -- /head body !-- 脚本会自动将 CMS 界面渲染到这个 div 中 -- div idncms-root/div /body /html编写核心config.yml这个文件定义了 CMS 的后台如何工作连接哪个仓库管理哪些内容。这是配置的核心。backend: name: github repo: 你的GitHub用户名/my-hexo-blog # 你的仓库路径 branch: main # 你的默认分支 media_folder: source/images # 上传的图片保存到源码的哪个目录 public_folder: /images # 在最终生成的网站中图片的访问路径前缀 collections: - name: posts # 集合名称对应 Hexo 的“文章” label: Posts folder: source/_posts # 内容文件存储的目录 create: true # 允许在 CMS 中创建新文章 slug: {{year}}-{{month}}-{{day}}-{{slug}} # 文件名模板与 Hexo 的 new_post_name 配置保持一致 fields: - { label: Title, name: title, widget: string } - { label: Publish Date, name: date, widget: datetime, date_format: YYYY-MM-DD, time_format: HH:mm, format: YYYY-MM-DD HH:mm } - { label: Tags, name: tags, widget: list, default: [未分类] } - { label: Categories, name: categories, widget: list } - { label: Body, name: body, widget: markdown }关键点解析backend: 指定使用 GitHub 作为存储后端并指明仓库和分支。media_folder和public_folder: 这是处理图片上传的关键。media_folder是相对于项目根目录的路径上传的图片会保存到这里。public_folder是图片在最终网站中的公开访问路径。Hexo 在处理source/images下的图片时会将其输出到public/images访问路径正好是/images。这个配置需要和你 Hexo 主题中引用图片的路径方式相匹配。collections: 定义内容类型。这里我们定义了一个posts集合对应 Hexo 的文章。folder指向 Hexo 存放文章的目录。fields定义了文章的前置参数Front-matter和正文内容对应的表单字段。提交配置到仓库将static/admin目录下的这两个新文件添加到 Git 并提交、推送。git add static/admin/ git commit -m Add Netlify CMS configuration git push origin main推送后Vercel 会自动开始一次新的构建。完成后访问https://你的站点.vercel.app/admin你应该能看到 Netlify-CMS 的登录界面。4.2 配置 GitHub OAuth 身份验证此时点击登录会提示你需要进行身份验证。因为 Netlify-CMS 需要权限来代表你向 GitHub 仓库写入内容。我们需要在 GitHub 上创建一个 OAuth App 来授权。创建 GitHub OAuth App登录 GitHub进入Settings-Developer settings-OAuth Apps-New OAuth App。Application name: 填一个你能识别的名字如 “My Blog CMS”。Homepage URL: 填写你博客的最终访问地址即https://你的站点.vercel.app。Authorization callback URL:这是最重要的。填写https://你的站点.vercel.app/admin。Netlify-CMS 在登录后需要跳转回这个地址。点击 “Register application”。获取 Client ID 和生成 Client Secret创建成功后你会进入应用详情页。在这里你可以看到Client ID。复制它。在同一个页面点击Generate a new client secret按钮生成一个Client Secret。复制它注意这个 secret 只显示一次请妥善保存。在 Vercel 中配置环境变量回到你的 Vercel 项目 Dashboard。进入Settings-Environment Variables。添加两个变量GITHUB_CLIENT_ID: 值为你刚才复制的 Client ID。GITHUB_CLIENT_SECRET: 值为你刚才生成的 Client Secret。点击 “Save”。重要添加环境变量后Vercel 会提示需要重新部署才能使新变量生效。请触发一次新的部署比如在仓库随便改个 README 并提交。修改 Netlify-CMS 配置以使用环境变量更新你本地的static/admin/config.yml文件中的backend部分backend: name: github repo: 你的GitHub用户名/my-hexo-blog branch: main # 添加以下两行引用 Vercel 的环境变量 client_id: {% raw %}{{process.env.GITHUB_CLIENT_ID}}{% endraw %} client_secret: {% raw %}{{process.env.GITHUB_CLIENT_SECRET}}{% endraw %}提交并推送这个修改。git add static/admin/config.yml git commit -m “Update CMS config to use env vars for auth” git push origin main等待 Vercel 完成新一轮部署。之后再次访问https://你的站点.vercel.app/admin点击登录此时应该会跳转到 GitHub 进行授权。授权成功后你就会进入 Netlify-CMS 的内容管理后台了在这里你可以看到已有的文章列表可以创建新文章使用富文本或 Markdown 编辑器写作上传图片并填写标题、日期、标签等元数据。点击发布内容就会提交到你的 GitHub 仓库并自动触发 Vercel 构建部署。5. 深度配置与优化实战基础流程跑通后我们需要进行一些优化配置让整个系统更健壮、更好用。5.1 优化 Hexo 配置以适应在线构建在线构建环境是全新的每次构建都像在一台新电脑上操作。因此一些在本地不是问题的情况在云端可能会出错。锁定依赖版本这是避免构建失败的最重要措施。在线构建时Vercel 会执行npm install默认会安装package.json中^或~指定的最新兼容版本。如果某个依赖发布了不兼容的更新你的构建就可能突然失败。操作将package.json中所有依赖的版本号前面的^或~去掉固定为确切的版本号。或者使用npm shrinkwrap或yarn.lock如果你用 Yarn来锁定整个依赖树。更简单的办法是直接运行npm install --save-exact hexo hexo-cli hexo-generator-archive ...为你所有的主要依赖hexo、主题、重要插件固定版本。处理主题依赖很多 Hexo 主题自身也有package.json。如果你是通过git clone把主题放在themes/xxx目录下那么主题的依赖不会被自动安装。这会导致在线构建失败。方案一推荐使用 npm 安装主题。像hexo-theme-fluid这样已发布到 npm 的主题直接用npm install hexo-theme-fluid安装。这样主题的依赖会成为你项目根目录node_modules的一部分能被正确安装。方案二如果主题没有发布到 npm或者你进行了大量自定义修改你需要将主题文件夹下的package.json中的依赖手动合并到你项目根目录的package.json的dependencies中。配置构建命令与缓存在 Vercel 项目设置的 “Build Development Settings” 中我们可以进一步优化。Build Command: 可以更明确地指定 Node.js 环境。例如NODE_ENVproduction hexo generate。Install Command: 默认npm install没问题。如果你使用 Yarn可以改为yarn install。忽略构建步骤对于只更新内容如.md文件的提交有时我们想跳过构建。可以在 Hexo 项目根目录创建vercel.json进行配置但这需要更精细的判断初期可以不考虑。5.2 强化 Netlify-CMS 的编辑体验默认的配置已经能用但我们可以让它更强大。优化编辑器预览在config.yml中可以配置editor部分让 Markdown 编辑器的预览样式更接近你博客的实际效果。editor: preview_stylesheets: - /css/main.css # 指向你博客实际使用的 CSS 文件路径这需要你知道博客最终生成的主 CSS 文件路径。这能帮助作者在写作时更好地预览排版。添加上传图片的媒体库默认图片上传是直接存到source/images。我们可以配置使用Git LFS或第三方存储如 Cloudinary、AWS S3来管理大体积图片避免仓库膨胀。以 Cloudinary 为例需要在 Cloudinary 注册并获取 API 密钥backend: name: github repo: your-username/your-repo branch: main media_library: name: cloudinary config: cloud_name: your-cloud-name api_key: your-api-key media_folder: source/images public_folder: /images配置后CMS 后台的上传按钮旁会出现一个媒体库图标可以从 Cloudinary 选择或上传图片。定义更丰富的内容模型除了posts你还可以为“页面”、“友链”、“项目”等创建独立的集合。collections: - name: pages label: Pages folder: source create: true slug: {{slug}} fields: - {label: Title, name: title, widget: string} - {label: Permalink, name: permalink, widget: string, required: false} - {label: Body, name: body, widget: markdown} - name: friends label: Friends folder: source/_data # 可以存到_data目录通过模板调用 create: true slug: {{slug}} fields: - {label: Name, name: name, widget: string} - {label: URL, name: url, widget: string} - {label: Avatar, name: avatar, widget: image}这样非技术团队成员也能轻松管理这些内容。5.3 利用 Vercel 高级功能自定义域名与 HTTPS在 Vercel 项目设置的 “Domains” 里可以添加你自己的域名如blog.yourname.com。Vercel 会自动为你申请并配置 Let‘s Encrypt SSL 证书实现全站 HTTPS。环境变量管理我们已经用环境变量存储了 GitHub OAuth 的密钥。你还可以将博客的 Google Analytics ID、评论系统密钥等敏感信息也放在这里然后在 Hexo 的模板中通过process.env.变量名来读取。这样既安全又方便在不同环境生产、预览使用不同配置。预览部署Vercel 为每个 Git 分支、每次 Pull Request 都会生成一个独立的、唯一的预览 URL。这意味着你可以在发布前先在一个临时的环境中查看更改的效果。这对于修改主题、调试配置非常有用。性能分析与缓存Vercel 自动提供的全球 CDN 已经很快。你还可以通过配置vercel.json中的headers来为静态资源设置更长的缓存时间进一步提升访问速度。{ headers: [ { source: /images/(.*), headers: [ { key: Cache-Control, value: public, max-age31536000, immutable } ] }, { source: /(.*).(css|js), headers: [ { key: Cache-Control, value: public, max-age31536000, immutable } ] } ] }这个配置告诉浏览器和 CDN图片、CSS、JS 文件可以缓存一年31536000秒并且内容是不可变的immutable极大地减少了重复请求。6. 常见问题、故障排查与实操心得即使流程清晰在实际搭建和运行中你还是会遇到各种各样的问题。下面是我总结的一些典型问题和解决方法。6.1 构建失败依赖与版本问题这是最常见的一类错误。Vercel 的构建日志是排查问题的第一现场。问题现象Vercel 部署状态显示 “Failed”日志中常见Module not found、Error: Cannot find module ‘xxx’或主题相关函数报错。排查步骤查看完整日志进入 Vercel 项目 Dashboard点击失败的那次部署查看详细的构建日志。错误信息通常很明确。检查package.json确认所有必需的依赖都已列入dependencies而不是devDependencies。在线构建通常以生产模式运行可能不会安装devDependencies。保险起见把构建必需的插件都放在dependencies里。锁定版本如 5.1 节所述立即执行版本锁定操作。特别是 Hexo 核心、渲染器插件如hexo-renderer-marked和你的主题。模拟构建在本地尝试删除node_modules和package-lock.json然后重新npm install再hexo g看是否能成功。这能复现云端环境。我的教训有一次一个 Hexo 插件更新后修改了 API导致我的主题模板报错。因为我在package.json里写的是^2.0.0构建时自动升级到了2.1.0于是构建失败。从此以后我对核心依赖全部使用精确版本号。6.2 Netlify-CMS 登录或保存失败问题现象点击登录没反应或登录后保存文章时报 “Failed to persist entry”。排查步骤检查回调地址确保 GitHub OAuth App 的 “Authorization callback URL”完全匹配你的 CMS 访问地址包括https://和末尾的/admin。检查环境变量确认 Vercel 中的GITHUB_CLIENT_ID和GITHUB_CLIENT_SECRET已正确设置并且已经完成了一次包含新变量的重新部署。环境变量在保存后不会立即生效于当前运行中的实例。查看浏览器控制台在 CMS 页面按 F12 打开开发者工具切换到 Console 和 Network 标签页。尝试登录或保存看是否有红色的 JavaScript 错误或网络请求失败。错误信息会给出更具体的线索。检查仓库权限确认你用于登录 GitHub 的账号有权限向你配置的仓库repo: 用户名/仓库名进行写入push。实操心得Netlify-CMS 的配置config.yml对缩进非常敏感必须是两个空格不能是 Tab。一个缩进错误就可能导致整个 CMS 无法加载。建议使用在线 YAML 校验工具检查语法。6.3 图片上传后无法显示或路径错误问题现象在 CMS 后台上传的图片发布后在博客中显示为裂图。原因分析这几乎总是config.yml中media_folder和public_folder配置与 Hexo 处理方式不匹配导致的。解决方案理解路径记住media_folder是源码路径public_folder是网站访问路径。匹配 Hexo 配置确保你的 Hexo 主题在引用图片时使用的路径与public_folder的设置能对应上。例如如果你设置public_folder: “/images”那么在 Markdown 中引用图片就应该是。检查构建结果去 Vercel 部署生成的网站中右键点击裂图选择“复制图片地址”看看这个地址是什么。然后去你的 GitHub 仓库source/images目录下查看图片是否存在。通过对比就能发现问题所在。使用绝对路径在 Netlify-CMS 的config.yml中public_folder最好以/开头表示站点根目录这样最不容易出错。6.4 如何实现草稿和定时发布Hexo 本身支持draft草稿和未来日期定时发布。Netlify-CMS 也可以配合实现。草稿功能在 Hexo 中将文章放在source/_drafts目录下就不会被构建发布。你可以在 Netlify-CMS 中新增一个drafts集合指向source/_drafts文件夹。当文章写完准备发布时在 CMS 中将其移动到posts集合这需要自定义 CMS 工作流或手动操作。更简单的做法是利用 Hexo 的 Front-matter 属性published: false。你可以在 CMS 的fields里添加一个布尔类型的published字段默认值为false。然后在 Hexo 的_config.yml中设置skip_render来忽略某些文件或者通过主题逻辑根据published字段判断是否显示。这种方法更直接。定时发布Hexo 会对 Front-matter 中date设置为未来时间的文章延迟到该时间点之后才构建生成。Netlify-CMS 的datetimewidget 可以方便地设置未来日期。关键在于构建触发。如果你设定了未来时间如明天发布但今天提交后 Vercel 立即构建这篇文章不会出现在构建结果中。只有当未来那个时间点之后再次触发一次构建文章才会出现。你可以使用 GitHub Actions 或 Vercel 的 CRON Jobs付费功能来设置定时构建任务从而实现真正的“定时发布”。6.5 备份与迁移你的所有内容文章、配置都在 GitHub 仓库里这本身就是最好的备份。但为了更安心定期仓库备份可以使用 GitHub 自带的仓库下载功能或使用第三方工具定期将仓库克隆到本地或其他 Git 服务。图片资源备份如果你的图片存储在仓库内的source/images那么它们已随仓库备份。如果使用了第三方图床如 Cloudinary请务必在图床服务中设置好备份策略。迁移到其他平台由于这套方案基于标准 Git 仓库和静态文件迁移成本极低。如果你想换到 Netlify、Cloudflare Pages 或其他支持 Git 触发构建的平台只需在新平台导入同一个 GitHub 仓库并配置类似的构建命令即可。内容和管理后台Netlify-CMS的配置都是可移植的。这套 “Hexo Netlify-CMS Vercel” 的在线构建方案我用了快两年它彻底改变了我的博客维护方式。从最初的频繁折腾本地环境到现在随时随地打开浏览器就能写、能发那种流畅感是传统方式无法比拟的。它可能不是最极客的方案但绝对是平衡了灵活性、易用性和性能的优选。如果你也受够了本地环境的繁琐不妨花点时间搭一套相信你也会爱上这种“云端写作边缘交付”的现代博客体验。