第 26 章 项目二:Walrus Sites 内容站
本章把一个静态内容站发布为 Walrus Site。目标不是替代所有传统 CDN,而是把可公开访问、版本化、抗单点故障的内容放到 Walrus,并用 Walrus Sites 的路由配置交付给用户。
项目目标
- 使用静态站点生成器构建内容站。
- 配置 SPA fallback、缓存策略和错误页。
- 通过 Walrus Sites 发布、更新、回滚。
- 用 CI/CD 固化构建与发布命令。
- 给出上线前验收标准。
架构
Markdown / CMS export
v
Static site generator
v
dist/
v
site-builder deploy
v
Walrus + Sui site object
v
Portal / SuiNS / custom domain
内容站适合放这些资产:
- 产品文档、博客、白皮书、开源项目主页。
- 纯前端应用的静态构建产物。
- 需要公开读、低频写、可版本化的站点。
不适合直接放这些内容:
- 必须服务端渲染的页面。
- 带用户私密数据的动态接口。
- 每秒频繁变动的大量小对象;这类数据应先做批处理或放后端 API。
目录结构
walrus-content-site/
content/
posts/
hello-walrus.md
public/
logo.svg
src/
layouts/
pages/
dist/
ws-resources.json
package.json
Walrus Sites 配置
示例 ws-resources.json:
{
"object_id": "0x<site-object-id-written-after-first-deploy>",
"headers": {
"/index.html": {
"cache-control": "public, max-age=300"
},
"/assets/app.3f1a2c.js": {
"cache-control": "public, max-age=31536000, immutable"
},
"/assets/app.a91c04.css": {
"cache-control": "public, max-age=31536000, immutable"
}
},
"routes": {
"/app/*": "/index.html"
},
"metadata": {
"site_name": "walrus-content-site",
"description": "A content site deployed with Walrus Sites"
}
}
如果站点是传统多页内容站,可以移除 routes;如果是 React/Vue/Svelte 单页应用,应保留 fallback 路由,避免刷新深层路由时返回 404。headers 必须写精确资源路径,不支持 /assets/* 这类通配符;真实项目可以在构建后扫描 dist/assets/ 自动生成这些条目。
关键代码
内容站构建脚本只关心输出 dist/:
{
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"deploy:site": "site-builder --context=testnet deploy --epochs 10 ./dist"
},
"dependencies": {},
"devDependencies": {
"astro": "6.2.2"
}
}
基础页面示例:
---
const posts = Object.values(
import.meta.glob("../content/posts/*.md", { eager: true }),
);
---
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Walrus 内容站</title>
</head>
<body>
<main>
<h1>Walrus 内容站</h1>
<ul>
{posts.map((post) => (
<li>
<a href={post.url}>{post.frontmatter.title}</a>
</li>
))}
</ul>
</main>
</body>
</html>
CI 发布流程需要把构建和发布分开。构建产物可重复生成,发布步骤需要 Sui/Walrus 凭证:
name: publish-walrus-site
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build
- name: Configure Sui key
run: |
mkdir -p ~/.sui/sui_config
printf '%s' "$SUI_CLIENT_YAML" > ~/.sui/sui_config/client.yaml
env:
SUI_CLIENT_YAML: ${{ secrets.SUI_CLIENT_YAML }}
- name: Publish site
run: npm run deploy:site
上线前可以把构建产物做一次静态检查:
npm run build
test -f dist/index.html
find dist -type f -size +50M -print
运行命令
首次发布:
npm install
npm run build
npm run deploy:site
后续更新:
npm run build
npm run deploy:site
本地预览:
npm run preview
运维要点
- 把
site object id写入配置和发布日志;它是回滚、迁移、绑定域名的核心标识。 - 静态资源文件名应带内容哈希,并配置长缓存。
- HTML 用短缓存,避免用户长期停留在旧入口。
- 自定义域名和 SuiNS 绑定应在发布完成后再切流量。
- CI 中的 Sui 配置属于高权限凭证,只放在 secret,不提交进仓库。
验收标准
npm run build生成dist/index.html、404.html和静态资源。site-builder deploy成功输出 site object id;第一次部署后ws-resources.json写入了object_id。- Portal URL 可以打开首页、文章页、404 页和任意前端深层路由。
- 刷新深层路由不会丢失 SPA 页面。
- 浏览器网络面板中 HTML 与静态资源的缓存策略符合配置。
- CI 只在
main分支发布,且凭证全部来自 secret。