让我们自己构建一个 CMS。但我们不会构建 UI,而是会以 GitHub 的形式免费获得该 UI!我们将利用 GitHub 作为管理静态网站生成器内容的方式(它可以是 _任何_ 静态网站生成器)。以下是其要点:GitHub 将成为管理、版本控制和存储文件的地方,同时也是我们进行内容编辑的地方。当发生编辑时,一系列自动化将测试、验证并最终将我们的内容部署到 Cloudflare。
您可以在 GitHub 上找到该项目的完整代码。我使用这种确切的方式来运行自己的网站 jonpauluritis.com。
完整堆栈是什么样子的?
以下是我们将在本文中使用的技术堆栈
- 任何 Markdown 编辑器(可选。例如 Typora.io)
- 静态网站生成器(例如 Metalsmith)
- 带 GitHub Actions 的 Github(CICD 和部署)
- Cloudflare Workers
为什么您应该关心这种设置?这种设置可能是管理网站(或 Jamstack 网站)最精简、最快、最便宜(约 5 美元/月)且最简单的方式。从技术方面和用户体验方面来说,它都非常棒。这种设置非常棒,我直接去购买了微软和 Cloudflare 的股票。
但在我们开始之前……
我不会引导您完成在这些服务上设置帐户的过程,我相信您自己可以做到。以下是您需要设置的帐户:
- GitHub(注册 GitHub Actions。)
- Cloudflare Workers 网站(这是每月收费 5 美元的一个。)
我还建议您使用 Typora 获得绝佳的 Markdown 写作体验,但 Markdown 编辑器是非常个人化的东西,因此请使用您觉得合适的编辑器。
项目结构
为了让您了解我们将要做什么,以下是完成项目的结构
├── build.js
├── .github/workflows
│ ├── deploy.yml
│ └── nodejs.js
├── layouts
│ ├── about.hbs
│ ├── article.hbs
│ ├── index.hbs
│ └── partials
│ └── navigation.hbs
├── package-lock.json
├── package.json
├── public
├── src
│ ├── about.md
│ ├── articles
│ │ ├── post1.md
│ │ └── post2.md
│ └── index.md
├── workers-site
└── wrangler.toml
步骤 1:命令行操作
在终端中,将目录更改为您保存此类项目的位置,并键入以下内容
$ mkdir cms && cd cms && npm init -y
这将创建一个新目录,进入该目录,并初始化 npm 的使用。
接下来我们要做的是站在巨人的肩膀上。我们将使用许多 npm 包来帮助我们完成操作,其中最重要的是使用静态网站生成器 Metalsmith
$ npm install --save-dev metalsmith metalsmith-markdown metalsmith-layouts metalsmith-collections metalsmith-permalinks handlebars jstransformer-handlebars
除了 Metalsmith 之外,还有其他一些有用的组件。为什么要使用 Metalsmith?我们来谈谈这个。
步骤 2:Metalsmith
我已经尝试使用静态网站生成器 2-3 年了,但我仍然没有找到“那个”。所有的大牌 — 例如 Eleventy、Gatsby、Hugo、Jekyll、Hexo 和 Vuepress — 都非常棒,但我无法克服 Metalsmith 的简单性和可扩展性。
例如,这段代码实际上会构建一个网站:
// EXAMPLE... NOT WHAT WE ARE USING FOR THIS TUTORIAL
Metalsmith(__dirname)
.source('src')
.destination('dest')
.use(markdown())
.use(layouts())
.build((err) => if (err) throw err);
很酷吧?
为了简洁起见,将此代码键入终端,我们将构建一些结构和文件作为起点。
首先,创建目录
$ mkdir -p src/articles && mkdir -p layouts/partials
然后,创建构建文件
$ touch build.js
接下来,我们将创建一些布局文件
$ touch layouts/index.hbs && touch layouts/about.hbs && touch layouts/article.hbs && touch layouts/partials/navigation.hbt
最后,我们将设置我们的内容资源
$ touch src/index.md && touch src/about.md && touch src/articles/post1.md && touch src/articles/post1.md touch src/articles/post2.md
项目文件夹应如下所示
├── build.js
├── layouts
│ ├── about.hbs
│ ├── article.hbs
│ ├── index.hbs
│ └── partials
│ └── navigation.hbs
├── package-lock.json
├── package.json
└── src
├── about.md
├── articles
│ ├── post1.md
│ └── post2.md
└── index.md
步骤 3:添加一些代码
为了节省空间(和时间),您可以使用以下命令创建我们虚构网站的内容。您可以随意进入“articles”并创建自己的博文。关键是这些文章需要一些元数据(也称为“前置 matter”)才能正确生成。您需要编辑的文件是 index.md
、post1.md
和 post2.md
。
元数据应如下所示:
---
title: 'Post1'
layout: article.hbs
---
## Post content here....
或者,如果您像我一样懒,可以使用以下终端命令将 GitHub Gists 的模拟内容添加到您的网站
$ curl https://gist.githubusercontent.com/jppope/35dd682f962e311241d2f502e3d8fa25/raw/ec9991fb2d5d2c2095ea9d9161f33290e7d9bb9e/index.md > src/index.md
$ curl https://gist.githubusercontent.com/jppope/2f6b3a602a3654b334c4d8df047db846/raw/88d90cec62be6ad0b3ee113ad0e1179dfbbb132b/about.md > src/about.md
$ curl https://gist.githubusercontent.com/jppope/98a31761a9e086604897e115548829c4/raw/6fc1a538e62c237f5de01a926865568926f545e1/post1.md > src/articles/post1.md
$ curl https://gist.githubusercontent.com/jppope/b686802621853a94a8a7695eb2bc4c84/raw/9dc07085d56953a718aeca40a3f71319d14410e7/post2.md > src/articles/post2.md
接下来,我们将创建布局和部分布局(“partials”)。在本教程中,我们将使用 Handlebars.js 作为我们的模板语言,但您可以使用任何您喜欢的模板语言。Metalsmith 可以与几乎所有模板语言配合使用,我对模板语言没有强烈的偏好。
构建索引布局
<!DOCTYPE html>
<html lang="en">
<head>
<style>
/* Keeping it simple for the tutorial */
body {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.navigation {
display: flex;
justify-content: center;
margin: 2rem 1rem;
}
.button {
margin: 1rem;
border: solid 1px #ccc;
border-radius: 4px;
padding: 0.5rem 1rem;
text-decoration: none;
}
</style>
</head>
<body>
{{>navigation }}
<div>
{{#each articles }}
<a href="{{path}}"><h3>{{ title }}</h3></a>
<p>{{ description }}</p>
{{/each }}
</div>
</body>
</html>
几点说明:
- 我们的“导航”尚未定义,但最终将替换
{{>navigation }}
所在的区域。 {{#each }}
将遍历 metalsmith 在其构建过程中生成的“collection”文章。- Metalsmith 有 _很多_ 插件 可用于样式表、标签等,但这并不是本教程的重点,因此我们将其留给您探索。
构建关于页面
将以下内容添加到您的 about.hbs
页面
<!DOCTYPE html>
<html lang="en">
<head>
<style>
/* Keeping it simple for the tutorial */
body {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.navigation {
display: flex;
justify-content: center;
margin: 2rem 1rem;
}
.button {
margin: 1rem;
border: solid 1px #ccc;
border-radius: 4px;
padding: 0.5rem 1rem;
text-decoration: none;
}
</style>
</head>
<body>
{{>navigation }}
<div>
{{{contents}}}
</div>
</body>
</html>
构建文章布局
<!DOCTYPE html>
<html lang="en">
<head>
<style>
/* Keeping it simple for the tutorial */
body {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.navigation {
display: flex;
justify-content: center;
margin: 2rem 1rem;
}
.button {
margin: 1rem;
border: solid 1px #ccc;
border-radius: 4px;
padding: 0.5rem 1rem;
text-decoration: none;
}
</style>
</head>
<body>
{{>navigation }}
<div>
{{{contents}}}
</div>
</body>
</html>
您可能已经注意到,这与关于页面的布局完全相同。是的,就是这样。我只是想说明如何添加其他页面,以便您知道如何操作。如果您想让这个页面与众不同,请随意进行更改。
添加导航
将以下内容添加到 layouts/partials/navigation.hbs
文件
<div class="navigation">
<div>
<a class="button" href="/">Home</a>
<a class="button" href="/about">About</a>
</div>
</div>
当然,它并没有什么特别的……但这并不是关于 Metalsmith/SSG 的教程。 ¯\_(ツ)_/¯
步骤 4:构建文件
Metalsmith 的核心是构建文件。为了完整起见,我将逐行介绍它。
我们首先导入依赖项
快速提示: Metalsmith 创建于 2014 年,当时主要的模块系统是 common.js
,所以我将坚持使用 require 语句而不是 ES 模块。值得注意的是,大多数其他教程也使用 require 语句,因此跳过使用 Babel 进行构建步骤只会让这里的生活稍微不那么复杂。
// What we use to glue everything together
const Metalsmith = require('metalsmith');
// compile from markdown (you can use targets as well)
const markdown = require('metalsmith-markdown');
// compiles layouts
const layouts = require('metalsmith-layouts');
// used to build collections of articles
const collections = require('metalsmith-collections');
// permalinks to clean up routes
const permalinks = require('metalsmith-permalinks');
// templating
const handlebars = require('handlebars');
// register the navigation
const fs = require('fs');
handlebars.registerPartial('navigation', fs.readFileSync(__dirname + '/layouts/partials/navigation.hbt').toString());
// NOTE: Uncomment if you want a server for development
// const serve = require('metalsmith-serve');
// const watch = require('metalsmith-watch');
接下来,我们将包含 Metalsmith 并告诉它在哪里找到它的编译目标
// Metalsmith
Metalsmith(__dirname)
// where your markdown files are
.source('src')
// where you want the compliled files to be rendered
.destination('public')
到目前为止,一切都很好。在设置了源和目标之后,我们将设置 markdown 渲染、布局渲染,并让 Metalsmith 知道使用“集合”。这些是将文件组合在一起的一种方式。一个简单的例子可能是“博文”,但实际上它可以是任何东西,比如食谱、威士忌评论或任何其他东西。在上面的例子中,我们称这个集合为“文章”。
// previous code would go here
// collections create groups of similar content
.use(collections({
articles: {
pattern: 'articles/*.md',
},
}))
// compile from markdown
.use(markdown())
// nicer looking links
.use(permalinks({
pattern: ':collection/:title'
}))
// build layouts using handlebars templates
// also tell metalsmith where to find the raw input
.use(layouts({
engine: 'handlebars',
directory: './layouts',
default: 'article.html',
pattern: ["*/*/*html", "*/*html", "*html"],
partials: {
navigation: 'partials/navigation',
}
}))
// NOTE: Uncomment if you want a server for development
// .use(serve({
// port: 8081,
// verbose: true
// }))
// .use(watch({
// paths: {
// "${source}/**/*": true,
// "layouts/**/*": "**/*",
// }
// }))
接下来,我们将添加 markdown 插件,这样我们就可以使用 markdown 来编写内容并将其编译成 HTML。
从那里,我们使用 layouts 插件 将我们的原始内容包裹在我们在 layouts 文件夹中定义的布局中。您可以在官方插件网站上了解有关此功能的更多信息,但结果是,我们可以在模板中使用 {{{contents}}}
,它会正常工作。
我们这个小型构建脚本的最后一个添加项将是构建方法
// Everything else would be above this
.build(function(err) {
if (err) {
console.error(err)
}
else {
console.log('build completed!');
}
});
将所有内容组合在一起,我们应该得到一个如下所示的构建脚本
const Metalsmith = require('metalsmith');
const markdown = require('metalsmith-markdown');
const layouts = require('metalsmith-layouts');
const collections = require('metalsmith-collections');
const permalinks = require('metalsmith-permalinks');
const handlebars = require('handlebars');
const fs = require('fs');
// Navigation
handlebars.registerPartial('navigation', fs.readFileSync(__dirname + '/layouts/partials/navigation.hbt').toString());
Metalsmith(__dirname)
.source('src')
.destination('public')
.use(collections({
articles: {
pattern: 'articles/*.md',
},
}))
.use(markdown())
.use(permalinks({
pattern: ':collection/:title'
}))
.use(layouts({
engine: 'handlebars',
directory: './layouts',
default: 'article.html',
pattern: ["*/*/*html", "*/*html", "*html"],
partials: {
navigation: 'partials/navigation',
}
}))
.build(function (err) {
if (err) {
console.error(err)
}
else {
console.log('build completed!');
}
});
我喜欢简单干净的东西,在我看来,没有比 Metalsmith 构建更简单干净的了。我们只需要对 package.json
文件进行一个小更新,我们就可以运行它了
"name": "buffaloTraceRoute",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "node build.js",
"test": "echo \"No Tests Yet!\" "
},
"keywords": [],
"author": "Your Name",
"license": "ISC",
"devDependencies": {
// these should be the current versions
// also... comments aren't allowed in JSON
}
}
如果您想看看自己的作品,您可以取消注释构建文件中允许您为项目提供服务并执行诸如运行 npm run build
之类操作的部分。只需确保在部署之前删除此代码。
使用 Cloudflare
接下来,我们将使用 Cloudflare 来获取对他们的 Cloudflare Workers 的访问权限。这是每月 5 美元的成本发挥作用的地方。
现在,您可能会问:“好吧,但为什么是 Cloudflare?为什么不使用 GutHub Pages 或 Netlify 之类的免费服务?”这是一个好问题。有很多方法可以部署静态站点,那么为什么要选择一种方法而不是另一种方法呢?
好吧,Cloudflare 有一些优势...
速度和性能
切换到静态网站生成器最大的原因之一是为了提高网站性能。使用 Cloudflare Workers Site 可以进一步提高您的性能。
以下是将 Cloudflare 与两个竞争对手进行比较的图表

Cloudflare 速度最快的简单原因是:网站部署到 全球 190 多个数据中心。由于用户将从物理上更靠近他们的位置获取资源,因此这可以减少延迟。
简单性
诚然,如果您不知道 如何设置环境变量,Cloudflare Workers 的初始配置可能有点棘手。但是,在您为计算机设置基本配置后,部署到 Cloudflare 就和从站点目录中运行 wrangler publish 一样简单。本教程重点介绍了部署到 Cloudflare 的 CI/CD 方面,这涉及更多内容,但与大多数其他部署流程相比,它仍然非常简单。
(值得一提的是,GitHub Pages 和 Netlify 在这方面也做得很好。这三家公司的开发者体验都非常棒。)
物超所值
虽然 Github Pages 和 Netlify 都有免费层,但您的使用量(软)限制为每月 100 GB 带宽。别误会我的意思,这是一个非常慷慨的限制。但超过这个限制,你就走运了。GitHub Pages 不提供超过这个限制的任何东西,而 Netlify 则跃升至每月 45 美元,使 Cloudflare 的每月 5 美元的价格标签非常合理。
服务 | 免费层带宽 | 付费层价格 | 付费层请求 / 带宽 |
---|---|---|---|
GitHub Pages | 100GB | N/A | N/A |
Netlify | 100GB | $45 | ~150K / 400 GB |
Cloudflare Workers Sites | 无 | $5 | 10MM / 无限 |
当然,Cloudflare 没有免费层,但 5 美元可获得 1000 万次请求,这太便宜了。如果我没有提到 GitHub Pages 在过去一年中 经历了几次中断,那我会感到疏忽。在我的演示网站中,这完全没问题,但对于企业来说,这将是一个坏消息。
Cloudflare 为此提供了许多额外的功能,值得简要提及:免费 SSL 证书、免费(且易于使用)的 DNS 路由、用于项目的自定义 Workers Sites 域名(非常适合暂存)、无限环境(例如暂存)以及以成本注册域名(而不是其他注册商强加的加价定价)。
部署到 Cloudflare
Cloudflare 提供了一些很棒的教程,介绍如何使用他们的 Cloudflare Workers 产品。我们将在本文中介绍要点。
首先,确保已安装 Cloudflare CLI(Wrangler)
$ npm i @cloudflare/wrangler -g
接下来,我们将像这样将 Cloudflare Sites 添加到项目中
wrangler init --site cms
假设我没有弄错并忘记了某个步骤,那么此时我们在终端中应该看到以下内容
⬇️ Installing cargo-generate...
🔧 Creating project called `workers-site`...
✨ Done! New project created /Users/<User>/Code/cms/workers-site
✨ Succesfully scaffolded workers site
✨ Succesfully created a `wrangler.toml`
项目根目录中还应该有一个名为 /workers-site
的生成文件夹,以及一个名为 wrangler.toml
的配置文件——这就是神奇所在。
name = "cms"
type = "webpack"
account_id = ""
workers_dev = true
route = ""
zone_id = ""
[site]
bucket = ""
entry-point = "workers-site"
您可能已经猜到接下来会发生什么……我们需要在配置文件中添加一些信息!我们要更新的第一个键值对是 bucket
属性。
bucket = "./public"
接下来,我们需要获取帐户 ID 和区域 ID(即您域名的路由)。您可以在 Cloudflare 帐户中找到它们,它们位于您域名仪表板最底部

停止! 在继续之前,请不要忘记单击“获取您的 API 令牌”按钮,以获取我们将需要的最后一个配置部分。将它保存在记事本或某个方便的地方,因为我们将在下一部分中使用它。
呼!好了,下一步是将我们刚刚获取的帐户 ID 和区域 ID 添加到 .toml 文件中
name = "buffalo-traceroute"
type = "webpack"
account_id = "d7313702f333457f84f3c648e9d652ff" # Fake... use your account_id
workers_dev = true
# route = "example.com/*"
# zone_id = "805b078ca1294617aead2a1d2a1830b9" # Fake... use your zone_id
[site]
bucket = "./public"
entry-point = "workers-site"
(Again, those IDs are fake.)
同样,这些 ID 是假的。您可能会被要求在计算机上设置凭据。如果出现这种情况,请在终端中运行 wrangler config
。
GitHub Actions
拼图的最后一块是配置 GitHub 为我们执行自动部署。之前我曾多次尝试进行 CI/CD 设置,因此这次我做好了最坏的准备,但令人惊讶的是,对于这种设置,GitHub Actions 非常简单。
那么这如何运作呢?
首先,让我们确保我们的 GitHub 帐户 已激活 GitHub Actions。从技术上讲,它现在处于测试阶段,但我到目前为止还没有遇到任何问题。
接下来,我们需要在 GitHub 中创建一个存储库并将我们的代码上传到其中。从访问 GitHub 并创建一个存储库开始。

本教程并不打算涵盖 Git 和/或 GitHub 的更精细方面,但有一个 很棒的介绍。或者,在项目根目录中复制粘贴以下命令
# run commands one after the other
$ git init
$ touch .gitignore && echo 'node_modules' > .gitignore
$ git add .
$ git commit -m 'first commit'
$ git remote add origin https://github.com/{username}/{repo name}
$ git push -u origin master
这应该将项目添加到 GitHub 中。我有点犹豫地说,但这是我总是遇到问题的地方。例如,将太多命令放入终端,突然 GitHub 出现故障,或者终端无法找到 Python 的路径。小心行事!
假设我们已经完成了这一部分,我们的下一步任务是激活 Github Actions 并在项目目录的根目录中创建一个名为 .github/workflows
的目录。(GitHub 也可以通过在激活操作时添加“node”工作流来自动执行此操作。在撰写本文时,添加 GitHub Actions 工作流是 GitHub 用户界面的一个组成部分。)
一旦我们在项目根目录中拥有该目录,我们就可以添加最后的两个文件。每个文件将处理不同的工作流
- 一个工作流来检查更新是否可以合并(即 CI/CD 中的“CI”)
- 一个工作流,在更新合并到 master 后部署更改(即 CI/CD 中的“CD”)
# integration.yml
name: Integration
on:
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
env:
CI: true
这是一个简单的流程。事实上,它非常简单,我直接从官方 GitHub Actions 文档中复制了它,并且几乎没有修改。让我们一起了解一下其中发生了什么。
on:
仅在为 master 分支创建拉取请求时运行此工作流程。jobs:
针对双节点环境(例如,Node 10 和 Node 12 - Node 12 是当前推荐的版本)运行以下步骤。如果定义了构建脚本,它将进行构建。如果定义了测试脚本,它还会运行测试。
第二个文件是我们的部署脚本,它更复杂一些。
# deploy.yml
name: Deploy
on:
push:
branches:
- master
jobs:
deploy:
runs-on: ubuntu-latest
name: Deploy
strategy:
matrix:
node-version: [10.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- uses: actions/checkout@master
- name: Build site
run: "npm run build"
- name: Publish
uses: cloudflare/[email protected]
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
重要!还记得我之前提到的 Cloudflare API 令牌吗?现在是使用它的时机。转到项目设置并添加一个秘密。将秘密命名为 CF_API_TOKEN
并添加 API 令牌。
让我们看看这个脚本中发生了什么。
on:
当代码合并到 master 分支时运行这些步骤。steps:
使用 Nodejs 安装所有依赖项,使用 Nodejs 构建网站,然后使用 Cloudflare Wrangler 发布网站。
以下是运行构建之前项目应该具有的外观(不包括 node_modules
):
├── build.js
├── dist
│ └── worker.js
├── layouts
│ ├── about.hbs
│ ├── article.hbs
│ ├── index.hbs
│ └── partials
│ └── navigation.hbs
├── package-lock.json
├── package.json
├── public
├── src
│ ├── about.md
│ ├── articles
│ │ ├── post1.md
│ │ └── post2.md
│ └── index.md
├── workers-site
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ └── worker
│ └── script.js
└── wrangler.toml
基于 GitHub 的 CMS
好的,我已经做到这一步了……我被承诺了一个 CMS?数据库和登录的 GUI 在哪里?
别担心,你已经到达终点了!GitHub 现在就是你的 CMS,它是这样工作的。
- 编写一个 Markdown 文件(带有前置信息)。
- 打开 GitHub 并转到项目仓库。
- 点击“Articles”目录,并上传新文章。GitHub 会询问是否应该创建一个新的分支并附带一个拉取请求。答案是是。
- 在集成验证后,可以合并拉取请求,这会触发部署。
- 坐下来放松,等待 10 秒钟……内容正在部署到全球 164 个数据中心。
恭喜!你现在拥有一个最小化的基于 Git 的 CMS,几乎任何人都可以使用。
故障排除说明
- Metalsmith 布局有时可能有点棘手。尝试在构建步骤之前添加此调试行,以便它能输出一些有用的信息:
DEBUG=metalsmith-layouts npm run build
- 有时,Github Actions 需要我将
node_modules
添加到提交中才能部署……这对我来说很奇怪(而且不推荐),但解决了部署问题。 - 如果你正在寻找一种简单的方法来处理资产(图像、SVG 等),这个插件很棒:https://github.com/alexgs/metalsmith-assets-improved(感谢 @gofango 指出这个遗漏!)
- 如果你遇到任何问题,请告诉我,我们可以将其添加到此列表中!
不错的文章,但 GitHub Pages 允许你免费获得同样的功能。我在上面构建了我的网站,并且启用了 Cloudflare 缓存,也是免费的。我是否遗漏了什么?这种设置比文章中描述的设置好在哪里?
你能提供一个指向 GitHub 上该项目的链接吗?
为什么要付费?我在 Netlify 上免费运行多个网站,例如 zavrel.net、codewithjan.com 和 smartprofitschool.com,使用 Stackbit 非常简单。这种设置太麻烦了 :)
我同意 Jan 的观点。我在 Blogger 上运行 littleireland.co.uk,它非常简单,而且拥有巨大的容量。我还接入了免费的 Cloudflare,以增强安全性并提高速度。整个系统每年大约花费我 8 英镑。
或者你可以使用 Blogger(blogspot)来获得免费的 Google 托管。各种情况下都有大量免费主题,例如我的关于移动游戏新闻的网站 mmorpg.news
甚至与 PayPal 集成的电子商务主题。
缺点 - Blogger 在中国被禁止。
非常感谢你,我学到了很多东西。这篇文章非常有用!
Cloudflare Pages 也是免费的。
感谢你的指南!
对于在 GitHub 构建操作失败的用户:如果你遇到模块未找到错误,请将 npm install 移动到 # deploy.yml 中的 npm build 之前。
你可能还需要将 master 更改为 main 才能使其正确触发,并在 #deploy 中的 wrangler 调用之后添加 env: USER: root。