Next.js <Link>组件跨域预取失效,微前端重写场景下如何解决?
我用Next.js的rewrites实现了单域名访问多个微前端:博客项目部署在https://my-blog-project.vercel.app,通过https://my-project.vercel.app/blog访问;商城项目部署在https://my-store-project.vercel.app,通过https://my-project.vercel.app/store访问。基础重写配置能正常运行,但**组件的预取功能失效——根项目会从自身域名请求预取数据,而非对应子项目的域名。尝试添加/_next/data路径的重写规则,但没生效,不想关闭预取,求可行方案。
现有配置示例
初始重写配置
const nextConfig = { rewrites: () => [ { source: "/blog/:match*", destination: `${process.env.NEXT_PUBLIC_BLOG_URL}/blog/:match*` }, { source: "/store/:match*", destination: `${process.env.NEXT_PUBLIC_STORE_URL}/store/:match*` }, ], };
添加预取路径后的配置(未生效)
const nextConfig = { rewrites: () => [ { source: `/_next/data/:release/blog/:path*`, destination: `${process.env.NEXT_PUBLIC_BLOG_URL}/_next/data/:release/blog/:path*` }, { source: "/blog/:match*", destination: `${process.env.NEXT_PUBLIC_BLOG_URL}/blog/:match*` }, { source: "/store/:match*", destination: `${process.env.NEXT_PUBLIC_STORE_URL}/store/:match*` }, ], };
可行解决办法
1. 调整重写规则的匹配顺序与通配符逻辑
Next.js的rewrites是按顺序匹配的,/:match*不会覆盖/_next/data这类特殊路径。需要针对每个微前端项目的预取路径单独配置,并且把/_next/data的规则放在最前面,同时注意通配符的正确使用:
const nextConfig = { rewrites: async () => [ // 博客项目的预取数据路径重写 { source: "/_next/data/:release/blog/:path*", destination: `${process.env.NEXT_PUBLIC_BLOG_URL}/_next/data/:release/blog/:path*`, }, // 商城项目的预取数据路径重写 { source: "/_next/data/:release/store/:path*", destination: `${process.env.NEXT_PUBLIC_STORE_URL}/_next/data/:release/store/:path*`, }, // 基础页面路径重写 { source: "/blog/:match*", destination: `${process.env.NEXT_PUBLIC_BLOG_URL}/blog/:match*`, }, { source: "/store/:match*", destination: `${process.env.NEXT_PUBLIC_STORE_URL}/store/:match*`, }, ], };
确保预取路径的规则先被匹配,避免被后面的/:match*规则拦截。同时明确指定blog和store在/_next/data路径中的位置,让Next.js能正确识别路由归属。
2. 为微前端项目配置basePath
在每个微前端项目(博客、商城)的next.config.js中设置对应的basePath,这样生成的预取路径会自动带上前缀,和根项目的重写规则对齐:
博客项目的next.config.js
const nextConfig = { basePath: "/blog", }; module.exports = nextConfig;
商城项目的next.config.js
const nextConfig = { basePath: "/store", }; module.exports = nextConfig;
设置basePath后,微前端项目的所有资源(包括/_next/data下的预取数据)都会自动带上/blog或/store前缀,根项目的重写规则就能更精准地匹配到对应的预取请求,避免路径混淆。
3. 自定义**组件的预取逻辑(兜底方案)
如果上述配置仍不生效,可以自定义一个封装版的**组件,手动指定预取的目标域名:
import Link from "next/link"; import { useRouter } from "next/router"; const MicroFrontendLink = ({ href, ...props }) => { const router = useRouter(); const handlePrefetch = async () => { let targetUrl = href; // 根据路径前缀判断对应的微前端域名 if (href.startsWith("/blog")) { targetUrl = `${process.env.NEXT_PUBLIC_BLOG_URL}${href}`; } else if (href.startsWith("/store")) { targetUrl = `${process.env.NEXT_PUBLIC_STORE_URL}${href}`; } // 手动触发预取 await router.prefetch(targetUrl); }; return ( <Link href={href} {...props} prefetch={false} // 关闭默认预取 onMouseEnter={handlePrefetch} // 手动绑定预取事件 onTouchStart={handlePrefetch} /> ); }; export default MicroFrontendLink;
关闭Next.js默认的预取逻辑,手动根据路径前缀拼接对应的微前端域名,触发预取请求。这种方式更灵活,适合复杂的路由场景。
内容的提问来源于stack exchange,提问作者lpetrucci

