mcpField
F
frontend-playbook

frontend-playbook

github.com/austintgriffith云与 DevOps30237 次安装2 天前更新
代码仓库

关于 frontend-playbook

面向 Scaffold-ETH 2 项目的开发技能,涵盖本地分叉、构建验证及 IPFS、Vercel 和 ENS 部署流程。适合开发和发布以太坊应用的团队,重点在于静态路由、构建产物和链上状态的检查。

主要功能

  1. 01分叉 Base 等真实网络状态
  2. 02配置静态导出与 IPFS 路由
  3. 03检查构建产物和部署路由
  4. 04配置 ENS 子域名与内容哈希
  5. 05涵盖合约及浏览器端 QA

适用场景

  1. 01在真实协议状态上测试合约
  2. 02将 Scaffold-ETH 2 应用部署到 IPFS
  3. 03排查静态站点路由或旧构建问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/austintgriffith/ethskills --skill frontend-playbook

安装后在 Claude Code 中输入/frontend-playbook确认已加载。

详细介绍

前端开发指南

你可能弄错的地方

“我会用 yarn chain。” 错。yarn chain 会创建一个空的本地区块链,没有协议、没有代币、没有状态。yarn fork --network base 会创建真实 Base 的副本,其中包含 Uniswap、Aave、USDC、真实巨鲸余额等所有内容(已验证地址:addresses/SKILL.md)。始终使用 fork。

“我部署到 IPFS 了,而且能用。” CID 变了吗?如果没变,你部署的是过期输出。路由能用吗?没有 trailingSlash: true,除了 / 之外的所有路由都会返回 404。你检查过 OG 图片吗?没有 NEXT_PUBLIC_PRODUCTION_URL,它就会指向 localhost:3000。

“我会手动设置项目。” 别这么做。npx create-eth@latest 会处理好一切——Foundry、Next.js、RainbowKit、scaffold hooks。不要运行 forge init,也不要从头创建 Next.js 项目。


Fork 模式设置

为什么用 Fork,而不是 Chain
yarn chain (WRONG)              yarn fork --network base (CORRECT)
└─ Empty local chain            └─ Fork of real Base mainnet
└─ No protocols                 └─ Uniswap, Aave, etc. available
└─ No tokens                    └─ Real USDC, WETH exist
└─ Testing in isolation         └─ Test against REAL state
设置
npx create-eth@latest          # Select: foundry, target chain, name
cd <project-name>
yarn install
yarn fork --network base       # Terminal 1: fork of real Base
yarn deploy                    # Terminal 2: deploy contracts to fork
yarn start                     # Terminal 3: Next.js frontend
重要:Chain ID 易错点

使用 fork 模式时,前端目标网络必须是 chains.foundry(chain ID 31337),而不是你正在 fork 的链。

Fork 在 Anvil 上本地运行,chain ID 为 31337。即使你 fork 的是 Base:

// scaffold.config.ts during development
targetNetworks: [chains.foundry],  // ✅ NOT chains.base!

只有在将合约部署到真实网络时,才切换到 chains.base。

启用区块挖掘
# In a new terminal — REQUIRED for time-dependent logic
cast rpc anvil_setIntervalMining 1

否则,block.timestamp 会一直冻结。任何使用时间戳的合约逻辑(截止时间、过期时间、归属期)都会悄无声息地失效。

**让设置永久生效:**编辑 packages/foundry/package.json,在 fork 脚本中添加 --block-time 1。


部署到 IPFS(推荐)

IPFS 是 SE2 推荐的部署方式。它完全避开 Vercel 的内存限制,并生成完全去中心化的静态站点。

完整构建命令
cd packages/nextjs
rm -rf .next out  # ALWAYS clean first

NEXT_PUBLIC_PRODUCTION_URL="https://yourapp.yourname.eth.link" \
  NODE_OPTIONS="--require ./polyfill-localstorage.cjs" \
  NEXT_PUBLIC_IPFS_BUILD=true \
  NEXT_PUBLIC_IGNORE_BUILD_ERROR=true \
  yarn build

# Upload to BuidlGuidl IPFS
yarn bgipfs upload out
# Save the CID!
Node 25+ localStorage Polyfill(必需)

Node.js 25+ 自带的 localStorage 对象缺少标准 WebStorage API 方法(getItem、setItem)。这会导致 next-themes、RainbowKit,以及任何在静态页面生成期间调用 localStorage.getItem() 的库出错。

你会看到的错误:

TypeError: localStorage.getItem is not a function
Error occurred prerendering page "/_not-found"

**解决方法:**在 packages/nextjs/ 中创建 polyfill-localstorage.cjs:

if (typeof globalThis.localStorage !== "undefined" &&
    typeof globalThis.localStorage.getItem !== "function") {
  const store = new Map();
  globalThis.localStorage = {
    getItem: (key) => store.get(key) ?? null,
    setItem: (key, value) => store.set(key, String(value)),
    removeItem: (key) => store.delete(key),
    clear: () => store.clear(),
    key: (index) => [...store.keys()][index] ?? null,
    get length() { return store.size; },
  };
}

