Next.js集成next-pwa后首页链接无法正常导航的技术问题
问题:Next.js + next-pwa 首页链接点击后URL变化但页面不渲染
原本Web应用所有链接正常,接入next-pwa迁移为PWA后,仅首页(manifest.json中start_url对应的/路由)的链接失效:点击链接URL变化,但页面不重新渲染;直接输入URL可正常跳转,离开首页后所有链接恢复正常。
相关代码
自定义Link组件(Next.js 12.3.1)
import styled from '@emotion/styled'; import NextLink from 'next/link'; export const Link = ({ href, children, justifyContent = 'center', width = '', ...rest }) => { const A = styled.a({ color: 'inherit', textDecoration: 'inherit', display: 'flex', alignItems: 'center', margin: '0', padding: '0', width, height: '100%', justifyContent }); return ( <NextLink href={href} {...rest} passHref> <A {...rest}> {children} </A> </NextLink> ); };
next.config.js
const runtimeCaching = require('next-pwa/cache'); /** @type {import('next').NextConfig} */ const withPWA = require('next-pwa')({ dest: 'public', register: true, skipWaiting: true, runtimeCaching, navigationPreload: true }); const nextConfig = withPWA({ reactStrictMode: true, swcMinify: true, trailingSlash: true, images: { domains: [ 'firebasestorage.googleapis.com', 'i.gyazo.com', 'gateway.pinata.cloud' ] }, async headers() { return [ { source: '/:path*', headers: securityHeaders, } ] }, experimental: { modularizeImports: { '@mui/material': { transform: '@mui/material/{{member}}' }, '@mui/icons-material': { transform: '@mui/icons-material/{{member}}' }, lodash: { transform: 'lodash/{{member}}' }, 'react-xarrows': { transform: 'react-xarrows/lib/{{member}}' } } }, }); // Use to analyze bundle size // const withBundleAnalyzer = require('@next/bundle-analyzer')({ // enabled: process.env.ANALYZE === 'true', // }); module.exports = nextConfig;
manifest.json
{ "theme_color": "#ffffff", "background_color": "#1565c0", "display": "fullscreen", "start_url": "/", "scope": ".", "name": "Student Property Review", "short_name": "Student Property Review", "description": "A platform to read and review reviews about student properties and landlords; review your properties to help other students.", "icons": [ { "src": "icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "icons/icon-256x256.png", "sizes": "256x256", "type": "image/png" }, { "src": "icons/icon-384x384.png", "sizes": "384x384", "type": "image/png" }, { "src": "icons/icon-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" } ] }
解决方案
1. 修复自定义Link组件的props传递冲突
你同时将...rest传给NextLink和a标签,可能导致props冲突(比如把a标签的事件props传给NextLink)。拆分props,只传递对应组件需要的内容:
import styled from '@emotion/styled'; import NextLink from 'next/link'; export const Link = ({ href, children, justifyContent = 'center', width = '', ...rest }) => { // 分离NextLink和a标签的props,避免冲突 const { onClick, ...linkProps } = rest; const A = styled.a({ color: 'inherit', textDecoration: 'inherit', display: 'flex', alignItems: 'center', margin: '0', padding: '0', width, height: '100%', justifyContent }); return ( <NextLink href={href} passHref {...linkProps}> <A {...rest}> {children} </A> </NextLink> ); };
2. 调整PWA的runtimeCaching策略
next-pwa默认缓存规则可能拦截首页的客户端导航,自定义缓存规则优先使用网络请求:
const runtimeCaching = [ { urlPattern: /^https?.*/, handler: 'NetworkFirst', options: { cacheName: 'offline-cache', networkTimeoutSeconds: 10, expiration: { maxEntries: 200, maxAgeSeconds: 7 * 24 * 60 * 60, // 缓存7天 }, cacheableResponse: { statuses: [0, 200], }, }, }, // 针对静态资源添加单独缓存规则 { urlPattern: /^https:\/\/firebasestorage\.googleapis\.com\/.*/, handler: 'CacheFirst', options: { cacheName: 'firebase-storage', expiration: { maxEntries: 50, }, }, }, ];
3. 修改manifest的scope配置
将scope改为"/",确保首页导航不受PWA范围限制:
{ // ...其他配置 "scope": "/", // ...其他配置 }
4. 清除PWA缓存并重新注册Service Worker
开发环境:打开浏览器DevTools的Application标签,清除Service Worker和缓存存储;
生产环境:确保skipWaiting: true生效,或手动触发用户更新Service Worker。
内容的提问来源于stack exchange,提问作者J. Whitehead
相关产品推荐
相关产品推荐

