vite-plugin-prefetch-api
TypeScript icon, indicating that this package has built-in type declarations

1.0.2 • Public • Published

vite-plugin-prefetch-api

A prefetch plugin for an API, which inserts the APIs that need to be requested in advance into the head tag and mounts the request information on the window object. Suitable for CSR projects.

Installation

pnpm i vite-plugin-prefetch-api

or

yarn add vite-plugin-prefetch-api

or

npm i vite-plugin-prefetch-api

Example

Configuration

// vite.config.js
import { defineConfig } from "vite";
import PrefetchPlugin from "vite-plugin-prefetch-api";

export default defineConfig({
  plugins: [
    PrefetchPlugin({
      list: [
        {
          url: '/api/task',
          method: 'post',
          adapter: function(data) {
            return { body: { username: data.cookie.username } }
          }
        },
        {
          url: '/api/msg',
          method: 'get',
          adapter: function(data) {
            return { query: { uid: data.cookie.uid } }
          },
          trigger: function(data) {
            return data.hash === 'inbox'
          }
        }
      ]
    })
  ],
});

Get Prefetch Data

import { getCache } from "vite-plugin-prefetch-api/util";

export async function request(url: string, options: any) {
    const cacheFetch = getCache({ url, ...options });
    if (cacheFetch) {
        return cacheFetch;
    }
    return fetch(url, options).then((res) => res.json());
}

Html before:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>example</title>
    <script type="module" crossorigin src="/assets/index-127f2da4.js"></script>
    <link rel="stylesheet" href="/assets/index-c322ae43.css">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

Html after:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>example</title>
    <script type="module" crossorigin src="/assets/index-b747b36c.js"></script>
    <link rel="stylesheet" href="/assets/index-8c9b6ecb.css">
    <script>!function(){try{const n="__PREFETCH__",c={cookie:document.cookie.split("; ").reduce(function(e,t){var[t,o]=t.split("=");return e[t]=decodeURIComponent(o),e},{}),query:location.search.slice(1).split("&").reduce(function(e,t){t=t.split("=");return e[decodeURIComponent(t[0])]=decodeURIComponent(t[1]||""),e},{}),hash:location.hash.slice(2),path:location.pathname};function r(e,t,o){t=function r(c){return Object.keys(c).sort().reduce(function(t,e){var o=c[e];if(void 0!==o){var n=e+":"+("object"==typeof o?r(o):o);for(let e=0;e<n.length;e++)t=(t<<5)-t+n.charCodeAt(e)}return t},0).toString(36)}(t);window[n]=window[n]||{},window[n][t]={count:o||1,value:e}}function o(e){var t=function(e,t){var{url:o,method:n}=e;try{var r=e["adapter"];const{body:i,header:a,query:u={}}=r(t)||{};var c=Object.keys(u).map(e=>e+"="+u[e]).join("&");return{url:c?o+"?"+c:o,method:n,body:i,header:a}}catch(e){return{url:o,method:n}}}(e,c);const{url:o,...n}=t;r(function(e,t){const{header:o,method:n="get"}=t,r=new Headers;return r.append("Content-Type","application/json"),o&&Object.keys(o).forEach(function(e){r.append(e,o[e])}),t={body:t.body?JSON.stringify(t.body):void 0,headers:r,method:n.toLocaleUpperCase()},fetch(e,t).then(e=>e.ok?e.json():Promise.reject(e.statusText))}(o,n),t,e.count||1)}[{url:"/api/task",method:"post",adapter:function(e){return{body:{username:e.cookie.username}}},count:1,trigger:function(){return 1}},{url:"/api/msg",method:"get",adapter:function(e){return{query:{uid:e.cookie.uid}}},trigger:function(e){return"inbox"===e.hash},count:1}].forEach(({trigger:e,...t})=>{e(c)&&o(t)})}catch(e){console.error("[prefetch-api error]",String(e))}}();</script>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

Prefetch API

Prefetch Plugin Config

interface PluginConfig {
  api?: "xhr" | "fetch"; // use "xhr" or "fetch", default "fetch"
  minify?: boolean; // minify code, default true
  list: RequestConfig[]; // prefetch api list
}

interface RequestConfig {
  url: string;
  method: "get" | "post" | "put" | "delete";
  count?: number; // The number of times response can be used, default 1
  adapter?: ParamsAdaptFunc; // Here you can set the request parameters according to the current environment information, default () => ({})
  trigger?: TriggerFunc | boolean; // default true, If the trigger is equal to false, it is filtered out before the html is inserted
}
type ParamsAdaptFunc = (data: SourceData) => ParamsInfo;
type TriggerFunc = (data: SourceData) => boolean;

type SourceData = {
  cookie: Record<string, unknown>;
  query: Record<string, unknown>;
  hash: string;
  path: string;
};
type ParamsInfo = {
  header?: Record<string, unknown>;
  query?: Record<string, unknown>;
  body?: unknown;
};

Prefetch GetCache API

Prefetch-plugin generates the hash value according to the RequestParams and stores the response to the window.
Therefore, when you want get response, keep the Settings of RequestParams and Prefetch-plugin consistent.

type RequestParams = {
  url: string;
  method: "get" | "post" | "put" | "delete";
  header?: Record<string, unknown>;
  body?: unknown;
}
type Response<T> = {
  data: T;
  status: number;
  statusText: string;
}
type ResponseReject = {
  status: number;
  statusText: string;
}
function getCache<T>(params: RequestParams): Promise<Response<T>> | null;

Why prefetch?

The CSR project is executed in the normal order of network load execution and JS execution:
normal

When you prefetch an api interface:
use-prefetch-api

Readme

Keywords

Package Sidebar

Install

npm i vite-plugin-prefetch-api

Weekly Downloads

3

Version

1.0.2

License

ISC

Unpacked Size

31.7 kB

Total Files

18

Last publish

Collaborators

  • zerosaturation