SSG Integration
通用评论和搜索集成
使用 RaisFast 的通用 API 为 Hugo、Astro、Hexo 或任何静态站点生成器添加实时评论和全文搜索功能。
概述
RaisFast 提供了通用 REST API 来实现评论和全文搜索,适用于任何静态站点生成器。本指南展示如何将这两个功能集成到任何 SSG — Hugo、Astro、Hexo、Eleventy、Jekyll、Next.js 静态导出,或其他任何生成器。
你的 SSG → 生成静态 HTML
RaisFast → 评论 API + 搜索 API(通过 fetch / JavaScript)前提条件
- 已安装 RaisFast(安装指南 →)
- 任何静态站点生成器
步骤 1:启动 RaisFast
raisfastAPI 地址为 http://localhost:9898/api/v1。
步骤 2:添加评论(通用方案)
创建 raisfast-comments.js 文件,并在需要评论的页面中引入:
<!-- 添加到文章模板 -->
<div id="raisfast-comments" data-page-id="{{ .RelPermalink }}"></div>
<script src="/js/raisfast-comments.js"></script>// static/js/raisfast-comments.js
(function () {
var API_BASE = "http://localhost:9898/api/v1";
var container = document.getElementById("raisfast-comments");
if (!container) return;
var pageId = container.dataset.pageId;
function renderComments(items) {
return items
.map(function (c) {
return (
'<div class="rf-comment" style={{marginBottom: "16px"}}>' +
"<strong>" +
c.author_name +
"</strong>" +
"<span style={{marginLeft: "8px", color: "#999", fontSize: "0.85em"}}>" +
new Date(c.created_at).toLocaleDateString() +
"</span>" +
"<p>" +
c.content +
"</p>" +
"</div>"
);
})
.join("");
}
function renderForm() {
return (
'<form id="rf-comment-form" style={{"marginTop": "16px"}}>' +
'<input name="author_name" placeholder="你的名字" required style={{display: "block", marginBottom: "8px", padding: "8px", width: "100%", maxWidth: "400px"}}>' +
'<textarea name="content" placeholder="写下你的评论..." required style={{display: "block", marginBottom: "8px", padding: "8px", width: "100%", maxWidth: "600px", minHeight: "80px"}}></textarea>' +
'<button type="submit">提交评论</button>' +
"</form>"
);
}
fetch(API_BASE + "/comments?post_id=" + encodeURIComponent(pageId))
.then(function (r) {
return r.json();
})
.then(function (data) {
var items = (data.data && data.data.items) || [];
container.innerHTML =
'<h3>评论 (' + items.length + ")</h3>" +
renderComments(items) +
renderForm();
document
.getElementById("rf-comment-form")
.addEventListener("submit", function (e) {
e.preventDefault();
var form = this;
fetch(API_BASE + "/comments", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
post_id: pageId,
author_name: form.author_name.value,
content: form.content.value,
}),
}).then(function () {
location.reload();
});
});
});
})();各框架的 page ID 获取方式
data-page-id 属性需要能唯一标识每个页面:
| SSG | 模板变量 |
|---|---|
| Hugo | {{ .RelPermalink }} |
| Astro | {Astro.url.pathname} |
| Hexo | <%= page.path %> |
| Eleventy | {{ page.url }} |
| Jekyll | {{ page.url }} |
| Next.js(静态) | window.location.pathname |
步骤 3:添加搜索(通用方案)
创建 raisfast-search.js 文件,并在站点中添加搜索输入框:
<!-- 添加到布局头部或导航栏 -->
<div id="raisfast-search">
<input type="text" id="rf-search-input" placeholder="搜索...">
<div id="rf-search-results"></div>
</div>
<script src="/js/raisfast-search.js"></script>// static/js/raisfast-search.js
(function () {
var API_BASE = "http://localhost:9898/api/v1";
var input = document.getElementById("rf-search-input");
var results = document.getElementById("rf-search-results");
if (!input || !results) return;
var debounceTimer;
input.addEventListener("input", function () {
var query = this.value.trim();
clearTimeout(debounceTimer);
if (query.length < 2) {
results.innerHTML = "";
return;
}
debounceTimer = setTimeout(function () {
fetch(
API_BASE + "/search?q=" + encodeURIComponent(query)
)
.then(function (r) {
return r.json();
})
.then(function (data) {
var items = (data.data && data.data.items) || [];
if (items.length === 0) {
results.innerHTML = '<p style={{"padding": "8px", "color": "#999"}}>没有找到结果。</p>';
return;
}
results.innerHTML = items
.map(function (p) {
return (
'<a href="' +
p.url +
'" style={{display: "block", padding: "8px", textDecoration: "none", color: "inherit"}}>' +
"<strong>" +
p.title +
"</strong>" +
"<p style={{margin: "4px 0 0", fontSize: "0.85em", color: "#666"}}>" +
p.excerpt +
"</p>" +
"</a>"
);
})
.join("");
});
}, 300);
});
document.addEventListener("click", function (e) {
if (
!input.contains(e.target) &&
!results.contains(e.target)
) {
results.innerHTML = "";
input.value = "";
}
});
})();步骤 4:索引内容
搜索功能需要在构建后将内容推送到 RaisFast 的搜索索引中。创建构建脚本:
// scripts/index-content.js
// 在 hugo build / astro build / hexo generate 之后运行
// 用法: node scripts/index-content.js
var fs = require("fs");
var path = require("path");
var API_BASE = "http://localhost:9898/api/v1";
function walkDir(dir, ext) {
var results = [];
var list = fs.readdirSync(dir);
list.forEach(function (file) {
var filePath = path.join(dir, file);
var stat = fs.statSync(filePath);
if (stat && stat.isDirectory()) {
results = results.concat(walkDir(filePath, ext));
} else if (file.endsWith(ext)) {
results.push(filePath);
}
});
return results;
}
function extractTitle(html) {
var match = html.match(/<h1[^>]*>(.*?)<\/h1>/);
return match ? match[1] : "";
}
function stripHtml(html) {
return html.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
}
var outputDir = process.argv[2] || "./public";
var htmlFiles = walkDir(outputDir, ".html");
htmlFiles.forEach(function (file) {
var html = fs.readFileSync(file, "utf-8");
var title = extractTitle(html) || path.basename(file, ".html");
var content = stripHtml(html).substring(0, 5000);
var url = "/" + path.relative(outputDir, file);
fetch(API_BASE + "/search/index", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: title,
content: content,
url: url,
}),
});
});
console.log("已索引 " + htmlFiles.length + " 个页面。");将脚本加入构建流程:
# 先构建静态站点
hugo build # 或: astro build / hexo generate
# 然后索引内容到 RaisFast
node scripts/index-content.js ./public步骤 5:部署
生产架构
Internet
├── Nginx / Caddy(反向代理)
│ ├── / → 静态文件(Hugo/Astro/Hexo 输出)
│ └── /api/ → RaisFast(127.0.0.1:9898)
│
└── RaisFast(API + 管理后台)
├── 评论 API
├── 搜索 API
└── 管理后台 /adminNginx 配置
server {
listen 80;
server_name yourdomain.com;
# SSG 静态文件
location / {
root /var/www/site/public;
try_files $uri $uri/ /index.html;
}
# RaisFast API
location /api/ {
proxy_pass http://127.0.0.1:9898;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# RaisFast 管理后台(可选)
location /admin {
proxy_pass http://127.0.0.1:9898;
}
}Caddy 配置
yourdomain.com {
root * /var/www/site/public
try_files {path} /index.html
file_server
reverse_proxy /api/* localhost:9898
reverse_proxy /admin localhost:9898
}自定义样式
评论组件样式
添加自定义 CSS 以匹配你的站点设计:
#raisfast-comments {
max-width: 720px;
margin: 2rem auto;
}
.rf-comment {
padding: 12px 0;
border-bottom: 1px solid #eee;
}
#rf-comment-form input,
#rf-comment-form textarea {
border: 1px solid #ddd;
border-radius: 4px;
font-family: inherit;
}
#rf-comment-form button {
background: #0070f3;
color: white;
border: none;
padding: 8px 24px;
border-radius: 4px;
cursor: pointer;
}搜索组件样式
#raisfast-search {
position: relative;
}
#rf-search-input {
padding: 8px 16px;
border: 1px solid #ddd;
border-radius: 8px;
width: 240px;
font-size: 14px;
}
#rf-search-results {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: white;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
max-height: 400px;
overflow-y: auto;
z-index: 100;
}
#rf-search-results a:hover {
background: #f5f5f5;
}延伸阅读
- Hugo + RaisFast → — Hugo 专属集成指南
- Astro + RaisFast → — Astro 专属集成指南
- Hexo + RaisFast → — Hexo 专属集成指南
- API 参考 → — 评论和搜索接口的完整 API 文档
