用 React 构建静态作品集:从页面生成到 Pages 部署
记录这次双语作品集的静态生成、JavaScript 体积优化,以及 Cloudflare Pages 部署中遇到的入口和生产分支问题。
为什么使用构建时渲染 #
这个作品集主要展示个人介绍、项目和技术笔记。正文不需要登录,也不依赖实时请求。项目使用 React 组织组件,在构建时生成 HTML,再交给 Cloudflare Pages 托管。
构建分为四步:TypeScript 检查、浏览器资源打包、构建端渲染模块打包、逐个路由生成静态页面。部署目录是 dist,dist-ssr 只供构建脚本调用,不是线上运行的后端。
中英文首页分别位于 / 和 /zh/。笔记使用 Markdown 编写,在构建时校验标题、日期、语言、分类及草稿状态,再生成对应页面。草稿不会进入公开列表和站点地图。
React 组件与浏览器交互分开 #
最初的版本在浏览器中使用 React hydration 接管页面。对于这次作品集,交互主要是导航定位、语言切换时保留所在区域、菜单关闭后的焦点处理,以及 Escape 收起节点。
这些功能改为少量原生 TypeScript 后,React 仍负责构建时的页面生成,浏览器不再下载 React 运行时和全部笔记数据。菜单和概念节点使用原生 details,即使关闭 JavaScript,也可以展开和阅读。
在发布首篇笔记前的六页构建中,JavaScript 从约 78.10 KB gzip 降至 1362 字节,CSS 为 3702 字节。这里的数字来自构建文件的 gzip 汇总,不是移动网络下的实测加载时间,也不能据此宣称 LCP、CLS 或 INP 已通过。
部署时遇到的两个问题 #
第一次部署选择了 Workers 创建流程。代码构建已经成功,随后执行 npx wrangler deploy,日志停在交互式配置提示。最终改用 Pages 的 Git 仓库导入入口,填写构建命令 npm run build、输出目录 dist,完成部署。
第二个问题更隐蔽:仓库实际生产分支是 master,代码却按 main 判断是否允许搜索引擎索引。网站能够打开,但正式页面带有 noindex,robots.txt 禁止抓取,站点地图为空。修复时把分支判断和数据更新工作流都对齐到实际分支,而不是只看部署面板的成功状态。
SITE_URL 也必须填写实际访问地址。它用于 canonical、分享图片地址和站点地图;未配置时项目会使用本地地址并禁止索引。
把验证留在维护流程里 #
npm test 会构建网站、执行自动化测试,并检查本地链接、资源和体积预算。GitHub 统计在独立任务中获取,失败时保留已有快照,避免普通页面构建依赖外部 API。
上线后还要检查 HTTP 状态、缓存、压缩、手机布局和键盘操作。真实设备上的性能和辅助技术检查仍需要单独进行。部署成功只是文件已发布,页面内容、索引策略和后续更新能否正常工作,还需要逐项确认。
本地检查和预览可以依次执行:
npm run test
npm run preview