mcmaster-fast 是做什么的?
让其他站点也拥有 mcmaster.com 的体验:首屏渲染在几十毫秒内,下一页面在URL更新前加载完成。
技术栈无关。McMaster 在 ASP.NET、YUI 和 ScriptCombiner 上实现了这一点。关键在于顺序和请求数量,而非框架时尚。
他们实际的做法
根据现场站点观察(2026-09-13)以及 Wes Bos 的拆解分析(klinke.studio 笔记):
| 层级 | McMaster 的做法 | 为何感觉即时 |
|---|---|---|
| 首字节 | 服务端渲染的 HTML。浏览器在 JS 执行前即可绘制。热壳模式下 FCP ~64ms,TTFB ~19ms。 | 用户看到页面,而不是等待 bundle 加载时的转圈。 |
| 壳 | #ShellLayout_Cntnr + #MainContent。头部/购物车保持挂载。使用 history.pushState。 | 点击分类时,同一头部节点保持,内容在 35ms 内交换。 |
| 预测 | 悬停/意图触发预取下一个 HTML,在点击之前。 | 点击时相当于缓存命中 + DOM 交换。 |
| 重复访问 | 针对 GET 导航(非 PDF)启用 Service Worker 缓存优先。首次加载后缓存主页。 | 原始 HTML 约需 200ms (mc-turn);SW 本地提供服务。 |
| 请求瀑布 | 对图片主机使用 dns-prefetch。preload woff2 字体、Logo、LCP 精灵图、页面 JS/CSS、ShellDynamic.aspx。 | 浏览器在 CSS 发现前开始加载字体/LCP。 |
| CSS | 约 32KB 通用 CSS 内联在 <head> 的 <style> 中。其余通过页面特定的合并器加载。 | 首次布局无需额外 CSS 请求。 |
| JS | 页面特定的 ScriptCombiner 合并包 (?files=…)。异步加载。WebParts 在绘制后加载。 | 分类页面不会下载结账代码。 |
| 资源 | 版本化 URL (/mv1789156784/, ?ver=)。Cache-Control: public,immutable,max-age=31536000。图片主机 images1.mcmaster.com。平铺网格使用精灵图。 | 一年长缓存,无失效问题,请求数极少。 |
| 稳定性 | 预留盒子/精灵图。测量 CLS 0。 | 图片到达时无重排。 |
| 权重 | 第一方分析 (/trk/)。无广告。CSP 锁定到 *.mcmaster.com。 | 页面本身就是产品。 |
HTML 文档本身是 Cache-Control: no-cache 且 Akamai 上标记为 x-check-cacheable: NO。不要 复制“CDN 缓存所有 HTML”。他们在浏览器中缓存壳,并在边缘缓存不可变静态文件。
优先级阶梯
在热缓存下达到约 200ms LCP 即可停止。不要在同一个 PR 中同时安装 Workbox、精灵图管道和推测规则。
- 提供浏览器可绘制的 HTML。 SSR 或静态 HTML。首次视图不由客户端渲染。移除构建首屏的 JS。
- 解锁首屏绘制。 只内联首屏以上的 CSS(或一个小的阻塞样式表)。
preloadLCP 图片和 woff2 字体(带crossorigin)。为每个图片设置width/height(或 CSS aspect-ratio)。 - 不可变静态文件。 指纹或版本查询。
Cache-Control: public, immutable, max-age=3150000。 - 持久化壳 + 内容交换。 共享布局。下一次导航替换一个内容节点并执行
pushState。不要重新挂载头部。 - 意图预取。 在悬停/视口可见时推测下一个文档。设置上限。永远不要预取结账、搜索 API 或认证后的 HTML。
- 导航 SW(可选)。 对公共壳/主页使用缓存优先的 GET 导航。部署时清空。从页面中失效,而非聪明的 SW。如果站点主要是私有内容,则跳过。
- 页面特定 JS。 路由拆分。将分析延迟到空闲时执行。删除不是产品的第三方标签。
- 精灵图/图片主机 仅当你在一个视图中包含数十个小图标时才需要。HTTP/2 加上少量压缩图片就足以满足需求。
智能体工作流
当要求以这种方式加速网站时:
- 跟踪真实的首屏加载和一次应用内导航(网络 + 绘制内容)。指出当前的 LCP 元素和阻塞它的 JS。
- 应用缺失的最低阶梯层级。除非用户要求全面改进,否则每次只做一个改动。
- 优先使用仓库中已有的平台特性(如 Next
<Link>、next/font、App Router 布局),而不是新库。 - 每次改动后,留下一个检查项:LCP / FCP 数值,或一个小断言,确认客户端导航时壳节点被复用。
- 阅读 techniques.md 了解要实现的层级的具体方法。阅读 recipes.md 了解 Next.js / 纯 HTML / 现有 SPA 的映射。
硬性规则
- HTML 是产品。JS 是可选的增强。
- 预取是提示,不是爬虫。仅限于同源 GET 文档。
- 个性化 HTML 使用
no-store或仅 SW 缓存并设置短 TTL。永远不要将购物车/账户 HTML 放在共享 CDN 缓存上。 - 不要添加拦截所有资源的 Service Worker。仅限导航文档,匹配 McMaster 的
ServiceWorkerJS.aspx。 - 不要复制 YUI、精灵图或 ASP.NET。复制的是操作顺序。
- 不要为了修复问题而将快速 HTML 页面“现代化”成客户端 SPA。
- 第三方脚本(广告、标签管理器、聊天)被假定为有罪。让它们远离首屏绘制,或者删除它们。
- 当跳过低价值的层级时,使用
ponytail:标记快捷方式。
完成标志
- 首次访问:HTML 在任何应用 bundle 执行之前绘制。LCP 是服务端发送的元素,而非客户端渲染的。
- 下次点击:壳保持挂载;仅内容区域交换。
- 对主页/壳的重复访问:本地或内存缓存提供服务。
- 字体和 LCP 图片在前 1-2 个往返中加载,而不是在 CSS 之后才发现。
- 在您接触的页面上,CLS 保持接近 0。