mcpField
S
stitch::extract-static-html

stitch::extract-static-html

github.com/google-labs-code开发8.6k10.1k 次安装10 周前更新
代码仓库

关于 stitch::extract-static-html

该技能指导从 Web 应用提取独立静态 HTML,面向需要保存页面快照的开发者。它要求用户先选择方案,并提供 Puppeteer、浏览器交互和静态回退流程。

主要功能

  1. 01Puppeteer 快照并内联样式与图片
  2. 02浏览器交互后提取 DOM
  3. 03支持登录脚本与多路由页面
  4. 04可配置视口、等待时间和页面清理
  5. 05提供无法运行应用时的静态回退

适用场景

  1. 01将本地 Web 页面保存为独立 HTML
  2. 02登录后捕获受保护页面
  3. 03先操作页面再提取特定状态
  4. 04应用无法启动时手动构建页面快照

安装

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

$npx skills add https://github.com/google-labs-code/stitch-skills --skill stitch::extract-static-html

安装后在 Claude Code 中输入/stitch::extract-static-html确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

scripts/
post_process.ts
extract_inline_html.ts
snapshot.ts

详细介绍

提取静态 HTML

从任意 Web 应用中提取独立的静态 HTML 文件。

选择使用哪种策略

继续之前,必须先询问用户选择使用哪种策略。清晰地列出选项,推荐策略 A作为默认首选,并简要总结每种选项的优缺点,帮助用户做出明智的决定。

策略 A(Puppeteer)策略 B(浏览器子 Agent)
适用场景应用在本地运行,且没有身份验证限制需要先与页面交互(点击、填写表单)
保真度最高 — 可解析计算后的样式高 — 已渲染的 DOM
设置无需设置 — 不需要 mock无需设置 — 不需要 mock
框架任意任意
输出写入文件 — 无大小限制可能在 Agent 上下文中被截断

警告

检查点 — 需要用户确认。 你必须询问用户偏好哪种策略,然后才能继续。 展示上方的对比表,推荐策略 A 作为默认选项,并 等待用户明确批准。不要自行做出决定,也不要在用户确认前继续操作。


策略 A:Puppeteer 快照(推荐)

启动无头 Chrome,捕获完全渲染后的 DOM,并生成独立的 HTML 文件,其中所有 CSS 均已内联,图片则以 base64 格式嵌入。适用于任意框架 — 无需 MockPage.jsx。

前提条件
  • 应用在本地运行(例如,npm run dev)
  • Node.js 中可使用 puppeteer(检查:node -e "require('puppeteer')")
工作流
  1. 启动应用并记下端口。

    警告

    检查点 — 需要用户确认。 启动本地服务器后,运行快照脚本或启动浏览器子 Agent 之前, 必须暂停并征求用户确认。向用户告知 URL 和端口,以便他们确认应用 正在运行且渲染正常。用户确认之前,不要继续执行快照 步骤。

  2. 运行快照脚本:

    npx tsx <SKILL_DIR>/scripts/snapshot.ts \
      --url http://localhost:5173 \
      --output .stitch/home.html \
      --wait 2000
    
  3. 多个页面 — 每个路由运行一次:

    npx tsx <SKILL_DIR>/scripts/snapshot.ts \
      --url http://localhost:5173 --output .stitch/home.html --wait 2000
    npx tsx <SKILL_DIR>/scripts/snapshot.ts \
      --url http://localhost:5173/pricing --output .stitch/pricing.html --wait 2000
    npx tsx <SKILL_DIR>/scripts/snapshot.ts \
      --url http://localhost:5173/dashboard --output .stitch/dashboard.html --wait 2000 --html-class dark
    
  4. 清理开发服务器: 如果专门为提取快照而启动了本地开发服务器,请务必在提取完成后停止服务器进程或终止后台任务。

脚本标志
标志默认值描述
--url(必需)要捕获的 URL
--output(必需)输出文件路径
--wait1000网络空闲后额外等待的时间(ms)。对于延迟加载的应用,请适当增加。
--viewport1280x800视口大小,格式为 WIDTHxHEIGHT
--html-class—<html> 元素的类(例如 dark)
--remove-fixedfalse移除固定/粘性元素(Cookie 横幅、聊天组件)
--full-heightfalse将视口调整为完整的滚动高度
--title—覆盖页面标题(设置为路由路径,例如 /dashboard 或 /settings/profile)
--auth-script—JS/TS 模块的路径;该模块需导出默认的 async (page) => void 函数以进行身份验证
--inline-canvasfalse将 <canvas> 元素(ECharts、Chart.js、D3)转换为 base64 <img> 标签
自动完成的操作
  • 从 document.styleSheets 捕获所有 CSSOM 规则(保留动态 Vite/Tailwind 开发样式和 CSS-in-JS)
  • 将所有 <link rel="stylesheet"> 内联为 <style> 块
  • 将 <img> 的 src 和 srcset 转换为 base64 数据 URI(跳过外部字体)
  • 将同源和相对路径的图标字体文件(@font-face)内联为 base64 数据 URI,避免连字被渲染为 ASCII 文本
  • 将 <source srcset> URL 内联为 base64
  • 移除加载失败或失效的 srcset 条目,让浏览器回退到内联的 src
  • 移除 <script> 标签、Vite HMR 开发样式块(createHotContext、import.meta.hot)和开发覆盖层
  • 内联前解析相对 CSS url() 路径
