UNPKG

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
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