vite-plugin-react-pages
Version:
<p> <a href="https://www.npmjs.com/package/vite-plugin-react-pages" target="_blank" rel="noopener"><img src="https://img.shields.io/npm/v/vite-plugin-react-pages.svg" alt="npm package" /></a> </p>
1,090 lines (1,059 loc) • 34 kB
JavaScript
import ReactExports, { createContext, useState, useReducer, useEffect, useDebugValue, useContext, useCallback, useMemo, useLayoutEffect, useRef } from 'react';
import { createRoot } from 'react-dom/client';
import { HashRouter, BrowserRouter, useRoutes, useLocation } from 'react-router-dom';
import { jsx } from 'react/jsx-runtime';
import { dequal } from 'dequal';
import initialPages from '/@react-pages/pages';
import initialTheme from '/@react-pages/theme';
import { unstable_batchedUpdates } from 'react-dom';
/**
* During ssr hydration, we pass all the data needed by App
* with this ctx
* so the App can render the page data directly
* instead of render the loading state
*/
const dataCacheCtx = /*#__PURE__*/createContext({});
const setDataCacheCtx = /*#__PURE__*/createContext(() => {
throw new Error(`setDataCacheCtx not found`);
});
/// <reference types="vite/client" />
// @ts-expect-error
const Router = __HASH_ROUTER__ ? HashRouter : BrowserRouter;
// @ts-expect-error
const basename = __HASH_ROUTER__ ? undefined : import.meta.env.BASE_URL?.replace(/\/$/, '');
const ClientAppWrapper = ({
initCache,
children
}) => {
const [dataCache, setDataCache] = useState(initCache ?? {});
return /*#__PURE__*/jsx(Router, {
basename: basename,
children: /*#__PURE__*/jsx(dataCacheCtx.Provider, {
value: dataCache,
children: /*#__PURE__*/jsx(setDataCacheCtx.Provider, {
value: setDataCache,
children: children
})
})
});
};
let keyCount = 0;
function atom(read, write) {
const key = `atom${++keyCount}`;
const config = {
toString: () => key
};
if (typeof read === "function") {
config.read = read;
} else {
config.init = read;
config.read = function(get) {
return get(this);
};
config.write = function(get, set, arg) {
return set(
this,
typeof arg === "function" ? arg(get(this)) : arg
);
};
}
if (write) {
config.write = write;
}
return config;
}
const hasInitialValue = (atom) => "init" in atom;
const isActuallyWritableAtom = (atom) => !!atom.write;
const cancelPromiseMap = /* @__PURE__ */ new WeakMap();
const registerCancelPromise = (promise, cancel) => {
cancelPromiseMap.set(promise, cancel);
promise.catch(() => {
}).finally(() => cancelPromiseMap.delete(promise));
};
const cancelPromise = (promise, next) => {
const cancel = cancelPromiseMap.get(promise);
if (cancel) {
cancelPromiseMap.delete(promise);
cancel(next);
}
};
const resolvePromise = (promise, value) => {
promise.status = "fulfilled";
promise.value = value;
};
const rejectPromise = (promise, e) => {
promise.status = "rejected";
promise.reason = e;
};
const isPromiseLike$1 = (x) => typeof (x == null ? void 0 : x.then) === "function";
const isEqualAtomValue = (a, b) => !!a && "v" in a && "v" in b && Object.is(a.v, b.v);
const isEqualAtomError = (a, b) => !!a && "e" in a && "e" in b && Object.is(a.e, b.e);
const hasPromiseAtomValue = (a) => !!a && "v" in a && a.v instanceof Promise;
const isEqualPromiseAtomValue = (a, b) => "v" in a && "v" in b && a.v.orig && a.v.orig === b.v.orig;
const returnAtomValue = (atomState) => {
if ("e" in atomState) {
throw atomState.e;
}
return atomState.v;
};
const createStore = () => {
const atomStateMap = /* @__PURE__ */ new WeakMap();
const mountedMap = /* @__PURE__ */ new WeakMap();
const pendingMap = /* @__PURE__ */ new Map();
let storeListenersRev2;
let mountedAtoms;
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
storeListenersRev2 = /* @__PURE__ */ new Set();
mountedAtoms = /* @__PURE__ */ new Set();
}
const getAtomState = (atom) => atomStateMap.get(atom);
const setAtomState = (atom, atomState) => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
Object.freeze(atomState);
}
const prevAtomState = atomStateMap.get(atom);
atomStateMap.set(atom, atomState);
if (!pendingMap.has(atom)) {
pendingMap.set(atom, prevAtomState);
}
if (hasPromiseAtomValue(prevAtomState)) {
const next = "v" in atomState ? atomState.v instanceof Promise ? atomState.v : Promise.resolve(atomState.v) : Promise.reject(atomState.e);
if (prevAtomState.v !== next) {
cancelPromise(prevAtomState.v, next);
}
}
};
const updateDependencies = (atom, nextAtomState, nextDependencies) => {
const dependencies = /* @__PURE__ */ new Map();
let changed = false;
nextDependencies.forEach((aState, a) => {
if (!aState && a === atom) {
aState = nextAtomState;
}
if (aState) {
dependencies.set(a, aState);
if (nextAtomState.d.get(a) !== aState) {
changed = true;
}
} else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
console.warn("[Bug] atom state not found");
}
});
if (changed || nextAtomState.d.size !== dependencies.size) {
nextAtomState.d = dependencies;
}
};
const setAtomValue = (atom, value, nextDependencies) => {
const prevAtomState = getAtomState(atom);
const nextAtomState = {
d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(),
v: value
};
if (nextDependencies) {
updateDependencies(atom, nextAtomState, nextDependencies);
}
if (isEqualAtomValue(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
return prevAtomState;
}
if (hasPromiseAtomValue(prevAtomState) && hasPromiseAtomValue(nextAtomState) && isEqualPromiseAtomValue(prevAtomState, nextAtomState)) {
if (prevAtomState.d === nextAtomState.d) {
return prevAtomState;
} else {
nextAtomState.v = prevAtomState.v;
}
}
setAtomState(atom, nextAtomState);
return nextAtomState;
};
const setAtomValueOrPromise = (atom, valueOrPromise, nextDependencies, abortPromise) => {
if (isPromiseLike$1(valueOrPromise)) {
let continuePromise;
const updatePromiseDependencies = () => {
const prevAtomState = getAtomState(atom);
if (!hasPromiseAtomValue(prevAtomState) || prevAtomState.v !== promise) {
return;
}
const nextAtomState = setAtomValue(
atom,
promise,
nextDependencies
);
if (mountedMap.has(atom) && prevAtomState.d !== nextAtomState.d) {
mountDependencies(atom, nextAtomState, prevAtomState.d);
}
};
const promise = new Promise((resolve, reject) => {
let settled = false;
valueOrPromise.then(
(v) => {
if (!settled) {
settled = true;
resolvePromise(promise, v);
resolve(v);
updatePromiseDependencies();
}
},
(e) => {
if (!settled) {
settled = true;
rejectPromise(promise, e);
reject(e);
updatePromiseDependencies();
}
}
);
continuePromise = (next) => {
if (!settled) {
settled = true;
next.then(
(v) => resolvePromise(promise, v),
(e) => rejectPromise(promise, e)
);
resolve(next);
}
};
});
promise.orig = valueOrPromise;
promise.status = "pending";
registerCancelPromise(promise, (next) => {
if (next) {
continuePromise(next);
}
abortPromise == null ? void 0 : abortPromise();
});
return setAtomValue(atom, promise, nextDependencies);
}
return setAtomValue(atom, valueOrPromise, nextDependencies);
};
const setAtomError = (atom, error, nextDependencies) => {
const prevAtomState = getAtomState(atom);
const nextAtomState = {
d: (prevAtomState == null ? void 0 : prevAtomState.d) || /* @__PURE__ */ new Map(),
e: error
};
if (nextDependencies) {
updateDependencies(atom, nextAtomState, nextDependencies);
}
if (isEqualAtomError(prevAtomState, nextAtomState) && prevAtomState.d === nextAtomState.d) {
return prevAtomState;
}
setAtomState(atom, nextAtomState);
return nextAtomState;
};
const readAtomState = (atom, force) => {
const atomState = getAtomState(atom);
if (!force && atomState) {
if (mountedMap.has(atom)) {
return atomState;
}
if (Array.from(atomState.d).every(([a, s]) => {
if (a === atom) {
return true;
}
const aState = readAtomState(a);
return aState === s || isEqualAtomValue(aState, s);
})) {
return atomState;
}
}
const nextDependencies = /* @__PURE__ */ new Map();
let isSync = true;
const getter = (a) => {
if (a === atom) {
const aState2 = getAtomState(a);
if (aState2) {
nextDependencies.set(a, aState2);
return returnAtomValue(aState2);
}
if (hasInitialValue(a)) {
nextDependencies.set(a, void 0);
return a.init;
}
throw new Error("no atom init");
}
const aState = readAtomState(a);
nextDependencies.set(a, aState);
return returnAtomValue(aState);
};
let controller;
let setSelf;
const options = {
get signal() {
if (!controller) {
controller = new AbortController();
}
return controller.signal;
},
get setSelf() {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !isActuallyWritableAtom(atom)) {
console.warn("setSelf function cannot be used with read-only atom");
}
if (!setSelf && isActuallyWritableAtom(atom)) {
setSelf = (...args) => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && isSync) {
console.warn("setSelf function cannot be called in sync");
}
if (!isSync) {
return writeAtom(atom, ...args);
}
};
}
return setSelf;
}
};
try {
const valueOrPromise = atom.read(getter, options);
return setAtomValueOrPromise(
atom,
valueOrPromise,
nextDependencies,
() => controller == null ? void 0 : controller.abort()
);
} catch (error) {
return setAtomError(atom, error, nextDependencies);
} finally {
isSync = false;
}
};
const readAtom = (atom) => returnAtomValue(readAtomState(atom));
const addAtom = (atom) => {
let mounted = mountedMap.get(atom);
if (!mounted) {
mounted = mountAtom(atom);
}
return mounted;
};
const canUnmountAtom = (atom, mounted) => !mounted.l.size && (!mounted.t.size || mounted.t.size === 1 && mounted.t.has(atom));
const delAtom = (atom) => {
const mounted = mountedMap.get(atom);
if (mounted && canUnmountAtom(atom, mounted)) {
unmountAtom(atom);
}
};
const recomputeDependents = (atom) => {
const dependencyMap = /* @__PURE__ */ new Map();
const dirtyMap = /* @__PURE__ */ new WeakMap();
const getDependents = (a) => {
var _a;
const dependents = new Set((_a = mountedMap.get(a)) == null ? void 0 : _a.t);
pendingMap.forEach((_, pendingAtom) => {
var _a2;
if ((_a2 = getAtomState(pendingAtom)) == null ? void 0 : _a2.d.has(a)) {
dependents.add(pendingAtom);
}
});
return dependents;
};
const loop1 = (a) => {
getDependents(a).forEach((dependent) => {
if (dependent !== a) {
dependencyMap.set(
dependent,
(dependencyMap.get(dependent) || /* @__PURE__ */ new Set()).add(a)
);
dirtyMap.set(dependent, (dirtyMap.get(dependent) || 0) + 1);
loop1(dependent);
}
});
};
loop1(atom);
const loop2 = (a) => {
getDependents(a).forEach((dependent) => {
var _a;
if (dependent !== a) {
let dirtyCount = dirtyMap.get(dependent);
if (dirtyCount) {
dirtyMap.set(dependent, --dirtyCount);
}
if (!dirtyCount) {
let isChanged = !!((_a = dependencyMap.get(dependent)) == null ? void 0 : _a.size);
if (isChanged) {
const prevAtomState = getAtomState(dependent);
const nextAtomState = readAtomState(dependent, true);
isChanged = !isEqualAtomValue(prevAtomState, nextAtomState);
}
if (!isChanged) {
dependencyMap.forEach((s) => s.delete(dependent));
}
}
loop2(dependent);
}
});
};
loop2(atom);
};
const writeAtomState = (atom, ...args) => {
let isSync = true;
const getter = (a) => returnAtomValue(readAtomState(a));
const setter = (a, ...args2) => {
let r;
if (a === atom) {
if (!hasInitialValue(a)) {
throw new Error("atom not writable");
}
const prevAtomState = getAtomState(a);
const nextAtomState = setAtomValueOrPromise(a, args2[0]);
if (!isEqualAtomValue(prevAtomState, nextAtomState)) {
recomputeDependents(a);
}
} else {
r = writeAtomState(a, ...args2);
}
if (!isSync) {
const flushed = flushPending();
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
storeListenersRev2.forEach(
(l) => l({ type: "async-write", flushed })
);
}
}
return r;
};
const result = atom.write(getter, setter, ...args);
isSync = false;
return result;
};
const writeAtom = (atom, ...args) => {
const result = writeAtomState(atom, ...args);
const flushed = flushPending();
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
storeListenersRev2.forEach(
(l) => l({ type: "write", flushed })
);
}
return result;
};
const mountAtom = (atom, initialDependent, onMountQueue) => {
var _a;
const queue = onMountQueue || [];
(_a = getAtomState(atom)) == null ? void 0 : _a.d.forEach((_, a) => {
const aMounted = mountedMap.get(a);
if (aMounted) {
aMounted.t.add(atom);
} else {
if (a !== atom) {
mountAtom(a, atom, queue);
}
}
});
readAtomState(atom);
const mounted = {
t: new Set(initialDependent && [initialDependent]),
l: /* @__PURE__ */ new Set()
};
mountedMap.set(atom, mounted);
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
mountedAtoms.add(atom);
}
if (isActuallyWritableAtom(atom) && atom.onMount) {
const { onMount } = atom;
queue.push(() => {
const onUnmount = onMount((...args) => writeAtom(atom, ...args));
if (onUnmount) {
mounted.u = onUnmount;
}
});
}
if (!onMountQueue) {
queue.forEach((f) => f());
}
return mounted;
};
const unmountAtom = (atom) => {
var _a;
const onUnmount = (_a = mountedMap.get(atom)) == null ? void 0 : _a.u;
if (onUnmount) {
onUnmount();
}
mountedMap.delete(atom);
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
mountedAtoms.delete(atom);
}
const atomState = getAtomState(atom);
if (atomState) {
if (hasPromiseAtomValue(atomState)) {
cancelPromise(atomState.v);
}
atomState.d.forEach((_, a) => {
if (a !== atom) {
const mounted = mountedMap.get(a);
if (mounted) {
mounted.t.delete(atom);
if (canUnmountAtom(a, mounted)) {
unmountAtom(a);
}
}
}
});
} else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
console.warn("[Bug] could not find atom state to unmount", atom);
}
};
const mountDependencies = (atom, atomState, prevDependencies) => {
const depSet = new Set(atomState.d.keys());
const maybeUnmountAtomSet = /* @__PURE__ */ new Set();
prevDependencies == null ? void 0 : prevDependencies.forEach((_, a) => {
if (depSet.has(a)) {
depSet.delete(a);
return;
}
maybeUnmountAtomSet.add(a);
const mounted = mountedMap.get(a);
if (mounted) {
mounted.t.delete(atom);
}
});
depSet.forEach((a) => {
const mounted = mountedMap.get(a);
if (mounted) {
mounted.t.add(atom);
} else if (mountedMap.has(atom)) {
mountAtom(a, atom);
}
});
maybeUnmountAtomSet.forEach((a) => {
const mounted = mountedMap.get(a);
if (mounted && canUnmountAtom(a, mounted)) {
unmountAtom(a);
}
});
};
const flushPending = () => {
let flushed;
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
flushed = /* @__PURE__ */ new Set();
}
while (pendingMap.size) {
const pending = Array.from(pendingMap);
pendingMap.clear();
pending.forEach(([atom, prevAtomState]) => {
const atomState = getAtomState(atom);
if (atomState) {
const mounted = mountedMap.get(atom);
if (mounted && atomState.d !== (prevAtomState == null ? void 0 : prevAtomState.d)) {
mountDependencies(atom, atomState, prevAtomState == null ? void 0 : prevAtomState.d);
}
if (mounted && !// TODO This seems pretty hacky. Hope to fix it.
// Maybe we could `mountDependencies` in `setAtomState`?
(!hasPromiseAtomValue(prevAtomState) && (isEqualAtomValue(prevAtomState, atomState) || isEqualAtomError(prevAtomState, atomState)))) {
mounted.l.forEach((listener) => listener());
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
flushed.add(atom);
}
}
} else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
console.warn("[Bug] no atom state to flush");
}
});
}
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
return flushed;
}
};
const subscribeAtom = (atom, listener) => {
const mounted = addAtom(atom);
const flushed = flushPending();
const listeners = mounted.l;
listeners.add(listener);
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
storeListenersRev2.forEach(
(l) => l({ type: "sub", flushed })
);
}
return () => {
listeners.delete(listener);
delAtom(atom);
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
storeListenersRev2.forEach((l) => l({ type: "unsub" }));
}
};
};
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
return {
get: readAtom,
set: writeAtom,
sub: subscribeAtom,
// store dev methods (these are tentative and subject to change without notice)
dev_subscribe_store: (l, rev) => {
if (rev !== 2) {
throw new Error("The current StoreListener revision is 2.");
}
storeListenersRev2.add(l);
return () => {
storeListenersRev2.delete(l);
};
},
dev_get_mounted_atoms: () => mountedAtoms.values(),
dev_get_atom_state: (a) => atomStateMap.get(a),
dev_get_mounted: (a) => mountedMap.get(a),
dev_restore_atoms: (values) => {
for (const [atom, valueOrPromise] of values) {
if (hasInitialValue(atom)) {
setAtomValueOrPromise(atom, valueOrPromise);
recomputeDependents(atom);
}
}
const flushed = flushPending();
storeListenersRev2.forEach(
(l) => l({ type: "restore", flushed })
);
}
};
}
return {
get: readAtom,
set: writeAtom,
sub: subscribeAtom
};
};
let defaultStore;
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
if (typeof globalThis.__NUMBER_OF_JOTAI_INSTANCES__ === "number") {
++globalThis.__NUMBER_OF_JOTAI_INSTANCES__;
} else {
globalThis.__NUMBER_OF_JOTAI_INSTANCES__ = 1;
}
}
const getDefaultStore = () => {
if (!defaultStore) {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && globalThis.__NUMBER_OF_JOTAI_INSTANCES__ !== 1) {
console.warn(
"Detected multiple Jotai instances. It may cause unexpected behavior with the default store. https://github.com/pmndrs/jotai/discussions/2044"
);
}
defaultStore = createStore();
}
return defaultStore;
};
const StoreContext = createContext(void 0);
const useStore = (options) => {
const store = useContext(StoreContext);
return (options == null ? void 0 : options.store) || store || getDefaultStore();
};
const isPromiseLike = (x) => typeof (x == null ? void 0 : x.then) === "function";
const use = ReactExports.use || ((promise) => {
if (promise.status === "pending") {
throw promise;
} else if (promise.status === "fulfilled") {
return promise.value;
} else if (promise.status === "rejected") {
throw promise.reason;
} else {
promise.status = "pending";
promise.then(
(v) => {
promise.status = "fulfilled";
promise.value = v;
},
(e) => {
promise.status = "rejected";
promise.reason = e;
}
);
throw promise;
}
});
function useAtomValue(atom, options) {
const store = useStore(options);
const [[valueFromReducer, storeFromReducer, atomFromReducer], rerender] = useReducer(
(prev) => {
const nextValue = store.get(atom);
if (Object.is(prev[0], nextValue) && prev[1] === store && prev[2] === atom) {
return prev;
}
return [nextValue, store, atom];
},
void 0,
() => [store.get(atom), store, atom]
);
let value = valueFromReducer;
if (storeFromReducer !== store || atomFromReducer !== atom) {
rerender();
value = store.get(atom);
}
const delay = options == null ? void 0 : options.delay;
useEffect(() => {
const unsub = store.sub(atom, () => {
if (typeof delay === "number") {
setTimeout(rerender, delay);
return;
}
rerender();
});
rerender();
return unsub;
}, [store, atom, delay]);
useDebugValue(value);
return isPromiseLike(value) ? use(value) : value;
}
function useSetAtom(atom, options) {
const store = useStore(options);
const setAtom = useCallback(
(...args) => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !("write" in atom)) {
throw new Error("not writable atom");
}
return store.set(atom, ...args);
},
[store, atom]
);
return setAtom;
}
function useAtom(atom, options) {
return [
useAtomValue(atom, options),
// We do wrong type assertion here, which results in throwing an error.
useSetAtom(atom, options)
];
}
Symbol(
(import.meta.env ? import.meta.env.MODE : void 0) !== "production" ? "RESET" : ""
);
function atomFamily(initializeAtom, areEqual) {
let shouldRemove = null;
const atoms = /* @__PURE__ */ new Map();
const createAtom = (param) => {
let item;
if (areEqual === void 0) {
item = atoms.get(param);
} else {
for (const [key, value] of atoms) {
if (areEqual(key, param)) {
item = value;
break;
}
}
}
if (item !== void 0) {
if (shouldRemove == null ? void 0 : shouldRemove(item[1], param)) {
createAtom.remove(param);
} else {
return item[0];
}
}
const newAtom = initializeAtom(param);
atoms.set(param, [newAtom, Date.now()]);
return newAtom;
};
createAtom.remove = (param) => {
if (areEqual === void 0) {
atoms.delete(param);
} else {
for (const [key] of atoms) {
if (areEqual(key, param)) {
atoms.delete(key);
break;
}
}
}
};
createAtom.setShouldRemove = (fn) => {
shouldRemove = fn;
if (!shouldRemove)
return;
for (const [key, value] of atoms) {
if (shouldRemove(value[1], key)) {
atoms.delete(key);
}
}
};
return createAtom;
}
let useTheme;
let usePagePaths;
let usePageModule;
let useStaticData;
let useAllPagesOutlines;
// TODO: simplify this
// there is no easy way to handle the hmr of module such as `/@react-pages/pages/page1` so stop trying it
// https://github.com/vitejs/vite-plugin-react-pages/pull/19#discussion_r604251258
const initialPagePaths = Object.keys(initialPages);
// This HMR code assumes that our Jotai atoms are always managed
// by the same Provider. It also mutates during render, which is
// generally discouraged, but in this case it's okay.
if (import.meta.hot) {
let setTheme;
import.meta.hot.accept('/@react-pages/theme', module => {
// console.log('@@hot update /@react-pages/theme', module)
if (!module) {
console.error('unexpected hot module', module);
return;
}
setTheme?.({
Theme: module.default
});
});
const themeAtom = atom({
Theme: initialTheme
});
useTheme = () => {
const [{
Theme
}, set] = useAtom(themeAtom);
setTheme = set;
return Theme;
};
let setPages;
import.meta.hot.accept('/@react-pages/pages', module => {
// console.log('@@hot update /@react-pages/pages', module)
if (!module) {
console.error('unexpected hot module', module);
return;
}
setPages?.(module.default);
});
// let setAllPagesOutlines: SetAtom<any, void> | undefined
// import.meta.hot!.accept('/@react-pages/allPagesOutlines', (module) => {
// // console.log('@@hot update /@react-pages/allPagesOutlines', module)
// if (!module) {
// console.error('unexpected hot module', module)
// return
// }
// setAllPagesOutlines?.(module)
// })
const pagesAtom = atom(initialPages);
const pagePathsAtom = atom(initialPagePaths.sort());
const staticDataAtom = atom(toStaticData(initialPages));
const allPagesOutlinesAtom = atom(initialPages);
const setPagesAtom = atom(null, (get, set, newPages) => {
let newStaticData;
const pages = get(pagesAtom);
for (const path in newPages) {
const newPage = newPages[path];
const page = pages[path];
// Avoid changing the identity of `page.staticData` unless
// a change is detected. This prevents unnecessary renders
// of components that depend on `useStaticData(path)` call.
if (page && dequal(page.staticData, newPage.staticData)) {
newPage.staticData = page.staticData;
} else {
newStaticData ??= {};
newStaticData[path] = newPage.staticData;
}
}
// detect deleted pages
for (const path in pages) {
if (!newPages[path]) {
newStaticData ??= {};
newStaticData[path] = undefined;
}
}
// Update the `pagesAtom` every time, since no hook uses it directly.
set(pagesAtom, newPages);
// Avoid re-rendering `useStaticData()` callers if no data changed.
if (newStaticData) {
newStaticData = {
...get(staticDataAtom),
...newStaticData
};
// filter out deleted paths
newStaticData = Object.fromEntries(Object.entries(newStaticData).filter(([k, v]) => v !== undefined));
set(staticDataAtom, newStaticData);
}
// Avoid re-rendering `usePagePaths()` callers if no paths were added/deleted.
const newPagePaths = Object.keys(newPages).sort();
if (!dequal(get(pagePathsAtom), newPagePaths)) {
set(pagePathsAtom, newPagePaths);
}
});
const dataAtoms = atomFamily(path => atom(get => {
const pages = get(pagesAtom);
return pages[path];
}));
const staticDataAtoms = atomFamily(path => atom(get => {
const pages = get(pagesAtom);
const page = pages[path];
return page?.staticData;
}));
usePagePaths = () => {
setPages = useSetAtom(setPagesAtom);
return useAtomValue(pagePathsAtom);
};
usePageModule = pagePath => {
const data = useAtomValue(dataAtoms(pagePath));
return useMemo(() => data?.data(), [data]);
};
useStaticData = (pagePath, selector) => {
const staticData = pagePath ? staticDataAtoms(pagePath) : staticDataAtom;
if (selector) {
const selection = useMemo(() => atom(get => selector(get(staticData))), [staticData]);
return useAtomValue(selection);
}
return useAtomValue(staticData);
};
useAllPagesOutlines = timeout => {
const [data, set] = useAtom(allPagesOutlinesAtom);
// setAllPagesOutlines = set
useEffect(() => {
setTimeout(() => {
import('/@react-pages/allPagesOutlines').then(mod => {
set(mod);
});
}, timeout);
}, []);
return data;
};
}
// Static mode
else {
useTheme = () => initialTheme;
usePagePaths = () => initialPagePaths;
usePageModule = path => {
const page = initialPages[path];
return useMemo(() => page?.data(), [page]);
};
useStaticData = (path, selector) => {
if (path) {
const page = initialPages[path];
const staticData = page?.staticData || {};
return selector ? selector(staticData) : staticData;
}
return toStaticData(initialPages);
};
useAllPagesOutlines = timeout => {
const [data, set] = useState();
useEffect(() => {
setTimeout(() => {
import('/@react-pages/allPagesOutlines').then(mod => {
set(mod);
});
}, timeout);
}, []);
return data;
};
}
function toStaticData(pages) {
const staticData = {};
for (const path in pages) {
staticData[path] = pages[path].staticData;
}
return staticData;
}
if (globalThis['__vite_pages_use_static_data']) {
throw new Error(`[vite-pages] global hooks (.e.g useStaticData) already exists on window. It means there are multiple vite-pages runtime in this page. Please report this to vite-pages.`);
} else {
globalThis['__vite_pages_use_static_data'] = useStaticData;
globalThis['__vite_pages_use_all_pages_outlines'] = useAllPagesOutlines;
}
const isSSR = import.meta.env.SSR;
// fix warning of useLayoutEffect during ssr
// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
const useIsomorphicLayoutEffect = isSSR ? useEffect : useLayoutEffect;
function useAppState(routePath) {
const dataCache = useContext(dataCacheCtx);
const setDataCache = useContext(setDataCacheCtx);
const [loadState, setLoadState] = useState(() => {
if (dataCache[routePath]) {
// this is a ssr or hydration
// this page's data has already been loaded
return {
type: 'loaded',
routePath
};
}
if (routePath === '/internal-404-page') {
// this is a ssr or hydration
// for the 404 page
return {
type: '404',
routePath
};
}
return {
type: 'loading',
routePath
};
});
const onLoadState = (type, routePath, error) => setLoadState({
type,
routePath,
error
});
const loading = usePageModule(routePath);
const loadingRef = useRef();
useIsomorphicLayoutEffect(() => {
loadingRef.current = loading;
if (!loading) {
onLoadState('404', routePath);
} else {
if (dataCache[routePath]) {
/**
* Data already exists. Possible causes:
* - User navigates back to a loaded page.
* - This is a hmr update during dev. The dataCache[routePath] contains the old data. We need to load() the new data (but don't show loading state).
* - This is a ssr client-side render. The page data is loaded before hydration.
*/
onLoadState('loaded', routePath);
if (import.meta.hot) {
// If user navigates back to a loaded page during dev
// this will also be executed.
// But in this case, it will import() the same es module again,
// which is handled by the browser es module cache.
// So it won't load the module from dev server again and won't evaluate the module again.
load();
}
} else {
onLoadState('loading', routePath);
load();
}
}
function load() {
loading.then(page => loading === loadingRef.current && unstable_batchedUpdates(() => {
onLoadState('loaded', routePath);
setDataCache(prev => ({
...prev,
[routePath]: page.default
}));
}), error => loading === loadingRef.current && onLoadState('load-error', routePath, error));
}
}, [loading]);
return loadState;
}
const PageLoader = /*#__PURE__*/ReactExports.memo(({
routePath
}) => {
const Theme = useTheme();
const loadState = useAppState(routePath);
const dataCache = useContext(dataCacheCtx);
return /*#__PURE__*/jsx(Theme, {
loadState: loadState,
loadedData: dataCache
});
});
const App = () => {
const pageRoutes = usePagePaths().filter(path => path !== '/404').map(path => {
return {
path,
element: /*#__PURE__*/jsx(PageLoader, {
routePath: path
})
};
});
pageRoutes.push({
path: '*',
element: /*#__PURE__*/jsx(UseLocation, {
children: location => /*#__PURE__*/jsx(PageLoader, {
routePath: location.pathname
})
})
});
const routesRender = useRoutes(pageRoutes);
return routesRender;
};
function UseLocation({
children
}) {
const location = useLocation();
// console.log('###UseLocation', location)
return children(location);
}
/**
* This is the entry for client-side-render(csr).
* Used in: dev mode, build mode.
*/
const container = document.getElementById('root');
const root = createRoot(container);
root.render( /*#__PURE__*/jsx(ClientAppWrapper, {
children: /*#__PURE__*/jsx(App, {})
}));
//# sourceMappingURL=csr.mjs.map