
Nx 仓库 Netlify Edge Functions 实战Framer 代理、URL 重写与多源 Sitemap 聚合【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx导读本篇文章围绕 netlify/edge-functions/README.md 展开深入解析 Nx 官方仓库nx-dev 网站在 Netlify 边缘网络上的关键部署工程为什么 Edge Functions 必须放在仓库根目录以及rewrite-framer-urls.ts与additional-sitemaps.ts两个边缘函数如何实现全站代理 Framer 页面 流式 URL 重写 多源 Sitemap 聚合。读完本文你将掌握 Netlify Edge Functions 的目录约定、config声明式路由与excludedPath排除规则、跨 chunk 安全的流式字符串替换以及如何用边缘函数统一 canonical URL、避免搜索引擎重复收录。Edge Functions 为何必须放在仓库根目录Nx 官网nx.dev的前身是位于 nx-dev/nx-dev/ 的 Next.js 应用而 Netlify 站点在部署配置上有一个关键约束Edge Functions 的默认发现目录是相对base directory的netlify/edge-functions/。文档明确记录了两条决定目录位置的配置Base directory.仓库根目录Publish directory./nx-dev/nx-dev/.next也就是说Netlify 构建时以仓库根目录为基准去寻找netlify/edge-functions/因此边缘函数只能放在仓库根目录的 netlify/edge-functions/ 下而不是nx-dev/nx-dev/内部。文档还记录了一次失败的尝试曾在 netlify.toml 中配置自定义路径edge_functions nx-dev/nx-dev/netlify/edge-functions但 Netlify 构建系统并不识别该配置项。这是一个重要的经验教训Edge Functions 目录路径目前不受edge_functions配置控制必须遵守默认约定。从源码结构看nx-dev/nx-dev/netlify.toml 中只存在[[headers]]、[[plugins]]、[[redirects]]与[functions]配置也确实没有edge_functions自定义路径相关配置印证了文档的说法。边缘函数全景四个文件各司其职netlify/edge-functions/目录下共有四个边缘函数文档重点介绍两个代理类函数另两个为统计分析类文件职责rewrite-framer-urls.ts默认将全部请求代理到 Framer并流式重写 HTML 中的域名additional-sitemaps.ts代理根 Sitemap 索引引用的各来源 Sitemap 并重写 URLtrack-page-requests.ts对 HTML 页面请求上报 GA4 服务端页面浏览事件track-asset-requests.ts对.md/.txt文档资产请求上报 GA4 事件四个函数都导出一个默认handler和config这是 Netlify Edge Functions 的标准形态。下面聚焦文档重点讲解的两个函数。rewrite-framer-urls.ts全站代理与流式 URL 重写rewrite-framer-urls.ts 的核心思路是nx.dev 的页面托管在 Framer 上但对外必须表现为 nx.dev 自己的站点。边缘函数默认把所有请求代理到 Framer并把响应 HTML 中出现的 Framer 域名替换为https://nx.dev从而保证canonical 链接指向 nx.dev避免搜索引擎重复收录meta 标签与页面内链接品牌一致爬虫看到的 URL 空间统一收敛到官方域名。配置声明全路径匹配 HTML 过滤 排除清单export const config { path: [/*], accept: [text/html], excludedPath: [ /robots.txt, /sitemap.xml, /sitemap-0.xml, /llms.txt, /llms-full.txt, /docs, /docs/*, /api/*, /courses/*, /_next/*, /.netlify/*, // ... 大量遗留文档路径与静态资源目录 /ci, /cli, /concepts, /features, /recipes, /blog/2024-05-08-nx-19-release, /blog/evolving-nx, /documentation/*, /assets/*, /images/*, /fonts/*, /videos/*, /data/*, /socials/*, /favicon/*, ], };path: [/*]匹配全站路径accept: [text/html]只处理 HTML 请求显著节省边缘计算开销excludedPathSEO 关键文件如/robots.txt、/sitemap.xml、/llms.txt、/llms-full.txt、Next.js 内部路径/_next/*、/.netlify/*、全部文档站/docs/*以及遗留文档路径/ci、/cli、/concepts、/recipes等都必须绕过代理由 Next.js 或_redirects301 规则直接处理。排除清单中的遗留路径非常值得注意它们作为旧版文档的落地页/反向链接目标如果被代理到 Framer 将返回错误页面因此必须以精确路径形式保留在排除列表中而让代理继续服务其余所有页面。运行时决策bot 探针拦截 → Next.js 路径直通 → Blog 代理 → Framer 代理handler的执行顺序体现了完整的防御与路由逻辑rewrite-framer-urls.ts规范化路径url.pathname.replace(/^\//, /)折叠开头的多个/防止//wp/...这类协议相对 URL 攻击把wp提升为上游主机。Bot 探针拦截用正则/(wp-(includes|admin|content)|xmlrpc\.php|wlwmanifest|\.env|\.git\/)/i识别 WordPress/漏洞扫描器常见探测路径直接返回 404。这是文档未展开但源码中真实存在的安全防护。Next.js 路径直通nextjsPaths集合中的路径如/courses、/podcast、/ai-chat、/resources-library、/whitepaper-fast-ci、/500调用context.next()交给 Next.js当配置了BLOG_URL时/blog与/changelog从该集合移除改为代理到独立博客站点。Blog 代理/blog、/changelog及其子路径在BLOG_URL存在时代理到BLOG_URL pathname并透传 User-Agent、Accept、Accept-Language 与全部查询参数。Framer 代理其余所有路径在NEXT_PUBLIC_FRAMER_URL存在时代理到 Framer若该环境变量未配置则回退context.next()。跨 chunk 安全的流式替换实现代理后对 HTML 做字符串替换最棘手的边界问题是匹配串可能横跨两个网络 chunk 的边界。rewrite-framer-urls.ts 用TransformStream实现了一个健壮的解决方案function createStreamingReplace(search, replace) { let buffer ; return new TransformStream({ transform(chunk, controller) { buffer chunk; const safeEnd buffer.length - (search.length - 1); if (safeEnd 0) { controller.enqueue(buffer.substring(0, safeEnd).replaceAll(search, replace)); buffer buffer.substring(safeEnd); } }, flush(controller) { if (buffer) controller.enqueue(buffer.replaceAll(search, replace)); }, }); }其原理是始终在缓冲区末尾保留search.length - 1个字符不处理只有确认后续 chunk 不可能再补全匹配串时才把安全区刷出flush阶段再处理尾部残留。整条管道为response.body → TextDecoderStream → createStreamingReplace → TextEncoderStream同时删除Content-Length头因为替换会改变响应体大小。响应头增强代理响应被附加了多项安全与缓存头x-nx-edge-function: framer-proxy或blog-proxy标记由哪个边缘函数处理便于排障X-Frame-Options: DENY与Content-Security-Policy: frame-ancestors none防点击劫持与 nx-dev/nx-dev/netlify.toml 中的全局[[headers]]策略一致Cache-Control: public, max-age3600, must-revalidate与Netlify-CDN-Cache-Control: public, max-age3600, stale-while-revalidate86400边缘 CDN 一小时强缓存 24 小时 stale-while-revalidate缓存过期后先秒回旧内容再后台刷新Link: /llms.txt; reldescribedby; typetext/plain, /llms-full.txt; relservice-doc; typetext/plain, /sitemap.xml; relsitemap; typeapplication/xml按 RFC 8288 声明机器可读入口让 AI Agent 通过Link头发现 nx.dev 的 llms.txt 与 sitemap——这正是项目描述中amplifies both developers and AI agents理念在边缘层的落地。GA4 服务端埋点由于 Framer 代理路径没有经过context.next()track-page-requests.ts 的声明式顺序Netlify 按函数配置的字母序处理决定了它不会对代理路径触发。因此重写代理内部直接调用sendToGA4见 rewrite-framer-urls.ts在context.waitUntil中异步上报server_page_view事件payload 包含client_id从_gaCookie 解析、user_agent、基于 Netlifynetlify-agent-category头判定的is_ai_tool/is_bot标记以及country地理信息。客户端 ID 缺失时则用Math.random Date.now生成。additional-sitemaps.ts多源 Sitemap 聚合代理additional-sitemaps.ts 解决的是多来源站点Framer 独立博客如何统一贡献 sitemap的问题。文档给出了清晰的路由表路径上游环境变量/sitemap-1.xmlNEXT_PUBLIC_FRAMER_URL/sitemap.xmlNEXT_PUBLIC_FRAMER_URL/sitemap-2.xmlBLOG_URL/blog/sitemap.xmlBLOG_URL实现上用一张静态映射表驱动const sources { /sitemap-1.xml: { envVar: NEXT_PUBLIC_FRAMER_URL, path: /sitemap.xml }, /sitemap-2.xml: { envVar: BLOG_URL, path: /blog/sitemap.xml }, };处理流程additional-sitemaps.tsconfig.path仅匹配/sitemap-1.xml与/sitemap-2.xml两个精确路径计算量几乎为零未命中映射或对应环境变量未配置时context.next()放行向上游发起请求并透传 User-Agent、Accept上游非 2xx 时返回 502读取 XML 全文replaceAll(origin, https://nx.dev)将上游域名统一重写为 nx.dev强制设置content-type: application/xml; charsetutf-8、x-nx-edge-function: additional-sitemaps与Cache-Control: public, max-age3600, must-revalidate。将 sitemap 代理独立成函数而不是并入 Framer 代理是刻意的设计决策主代理可以保持accept: [text/html]以节省计算成本而 XML sitemap 不需要经过 HTML 流式重写管道。与根 Sitemap 索引的衔接这些聚合后的 sitemap 之所以是/sitemap-1.xml、/sitemap-2.xml是为了与根sitemap.xml索引配合。patch-sitemap-index.mjs 在构建后用脚本把额外 sitemap 追加进 next-sitemap 生成的索引const additionalSitemaps [ ${siteUrl}/sitemap-1.xml, ${siteUrl}/sitemap-2.xml, ${siteUrl}/docs/sitemap-index.xml, ]; // ...将 sitemaploc.../loc/sitemap 注入 /sitemapindex 之前也就是说根索引声明三个子 sitemap → 边缘函数把/sitemap-1.xml、/sitemap-2.xml分别反向代理到 Framer 与博客站点并重写域名 → 爬虫顺着索引抓到的全部 URL 都指向 nx.dev。整个链路保证了跨平台内容在搜索引擎视角下收敛为单一域名杜绝重复收录。环境变量总览文档与源码共同确认了以下环境变量在 Netlify 站点控制台配置变量用途缺失时的行为NEXT_PUBLIC_FRAMER_URLFramer 站点地址如https://nx.framer.websiteFramer 代理与/sitemap-1.xml的上游代理函数回退context.next()sitemap 返回 502 前由context.next()放行BLOG_URL独立博客站点地址/blog、/changelog与/sitemap-2.xml的上游blog 路径回退 Next.js/sitemap-2.xml放行GA_MEASUREMENT_ID/GA_API_SECRETGA4 Measurement Protocol 上报凭证未配置GA_API_SECRET时静默跳过上报打印 warn 日志从源码结构看Future边缘函数何时退役README 的Future部分指出一旦 nx-dev 的 Next.js 应用退役、所有页面迁移到 Astro 文档站本目录即可移除。仓库现状恰好印证了这一过渡正在进行astro-docs/ 已是一个完整的 Astro 文档站含 astro-docs/netlify.toml而 track-page-requests.ts 的排除清单中已出现/docs/_*、/docs/pagefind/*pagefind 是 Astro 站点的搜索索引等 Astro 产物路径说明文档站已纳入边缘层的统一分析体系。可以推断在完全迁移后Framer 代理与 sitemap 聚合职责将由 Astro 站点的构建产物与 Netlify 配置直接承担这些边缘函数将完成使命。小结Nx 仓库用四个边缘函数在 Netlify 边缘层完成了一件复杂而精巧的工作让托管在 Framer 的外部页面与独立博客在 nx.dev 域名下呈现为无缝、安全、SEO 友好、可被 AI Agent 发现的统一站点。其中两个核心函数分别示范了流式 HTML 重写含跨 chunk 边界处理与响应头增强和轻量级反向代理sitemap 聚合目录位置决策与excludedPath排除清单则记录了真实部署中的约束与踩坑经验。这套模式可以直接复用到任何外部托管页面 自建域名 Netlify 边缘的组合场景中。【免费下载链接】nxThe Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time.项目地址: https://gitcode.com/GitHub_Trending/nx/nx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考