remix-client-cache
Version:
Utility library to cache your client data in React Router
231 lines (229 loc) • 7.46 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.tsx
var src_exports = {};
__export(src_exports, {
CacheRoute: () => CacheRoute,
cache: () => cache,
cacheClientLoader: () => cacheClientLoader,
configureGlobalCache: () => configureGlobalCache,
createCacheAdapter: () => createCacheAdapter,
createClientLoaderCache: () => createClientLoaderCache,
decacheClientLoader: () => decacheClientLoader,
invalidateCache: () => invalidateCache,
useCacheInvalidator: () => useCacheInvalidator,
useCachedLoaderData: () => useCachedLoaderData,
useSwrData: () => useSwrData
});
module.exports = __toCommonJS(src_exports);
var import_react = require("react");
var import_react2 = __toESM(require("react"), 1);
var import_react_router = require("react-router");
var map = /* @__PURE__ */ new Map();
var CacheRoute = (Component, settings) => (
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
(props) => {
const { cacheKey, invalidate, ...rest } = useCachedLoaderData(settings);
return /* @__PURE__ */ import_react2.default.createElement(
Component,
{
...props,
loaderData: rest,
invalidate,
cacheKey
}
);
}
);
var cache = {
getItem: async (key) => map.get(key),
setItem: async (key, val) => map.set(key, val),
removeItem: async (key) => map.delete(key)
};
var augmentStorageAdapter = (storage) => {
return {
getItem: async (key) => {
try {
const item = JSON.parse(storage.getItem(key) || "");
return item;
} catch (e) {
return storage.getItem(key);
}
},
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
setItem: async (key, val) => storage.setItem(key, JSON.stringify(val)),
removeItem: async (key) => storage.removeItem(key)
};
};
var createCacheAdapter = (adapter) => {
if (typeof document === "undefined")
return { adapter: void 0 };
const adapterInstance = adapter();
if (adapterInstance instanceof Storage) {
return {
adapter: augmentStorageAdapter(adapterInstance)
};
}
return {
adapter: adapter()
};
};
var configureGlobalCache = (newCacheInstance) => {
if (typeof document === "undefined")
return;
const newCache = newCacheInstance();
if (newCache instanceof Storage) {
cache = augmentStorageAdapter(newCache);
return;
}
if (newCache) {
cache = newCache;
}
};
var decacheClientLoader = async ({ request, serverAction }, {
key = constructKey(request),
adapter = cache
}) => {
const data = await serverAction();
await adapter.removeItem(key);
return data;
};
var cacheClientLoader = async ({ request, serverLoader }, {
type = "swr",
key = constructKey(request),
adapter = cache
} = {
type: "swr",
key: constructKey(request),
adapter: cache
}) => {
const existingData = await adapter.getItem(key);
if (type === "normal" && existingData) {
return {
...existingData,
serverData: existingData,
deferredServerData: void 0,
key
};
}
const data = existingData ? existingData : await serverLoader();
await adapter.setItem(key, data);
const deferredServerData = existingData ? serverLoader() : void 0;
const dataToReturn = data != null ? data : existingData;
return {
...dataToReturn,
serverData: data,
deferredServerData,
key
};
};
var createClientLoaderCache = (props) => {
const clientLoader = (args) => cacheClientLoader(args, props);
clientLoader.hydrate = true;
return clientLoader;
};
function useCachedLoaderData({ adapter = cache } = { adapter: cache }) {
const loaderData = (0, import_react_router.useLoaderData)();
const navigate = (0, import_react_router.useNavigate)();
const [freshData, setFreshData] = (0, import_react.useState)({
..."serverData" in loaderData ? loaderData.serverData : loaderData
});
(0, import_react.useEffect)(() => {
let isMounted = true;
if (loaderData.deferredServerData) {
loaderData.deferredServerData.then((newData) => {
if (isMounted) {
adapter.setItem(loaderData.key, newData);
setFreshData(newData);
}
}).catch((e) => {
const res = e instanceof Response ? e : void 0;
if (res && res.status === 302) {
const to = res.headers.get("Location");
to && navigate(to);
} else {
throw e;
}
});
}
return () => {
isMounted = false;
};
}, [loaderData]);
(0, import_react.useEffect)(() => {
if (loaderData.serverData && JSON.stringify(loaderData.serverData) !== JSON.stringify(freshData)) {
setFreshData(loaderData.serverData);
}
}, [loaderData == null ? void 0 : loaderData.serverData]);
return {
...loaderData,
...freshData,
cacheKey: loaderData.key,
invalidate: () => invalidateCache(loaderData.key)
};
}
var constructKey = (request) => {
const url = new URL(request.url);
return url.pathname + url.search + url.hash;
};
var invalidateCache = async (key) => {
const keys = Array.isArray(key) ? key : [key];
for (const k of keys) {
await cache.removeItem(k);
}
};
var useCacheInvalidator = () => ({
invalidateCache
});
function useSwrData({
serverData,
deferredServerData,
...args
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
}) {
return function SWR({
children
}) {
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, deferredServerData ? /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Suspense, { fallback: children(serverData) }, /* @__PURE__ */ import_react2.default.createElement(import_react_router.Await, { resolve: deferredServerData }, children)) : children(serverData != null ? serverData : args));
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CacheRoute,
cache,
cacheClientLoader,
configureGlobalCache,
createCacheAdapter,
createClientLoaderCache,
decacheClientLoader,
invalidateCache,
useCacheInvalidator,
useCachedLoaderData,
useSwrData
});