**为什么用 --require,而不是 instrumentation.ts?**Next.js 会启动单独的构建工作进程来预渲染。--require 会注入到每个 Node 进程中(包括工作进程)。next.config.ts 中的 polyfill 只会在主进程中运行。instrumentation.ts 不会在构建工作进程中运行。只有 --require 有效。

IPFS 路由——路由失效的原因

IPFS 网关提供静态文件,没有服务器处理路由。以下三点必须成立:

1. 在 next.config.ts 中设置 output: "export"——生成静态 HTML 文件。

2. 设置 trailingSlash: true(关键)——这是路由失效的首要原因:

  • trailingSlash: false(默认值)→ 生成 debug.html
  • trailingSlash: true → 生成 debug/index.html
  • IPFS 网关会自动将目录解析为 index.html,但不会解析裸文件名
  • 不带尾随斜杠:/debug → 404 ❌
  • 带尾随斜杠:/debug → debug/ → debug/index.html ✅

3. 页面必须能通过静态预渲染——任何在 yarn build 期间崩溃的页面(例如在导入时调用浏览器 API、使用 localStorage)都会被静默跳过 → 在 IPFS 上返回 404。

完整的 IPFS 安全型 next.config.ts 模式:

const isIpfs = process.env.NEXT_PUBLIC_IPFS_BUILD === "true";
if (isIpfs) {
  nextConfig.output = "export";
  nextConfig.trailingSlash = true;
  nextConfig.images = { unoptimized: true };
}

SE2 的区块浏览器页面会在导入时调用 localStorage,并在静态导出期间崩溃。如果不需要,请将 app/blockexplorer 重命名为 app/_blockexplorer-disabled。

检测过期构建

**IPFS 部署中最容易踩的坑:**你修改了代码,却部署了旧构建。

# MANDATORY after ANY code change:
rm -rf .next out                     # 1. Delete old artifacts
# ... run full build command ...     # 2. Rebuild from scratch
grep -l "YOUR_STRING" out/_next/static/chunks/app/*.js  # 3. Verify changes present

# Timestamp check:
stat -f '%Sm' app/page.tsx           # Source modified time
stat -f '%Sm' out/                   # Build output time
# Source NEWER than out/ = STALE BUILD. Rebuild first!

**CID 就是证据:**如果部署后 IPFS CID 没变,你部署的就是相同内容。代码发生实际更改后,CID 一定会改变。

部署后验证路由
ls out/*/index.html                  # Each route has a directory + index.html
curl -s -o /dev/null -w "%{http_code}" -L "https://GATEWAY/ipfs/CID/debug/"
# Should return 200, not 404

部署到 Vercel(替代方案)

SE2 是一个 monorepo——Vercel 需要特殊配置。

配置
  1. 根目录: packages/nextjs
  2. 安装命令: cd ../.. && yarn install
  3. 构建命令: 保留默认值(next build)
  4. 输出目录: 保留默认值(.next)
# Via API:
curl -X PATCH "https://api.vercel.com/v9/projects/PROJECT_ID" \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"rootDirectory": "packages/nextjs", "installCommand": "cd ../.. && yarn install"}'
常见故障
错误原因修复方法
"No Next.js version detected"未设置根目录设置为 packages/nextjs
"cd packages/nextjs: No such file"构建命令中包含 cd清除它——根目录会处理
OOM / exit code 129SE2 monorepo 超过 8GB改用 IPFS,或使用 vercel --prebuilt
决策树
Want to deploy SE2?
├─ IPFS (recommended) → yarn ipfs / manual build + upload
│   └─ Fully decentralized, no memory limits, works with ENS
├─ Vercel → Set rootDirectory + installCommand
│   └─ Fast CDN, but centralized. May OOM on large projects
└─ vercel --prebuilt → Build locally, push artifacts to Vercel
    └─ Best of both: local build power + Vercel CDN

ENS 子域名设置

通过两笔主网交易,将 ENS 子域名指向你的 IPFS 部署。

交易 1:创建子域名(仅限新应用)
  1. 打开 https://app.ens.domains/yourname.eth
  2. 前往“Subnames”选项卡 → “New subname”
  3. 输入标签(例如 myapp)→ Next → Skip profile → Open Wallet → Confirm
  4. 如果 Gas 卡住:将 MetaMask 切换到 Ethereum → Activity 选项卡 → “Speed up”
交易 2:设置 IPFS 内容哈希
  1. 前往 https://app.ens.domains/myapp.yourname.eth
  2. “Records”选项卡 → “Edit Records” → “Other”选项卡
  3. 在 Content Hash 字段中粘贴:ipfs://<CID>
  4. 保存 → Open Wallet → 在 MetaMask 中确认

对于现有应用的更新:跳过交易 1,只执行交易 2。

