Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 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.html404.html 和静态资源。
  • site-builder deploy 成功输出 site object id;第一次部署后 ws-resources.json 写入了 object_id
  • Portal URL 可以打开首页、文章页、404 页和任意前端深层路由。
  • 刷新深层路由不会丢失 SPA 页面。
  • 浏览器网络面板中 HTML 与静态资源的缓存策略符合配置。
  • CI 只在 main 分支发布,且凭证全部来自 secret。