用途
webflow-migrate 用于将用户自己托管的 Webflow 网站迁移为可自托管的静态站点。它使用 wget 镜像已发布站点,然后清理资源、URL 和 Webflow 残留内容。适用情况包括:用户想在不付费购买 Webflow 代码导出的前提下迁出 Webflow;用户想在 Render、Netlify、Vercel 等平台自托管 Webflow 站点;用户想要一份可编辑、可维护的 Webflow 站点本地副本。
前提条件
站点必须已发布且可公开访问(wget 镜像的是线上站点);必须安装 wget(macOS/Linux 自带);可选使用 agent-browser 技能进行可视化验证。
迁移工作流
各阶段需按顺序执行,不得跳过。
阶段 1:镜像线上站点
使用带 CDN 跨域下载的 wget 下载整个站点,包括托管在 Webflow CDN 上的资源。关键参数包括:--span-hosts --domains=...,cdn.prod.website-files.com(必需,因为 Webflow 从独立 CDN 域提供资源)、--convert-links(将绝对 URL 重写为相对路径)、--page-requisites(下载每页引用的 CSS、JS、图片、字体)、--adjust-extension(为简洁 URL 添加 .html 扩展名)。常见问题:URL 编码路径(%2F、%20)的视频可能无法自动下载,需检查并手动下载;CDN 的 robots.txt 返回 403 属预期且无害;--page-requisites 只跟踪 src 和 href 属性,内联 background-image:url(...) 资源不会被下载,需在阶段 2 单独提取获取;Webflow 使用多个 CDN 站点 ID,一个用于站点级资源,另一个用于 CMS 集合内容,镜像后需检查 cdn.prod.website-files.com/ 下的多个目录。
阶段 2:整理为清晰结构
创建可部署目录结构 site/,包含 index.html、privacy.html、terms.html 等顶层页面及 careers/、post/ 等子目录,以及 assets/css、assets/js、assets/images。将下载目录中的 HTML 文件复制到 site/ 并保留子目录结构;将 CSS、JS、图片媒体分别复制到对应 assets 子目录,注意可能有多个站点 ID。需提取并下载 wget 未下载的 background-image 资源:用 grep 抓取 HTML 中指向 cdn.prod.website-files.com 的 background-image:url() 引用,提取 URL 后逐个用 wget 下载。对于因双重编码产生 0 字节的下载(Webflow 在 CMS 文件名中将特殊字符双重编码,如 %2520 代表空格、%252B 代表 +、%2526 代表 &),需用双重编码的 CDN URL 重试。整理完成后删除原始 wget 下载目录。
阶段 3:重写资源 URL
--convert-links 会将 URL 重写为相对路径,需进一步重写以匹配新的 assets/ 结构。注意子目录页面(如 careers/、post/)需使用 ../assets/ 而非 assets/,顶层与子目录页面应分别处理。步骤包括:重写相对 CDN 路径;重写绝对 CDN URL(--convert-links 只重写 src 和 href 属性,内联 background-image:url(...) 样式保留绝对 CDN URL,需第二遍处理);修复被破坏的 background-image:url() 内联样式(这是最常见的损坏,wget 的 --convert-links 会为内联样式 URL 生成垃圾内容);修复双重编码字符(%2520 → %20、%252B → %2B、%2526 → %26);验证无 CDN 引用残留,剩余引用通常位于 meta OG 标签或深层嵌套的内联样式中。
阶段 4:修复已知 Webflow 导出问题
这些问题几乎每次 Webflow 迁移都会出现。4a 视频源损坏:Webflow 视频 URL 路径含 %2F,在 URL 重写过程中会损坏,source 标签被截断,需检查所有 video 元素的 source src 属性及 poster 引用。4b Webflow 表单无法工作:Webflow 表单使用 method=get 且无 action URL,依赖 Webflow 后端,自托管站点上不会工作,可选择删除表单、替换为表单服务(Formspree、Netlify Forms、Basin)或自建表单处理器。4c 过时/模板文案:检查并更新 Coming Soon、Join Waitlist、Beta、Early Access、TestFlight 等文案,模板占位链接,版权年份,以及 href 域与显示文本不一致的破损 mailto 链接。4d Webflow 数据属性:data-wf-domain、data-wf-page、data-wf-site、data-wf-page-id、data-wf-element-id 及「Last Published」注释在无 Webflow 托管时无用途,可移除(可选,仅为保持 HTML 整洁)。4e 将编辑传播到所有页面:Webflow 站点各页通常共享相同页眉页脚,若在 index.html 中编辑页脚,必须对每个 HTML 页面应用相同编辑;还需检查子页面页脚导航链接是否指向 index.html#section 而非 subpage.html#section。
阶段 5:验证
可使用 agent-browser 进行可视化验证,启动本地服务器后截图并与线上站点比较。同时运行全面的资源引用检查(含 background-image:url() 引用),检查缺失资源,可发现单文件检查遗漏的问题:子页面引用、background-image URL 和双重编码文件名。
阶段 6:部署
Render(静态站点):构建命令 echo 'No build required',发布路径 ./site;也可使用 Render MCP。Netlify:npx netlify-cli deploy --dir=./site --prod。Vercel:npx vercel ./site --prod。部署后更新自定义域名的 DNS 记录指向新主机。
阶段 7:迁移后清理(可选)
站点上线后的低优先级改进:自托管外部脚本(CloudFront 的 jQuery、Google 的 WebFont loader);移除未使用的 Webflow JS 模块(500KB+ 的 webflow 运行时含 Lightbox、Slider、Lottie 等,许多站点未使用);优化图片(PNG 转 WebP、修复响应式图片过大的 sizes 属性);替换 Embedly YouTube 嵌入(改用直接 YouTube iframe 或点击加载外观);为首屏主图添加 loading="eager"(Webflow 将所有图片设为 lazy)。
限制
JavaScript 交互:Webflow 的 JS 运行时(webflow.*.js)处理动画、标签页、下拉菜单等,会继续工作,但它是约 500KB 的单体文件;若想缩减需重写交互。CMS 内容:若站点使用 CMS 集合,镜像站点捕获的是镜像时的静态 HTML,动态内容不会更新。表单:如前所述,无后端时 Webflow 表单不会工作。站点搜索:Webflow 原生搜索不会工作,可使用 Algolia、Pagefind 或类似工具。