HOW - prefetch 二级页面实践

文章目录

  • [方法一:使用 import()](#方法一:使用 import())
  • [方法二:使用 link rel="prefetch" 或 link rel="preload"](#方法二:使用 link rel="prefetch" 或 link rel="preload")
  • [方法三:借助 Vite 插件自动预取](#方法三:借助 Vite 插件自动预取)
  • 小结
  • 批量预加载

在 Vite + React 项目中,如果你希望在访问首页(index 页面)时提前预加载(prefetch)二级页面的资源,从而在用户点击进入时加快加载速度,有几种常见、有效的方式。


方法一:使用 import()

如果你的二级页面是通过 动态 import(代码分割) 实现的(这是 Vite 推荐的懒加载方式),那么你可以手动对它的资源进行预取(prefetch)。

比如你的路由是这样定义的

ts 复制代码
// router.tsx
import { lazy } from "react";

const IndexPage = lazy(() => import("./pages/Index"));
const AboutPage = lazy(() => import("./pages/About")); // 二级页面

export const routes = [
  { path: "/", element: <IndexPage /> },
  { path: "/about", element: <AboutPage /> },
];

你可以在 IndexPageuseEffect 中触发 import(),这样浏览器就会预加载资源(但不会执行)

ts 复制代码
// pages/Index.tsx
import { useEffect } from "react";

export default function Index() {
  useEffect(() => {
    // 预取 About 页面的资源
    import("./About");
  }, []);

  return (
    <div>
      <h1>首页</h1>
      <a href="/about">去 About</a>
    </div>
  );
}

这里 ./About 并不是指构建后的实际路径,而是与Index同一层级下的About.tsx。Vite 在打包时会自动把这个 import("./About") 替换成对 about-yyyy.js 的懒加载请求。你不需要知道它的真实文件名。

优点:

  • 简单好用,不需要额外依赖。
  • Vite 在 build 后会自动生成 chunk,对应资源会被预取。
  • 实际浏览器加载时,用户点击 /about 基本是即时打开。

注意:

  • 这种方式属于「预加载模块」,不是真正意义的浏览器 rel="prefetch" 标签。
  • 适合用在用户很大概率会访问的二级页面上。

如果你希望更明确地让浏览器在空闲时预取资源 ,可以在首页渲染时插入一个 <link> 标签

ts 复制代码
import { useEffect } from "react";

export default function Index() {
  useEffect(() => {
    const link = document.createElement("link");
    link.rel = "prefetch";
    link.href = "/assets/AboutPage.xxx.js"; // 构建后的 chunk 路径
    document.head.appendChild(link);
  }, []);

  return <h1>首页</h1>;
}

这种方式比较麻烦的是:

  • 你要知道 About 页面的构建产物路径(可以通过 manifest.json 或动态 import 的返回值获取)。
  • 更适合对静态资源(图片、视频、大文件)做预加载。

方法三:借助 Vite 插件自动预取

还有一种自动化的方式是使用社区插件,例如 👉
vite-plugin-pwa(适合离线场景)
vite-plugin-prefetch(更灵活的 prefetch)

vite.config.ts 中配置:

ts 复制代码
import prefetch from "vite-plugin-prefetch";

export default {
  plugins: [
    prefetch({
      rel: "prefetch",
      include: ["about"], // 你想要预取的 chunk 名称
    }),
  ],
};

优点

  • 自动插入 <link rel="prefetch">
  • 不需要在组件中写逻辑。

小结

方式 特点 适合场景
import() 预加载 简单、推荐 二级页面懒加载
<link rel="prefetch"> 控制更细,但需路径 预取静态资源
React Router 预加载 更规范 使用 react-router v6+
Vite 插件自动化 零侵入 大型项目,多个页面

批量预加载

如果你有多个页面,也可以并行预加载:

ts 复制代码
useEffect(() => {
  Promise.all([
    import("./About"),
    import("./Contact"),
    import("./Help"),
  ]);
}, []);

当然也可以封装一个工具函数:

ts 复制代码
// utils/prefetchRoutes.ts
export async function prefetchRoutes(paths: string[]) {
  const prefetchMap: Record<string, () => Promise<any>> = {
    "/about": () => import("../pages/About"),
    "/contact": () => import("../pages/Contact"),
    "/help": () => import("../pages/Help"),
  };

  await Promise.all(paths.map((path) => prefetchMap[path]?.()));
}

// Index.tsx
import { useEffect } from "react";
import { prefetchRoutes } from "../utils/prefetchRoutes";

export default function Index() {
  useEffect(() => {
    prefetchRoutes(["/about", "/contact", "/help"]);
  }, []);

  return (
    <div>
      <h1>首页</h1>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
      <a href="/help">Help</a>
    </div>
  );
}

注意,如果二级页面特别多,比如十几个甚至几十个,一次性全部预加载反而会拖慢首页加载。

推荐策略:

  1. 对访问概率高的页面在首页预加载(比如「关于我」)。
  2. 对不常访问的页面延迟到用户第一次 hover / focus 时再预加载。
ts 复制代码
<a
  href="/about"
  onMouseEnter={() => import("./About")}
>
  About
</a>

这样用户第一次将鼠标移到链接上时,就已经预取完成,点击时是"秒开"。

最推荐的实践组合是:

  1. 在首页 useEffect 中预加载 1~3 个高频页面。
  2. 对其余页面用 hover 延迟预加载。
  3. 保持首页首屏加载轻量。
相关推荐
GIS之路2 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug5 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu121387 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中29 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路32 分钟前
GDAL 实现矢量合并
前端
hxjhnct35 分钟前
React useContext的缺陷
前端·react.js·前端框架
冰暮流星42 分钟前
javascript逻辑运算符
开发语言·javascript·ecmascript
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常1 小时前
我学习到的AG-UI的概念
前端