框架说明
框架说明
React + Vite开箱即用。--wait 1000。
Next.jsSSR 水合需要设置 --wait 3000。URL:http://localhost:3000。/_next/image 中的 <img srcset> 会自动内联为 base64。
Angular (@angular/cli / v17+)使用 ng serve 开箱即用(默认 URL:http://localhost:4200)。对于 Angular Material / PrimeNG 动画水合和延迟加载路由,设置 --wait 2000。
Vue / Nuxt开箱即用。
Svelte / SvelteKit开箱即用。
Storybook使用故事 URL:--url http://localhost:6006/?path=/story/...
SSR (Webpack)可能需要更长的 --wait。
故障排除
问题解决方案
图片缺失增加 --wait
服务停止后图片显示为损坏确认 srcset 已内联——检查日志中是否有“已内联 N 张图片”。如果 srcset URL 加载失败,会自动移除,以便使用内联的 src。
图标显示为文本 / 使用未设置样式的 Serif 字体确保 snapshot.ts 从 document.styleSheets 捕获 CSSOM(步骤 0),并将同源图标字体(@font-face)内联为 base64 数据 URI。
Next.js /_next/image 未内联确保运行快照时开发服务正在运行——脚本会从运行中的服务获取优化后的图片。
未应用深色模式--html-class dark
输出中包含 Cookie 横幅--remove-fixed
页面需要登录使用 --auth-script ./auth.ts(见下方“受身份验证保护的页面”)
图表显示为空白框使用 --inline-canvas 将 <canvas> 序列化为 base64 <img>
Cannot find module 'puppeteer'npm install -g puppeteer
受身份验证保护的页面

对于带有登录守卫的应用(Vue Router beforeEach、React ProtectedRoute 等),创建一个小型身份验证脚本,在 Puppeteer 会话中运行:

// auth-myapp.ts
import type { Page } from 'puppeteer';

export default async function authenticate(page: Page) {
  // Example 1: Fill and submit a login form
  await page.type('#username', 'admin');
  await page.type('#password', 'password123');
  await page.click('#login-button');
  await page.waitForNavigation({ waitUntil: 'networkidle2' });

  // Example 2: Inject cookies/localStorage directly
  // await page.evaluate(() => {
  //   localStorage.setItem('token', 'mock-jwt-token');
  // });

  // Example 3: Call the app's own login API via module injection (Vue/Vite)
  // await page.evaluate(() => {
  //   return new Promise((resolve) => {
  //     const script = document.createElement('script');
  //     script.type = 'module';
  //     script.textContent = `
  //       import { useUserStore } from '/src/store/modules/user.ts';
  //       import { fetchLogin } from '/src/api/auth.ts';
  //       const res = await fetchLogin({ userName: 'Admin', password: '123456' });
  //       useUserStore().setToken(res.token, res.refreshToken);
  //       window.dispatchEvent(new CustomEvent('auth-done'));
  //     `;
  //     document.head.appendChild(script);
  //     window.addEventListener('auth-done', () => resolve(true), { once: true });
  //   });
  // });
}

然后使用它:

npx tsx <SKILL_DIR>/scripts/snapshot.ts \
  --url http://localhost:5173/#/dashboard \
  --output .stitch/dashboard.html \
  --auth-script ./auth-myapp.ts \
  --inline-canvas \
  --wait 5000

脚本会先导航到 --url(此时可能会重定向到登录页),运行你的身份验证函数,然后使用已通过身份验证的会话重新导航到原始 --url。


策略 B:浏览器子 Agent 捕获

当你需要在捕获前与页面交互(点击按钮、填写表单、切换标签页)时使用。浏览器子 Agent 可让你完全控制页面,但大型页面的输出可能会被截断。

工作流
  1. 在本地启动应用。

  2. 使用浏览器子 Agent 导航。

  3. 按需交互(点击、滚动、填写表单)。

  4. 提取 DOM:document.documentElement.outerHTML

    警告

    大型页面的内容可能会被截断。处理方法:

    • 提取前移除 <style> 标签:document.querySelectorAll('style').forEach(el => el.remove())
    • 静态地重新添加样式(Tailwind CDN 链接、源 CSS)
  5. 保存到文件。


附录:静态回退方案 (MockPage.jsx)

说明

当应用无法在本地运行时(依赖损坏、缺少后端、无法绕过的身份验证限制),可将此方法作为最后手段。它需要手动将 React 组件扁平化为单个 JSX 文件。只要条件允许,优先使用策略 A。

适用情况
  • 应用完全无法在本地运行
  • 页面需要身份验证,且没有模拟或绕过方案
  • 你需要通过导航无法进入的特定 UI 状态(错误界面、空状态)
快速参考
npx tsx <SKILL_DIR>/scripts/extract_inline_html.ts \
  --index-css src/css/App.css \
  --extra-css index.html \
  --outdir .stitch \
  --page src/MockPage.jsx:Page.html:"Page Title"

关键标志:--no-tailwind(非 Tailwind 应用)、--html-class dark(深色模式)、--css-files(额外的 CSS 文件)。

自动检测:自动检测 Tailwind 配置。@apply 指令会自动使用 <style type="text/tailwindcss">。

MockPage.jsx 规则
  1. 包含完整布局——页眉、侧边栏、页脚(先阅读 App.js)
  2. 展开所有条件判断——选择一种状态,移除所有三元表达式和 && 条件
  3. 将所有数据硬编码——将 {variable} 替换为具体值,展开 .map() 循环
  4. 保留 Logo——使用带有本地路径的 <img>(后处理会将其内联)
  5. 移除浮动元素——Cookie 横幅、聊天小组件、反馈按钮
后处理

内联本地图片:

npx tsx <SKILL_DIR>/scripts/post_process.ts \
  .stitch/Page.html --base-dir <app-directory>

评论

支持 Markdown