项目 · 已发布
工作室网站重建
把一个继承了重型 SaaS 模板假设的旧站,重建成真正符合工作室需求的小型静态网站。
为什么做
旧工作室网站继承的是 SaaS starter 的产品假设,而不是一个小型软件工作室真正需要的能力。线上站点既保留了过时定位和模板页面,也存在 sitemap、canonical 等搜索可见性问题,同时运行时复杂度明显高于这个网站的真实需求。
之前怎么做
旧 production 来自 ShipAny / Next.js / OpenNext 技术路线。公开现场仍有模板化 Blog 与 Showcases 页面、重复 canonical、指向 your-domain.com 的错误 sitemap,以及与当前定位冲突的 creator-economy metadata。
我们当时的判断
如果架构真正跟着网站职责走,一个内容型工作室网站应该更简单:公开页面直接输出静态 HTML,Projects / Journal 用 Markdown/MDX 管理,英文默认、中文辅助;只有出现真实需求时,才单独增加动态服务。
怎么验证
先冻结旧站能观察到的 URL 和 SEO 现场,再建立没有旧兼容负担的新 repo;用 Astro 实现双语信息架构;部署到隔离的 Cloudflare Workers Static Assets staging;在完全不碰 production 的情况下验证状态码、canonical / hreflang、raw HTML、crawler access 和响应式表现。
做了什么
一个 Astro 7 静态站:包含英文与简体中文 URL、Projects / Journal 内容集合、每页唯一 canonical、reciprocal hreflang + x-default、自动 sitemap、按环境切换的 robots 策略、真实 404、trailing-slash normalization 和独立 Cloudflare staging。首页随后又加入可逆的 Opening → Focus → Release → Expanded 滚动叙事,同时保留同一份语义化 DOM,以及 no-JS、reduced-motion、tablet 和 mobile fallback。
真实使用里看到了什么
最终验收 build 的 Astro check 为 0 errors / 0 warnings / 0 hints。隔离 Cloudflare 环境真实验证:首页可逆叙事在 1440×900 下复现通过;375px mobile 与 1024px tablet 使用正常流 fallback;reduced-motion 和 raw HTML 完整可用;document scroll width 与 viewport 保持一致;缺失路由返回真实 404。随后 production cutover 把同一个 apex Custom Domain object 原子转移到独立 Static Assets Worker,并在切换窗口内暂时保留 legacy Worker 作为回滚边界。切换后的 live crawl 与 Chrome 回归再次通过双语路由、canonical/hreflang、redirect、sitemap/robots、Email + X 联系状态、真实 404 与无横向溢出验收。新 production 路径经过后续发布与回归稳定后,未再使用的 legacy Worker 与其专用 D1 database 已正式退役。
现在的结果
V1 已正式运行在 inkblocklab.com 的独立 Cloudflare Workers Static Assets Worker 上。英文与中文作为同一版本同步上线,并保持已验收的 SEO、redirect、响应式、可访问性与 Email + X 联系合同。旧 ShipAny/OpenNext production Worker 与其专用 D1 database 已退役;current production 不再依赖旧 runtime。`Inkblock Lab` 仍是 V1 临时公开身份;locale suggestion 继续延后。
学到了什么
- starter template 只有在它的假设与产品匹配时才是加速器;否则预置功能会变成架构债。
- 迁移应该保留真正有业务价值的 URL 和搜索权益,而不是为了迁移而保留旧 runtime。
- 状态码、canonical、hreflang、raw HTML、crawler access 与 404 这类技术可见性问题,最好在 production 前就做成明确验收项。
- 响应式截图只有在 viewport 真的满足测试条件时才是证据;headless browser 的最小窗口限制可能制造假溢出。
涉及的能力
Web 工程 · Cloudflare · 技术 SEO · 国际化 · 产品架构
为什么把网站本身也当成一个 Project
工作室网站不只是放作品的页面。它要解释我们做什么、沉淀真实项目、发布构建记录,也要成为未来客户项目和自有产品的统一入口。
所以这次重建本身就是一条很合适的公开证据:先看网站真正需要完成什么,再删掉不服务于这个目标的架构。
我们没有为了“迁移完整”去恢复旧系统
旧源码已经删除,而且新站本来就不需要 auth、subscription、credits、dashboard、RBAC、database 或完整 SSR runtime。
真正可能有业务价值的是另一组东西:域名历史、旧 URL、潜在搜索权益,以及旧站已经公开过的事实。
所以这次迁移刻意把两件事拆开:
- 保留业务价值:旧 URL、可观察的搜索现场、可能需要的 redirect;
- 不保留架构包袱:ShipAny / Next.js / OpenNext 的旧 runtime 不因为“以前用了”就继续继承。
先在隔离环境把容易出错的地方测清楚
验证阶段没有直接把新站接到 production domain。
我们先在独立的 workers.dev staging 上验证:
- 核心页面是否真的返回 200;
- 缺失 URL 是否是真 404;
- canonical 与 EN/ZH hreflang 是否唯一、互相对应;
- sitemap 是否只包含真实 URL;
- staging 是否保持 noindex;
- 主要正文是否直接存在于 raw HTML;
- Googlebot、Bingbot、OAI-SearchBot 和普通浏览器是否都能访问;
- mobile / tablet / desktop 是否存在横向溢出或结构破坏。
首页后来增加了滚动叙事和更多双语内容,但 static-first 架构仍然不需要因此升级成 SSR、数据库或更重的应用 runtime。这比最初的 framework 对比更能说明架构选择是否合适。
为什么把 release 单独验收
英文版上线前检查、中文版原生本土化、临时公开名称,以及 production build / crawl rehearsal 都已经分别完成。两种语言共享事实,但没有被做成逐句镜像。
因此上线前没有继续无限精修首页和内容层,而是把 release engineering 单独处理:先识别旧 production binding 的精确 Cloudflare 对象、在 cutover 窗口内冻结可确定回滚和 redirect,再执行 binding-only cutover 与 live crawl。最终 apex 切到新的 Static Assets Worker,旧 Worker 在切换阶段暂时保持不变;新 production 路径经过后续发布与回归稳定后,旧 Worker 与其专用 D1 database 已退役。