验证
# 1. Onchain content hash matches
RESOLVER=$(cast call 0x00000000000C2e074eC69A0dFb2997BA6C7d2e1e \
  "resolver(bytes32)(address)" $(cast namehash myapp.yourname.eth) \
  --rpc-url https://eth.llamarpc.com)
cast call $RESOLVER "contenthash(bytes32)(bytes)" \
  $(cast namehash myapp.yourname.eth) --rpc-url https://eth.llamarpc.com

# 2. Gateway responds (may take 5-15 min for cache)
curl -s -o /dev/null -w "%{http_code}" -L "https://myapp.yourname.eth.link"

# 3. OG metadata correct (not localhost)
curl -s -L "https://myapp.yourname.eth.link" | grep 'og:image'

使用 .eth.link,不要使用 .eth.limo——.eth.link 在移动设备上效果更好。


上线生产环境 — 完整检查清单

当用户说“发布”时,请严格按照以下顺序操作。

步骤 1:最终代码审查 🤖
  • 已整合所有反馈
  • 没有重复的 h1、原始地址或共享的 isLoading
  • scaffold.config.ts 中包含 rpcOverrides 和 pollingInterval: 3000
步骤 2:选择域名 👤

询问:“你想要什么子域名?例如 myapp.yourname.eth → myapp.yourname.eth.link”

步骤 3:生成 OG 图片 + 修正元数据 🤖
  • 创建 1200×630 PNG(public/thumbnail.png)——不要使用 SE2 默认缩略图
  • 将 NEXT_PUBLIC_PRODUCTION_URL 设置为实际域名
  • 确认 og:image 将解析为绝对生产 URL
步骤 4:清理构建 + IPFS 部署 🤖
cd packages/nextjs && rm -rf .next out
NEXT_PUBLIC_PRODUCTION_URL="https://myapp.yourname.eth.link" \
  NODE_OPTIONS="--require ./polyfill-localstorage.cjs" \
  NEXT_PUBLIC_IPFS_BUILD=true NEXT_PUBLIC_IGNORE_BUILD_ERROR=true \
  yarn build

# Verify before uploading:
ls out/*/index.html                        # Routes exist
grep 'og:image' out/index.html             # Not localhost
stat -f '%Sm' app/page.tsx                 # Source older than out/
stat -f '%Sm' out/

yarn bgipfs upload out                     # Save the CID
步骤 5:提交审核 👤

发送:“构建已准备好供审核:https://community.bgipfs.com/ipfs/<CID>” 在 ENS 操作前等待批准。

步骤 6:设置 ENS 🤖

创建子域名(如果是新域名)+ 设置 IPFS 内容哈希。共两笔主网交易。

步骤 7:验证 🤖
  • 内容哈希与链上记录一致
  • .eth.link 网关返回 200
  • OG 图片正确加载
  • 路由可用(/debug/ 等)
步骤 8:汇报 👤

“已上线:https://myapp.yourname.eth.link——ENS 内容哈希已确认上链,展开预览元数据已设置。”


构建验证流程

代码编译通过并不代表构建完成。只有像真实用户那样测试过,才算完成。

阶段 1:代码 QA(自动化)
  • 扫描 .tsx 文件中的原始地址字符串(应使用 <Address/>)
  • 扫描多个按钮之间是否共享 isLoading 状态
  • 扫描交易按钮是否缺少 disabled 属性
  • 验证 RPC 配置和轮询间隔
  • 验证 OG 元数据是否使用绝对 URL
  • 验证所有文件中均未使用公共 RPC
阶段 2:智能合约测试
forge test                    # All tests pass
forge test --fuzz-runs 10000  # Fuzz testing

测试边界情况:零金额、最大金额、未经授权的调用方、重入尝试。

阶段 3:浏览器测试(真正的测试)

打开应用并进行完整的全流程检查:

  1. 加载应用 — 是否正确渲染?
  2. 检查页面标题 — 是否正确,而不是“Scaffold-ETH 2”?
  3. 连接钱包 — 连接流程是否正常?
  4. 错误的网络 — 在错误的链上连接,确认是否显示“Switch to Base”
  5. 切换网络 — 点击切换按钮,确认是否生效
  6. 授权流程 — 确认是否显示授权按钮,点击后等待交易,确认操作按钮是否出现
  7. 主要操作 — 点击主要操作按钮,确认加载指示器是否显示,等待交易,确认状态是否更新
  8. 错误处理 — 在钱包中拒绝交易,确认界面是否恢复正常
  9. 地址显示 — 所有地址是否都显示 ENS/Blockies,而不是原始十六进制?
  10. 分享 URL — 检查 OG 展开效果(图片、标题、描述)
阶段 4:QA 子 Agent(复杂构建)

对于较大的项目,使用全新上下文启动一个子 Agent。向它提供仓库路径和已部署的 URL。它会按照 UX 规则阅读所有代码,打开浏览器并独立完成全流程检查,然后报告问题。


请勿执行以下操作

  • ❌ yarn chain — 使用 yarn fork --network <chain>
  • ❌ forge init — 使用 npx create-eth@latest
  • ❌ 手动配置 Next.js — SE2 会处理
  • ❌ 手动连接钱包 — SE2 已预先配置 RainbowKit
  • ❌ 编辑 deployedContracts.ts — 它由 yarn deploy 自动生成
  • ❌ 在 scaffold.config.ts 中硬编码 API 密钥 — 使用 .env.local
  • ❌ 在生产环境中使用 mainnet.base.org — 使用 Alchemy 或类似服务

资源

评论

支持 Markdown