prefetch在spa路由切换中无效,因仅缓存js/css而不执行;modulepreload才是首屏bundle正确预加载方式,需路径一致、置于首个module脚本前、mime类型正确;真正优化应聚焦路由状态生命周期而非资源预加载。

SPA路由切换时,prefetch根本不起作用
它只存 JS/CSS 到 HTTP 缓存,不执行、不挂载、不恢复状态。用户点「下一步」才触发跳转,而 prefetch 又必须等当前页 onload 后才启动——此时路由已切走,请求被中止。就算资源进了缓存,新路由的组件仍要重新 mount,接口照发,表单校验照跑,白屏时间一毫秒没少。
modulepreload才是 SPA 首屏 Bundle 的正确预加载方式
如果你的入口是 type="module",且内部有静态 import 链(比如 import { router } from './router.js'),rel="preload" 只下载主文件,子模块还得等解析后逐个发起请求;而 rel="modulepreload" 会预解析主文件并递归抓取所有静态依赖。
- 必须写成
<link rel="modulepreload" href="/assets/app.[hash].js">,不能加as属性(加了反而失效) -
href必须和import('./app.js')或<script type="module" src="..."></script>中的路径完全一致,包括查询参数(如?t=123) - 所有
modulepreload标签必须出现在首个type="module"脚本之前,否则浏览器忽略 - 服务端返回的 MIME 类型必须是
application/javascript,否则部分浏览器拒绝执行
动态路由场景下,prefetch 的唯一可行用法
仅适用于明确知道用户下一步必进、且目标页资源路径稳定、无参数的纯静态页,比如最终提交页 /submit。其他所有“预取下一屏 JS”的尝试,在现代 SPA 中基本是徒劳。
- 路径必须为根相对或绝对,例如
/js/submit.chunk.js,不能写./submit.js(子路由下解析失败) -
as值必须准确:JS 用as="script",CSS 用as="style",HTML 用as="document" - 别对字体用
prefetch:不触发 CORS 预检,跨域字体静默失败 - 验证是否生效,看 Network 面板:
Initiator列显示prefetch,Priority为Low,跳转后资源状态码为200 (from memory cache)或304
真正该优化的不是资源加载,而是路由与状态生命周期
写一堆 prefetch 标签,掩盖不了整页跳转带来的 mount/unmount 开销。SPA 路由切换慢,根源不在 JS 下载,而在每次切换都重走一遍 React/Vue 初始化流程。
- 把多步表单改成单页内路由(
history.pushState或 hash),避免 reload - 用户点「下一步」前,用
fetch()预取/api/step3数据,而非预取 JS - 用
sessionStorage或React context持久化已填字段,跳步不丢输入 - 非首屏组件用
React.lazy+Suspense,或import()动态加载,而不是靠prefetch抢跑
最容易被忽略的点:所有预加载机制都建立在“资源路径可预测”基础上,而真实 SPA 的 chunk 名带 hash、路由懒加载路径动态生成、API 接口带用户态参数——这些都会让 prefetch 失效。与其调参,不如砍掉不必要的跳转逻辑。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











