UNPKG

vite-plugin-react18-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>

818 lines (661 loc) 20.9 kB
import { useRef, useState, useEffect, createContext, createElement, useCallback, useDebugValue, useContext } from 'react'; function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } const hasInitialValue = atom => 'init' in atom; const createState = (initialValues, newAtomReceiver) => { const state = { n: newAtomReceiver, v: 0, a: new WeakMap(), m: new WeakMap(), p: new Set() }; if (initialValues) { for (const [atom, value] of initialValues) { const atomState = { v: value, r: 0, d: new Map() }; if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { Object.freeze(atomState); } state.a.set(atom, atomState); } } return state; }; const getAtomState = (state, atom) => state.a.get(atom); const wipAtomState = (state, atom, dependencies) => { const atomState = getAtomState(state, atom); const nextAtomState = _extends({ r: 0 }, atomState, { d: dependencies ? new Map(Array.from(dependencies).map(a => { var _getAtomState$r, _getAtomState; return [a, (_getAtomState$r = (_getAtomState = getAtomState(state, a)) == null ? void 0 : _getAtomState.r) != null ? _getAtomState$r : 0]; })) : atomState ? atomState.d : new Map() }); if (!atomState && hasInitialValue(atom)) { nextAtomState.v = atom.init; } return [nextAtomState, atomState == null ? void 0 : atomState.d]; }; const setAtomValue = (state, atom, value, dependencies, promise) => { const [atomState, prevDependencies] = wipAtomState(state, atom, dependencies); if (promise && promise !== (atomState == null ? void 0 : atomState.p)) { // newer async read is running, not updating return; } delete atomState.e; // read error delete atomState.p; // read promise delete atomState.i; // invalidated revision if (!('v' in atomState) || !Object.is(atomState.v, value)) { atomState.v = value; ++atomState.r; // increment revision } commitAtomState(state, atom, atomState); mountDependencies(state, atom, atomState, prevDependencies); }; const setAtomReadError = (state, atom, error, dependencies, promise) => { const [atomState, prevDependencies] = wipAtomState(state, atom, dependencies); if (promise && promise !== (atomState == null ? void 0 : atomState.p)) { // newer async read is running, not updating return; } delete atomState.p; // read promise delete atomState.i; // invalidated revision atomState.e = error; // read error commitAtomState(state, atom, atomState); mountDependencies(state, atom, atomState, prevDependencies); }; const setAtomReadPromise = (state, atom, promise, dependencies) => { const [atomState, prevDependencies] = wipAtomState(state, atom, dependencies); atomState.p = promise; // read promise commitAtomState(state, atom, atomState); mountDependencies(state, atom, atomState, prevDependencies); }; const setAtomInvalidated = (state, atom) => { const [atomState] = wipAtomState(state, atom); atomState.i = atomState.r; // invalidated revision commitAtomState(state, atom, atomState); }; const setAtomWritePromise = (state, atom, promise) => { const [atomState] = wipAtomState(state, atom); if (promise) { atomState.w = promise; } else { delete atomState.w; // write promise } commitAtomState(state, atom, atomState); }; const scheduleReadAtomState = (state, atom, promise) => { promise.then(() => { readAtomState(state, atom, true); }); }; const readAtomState = (state, atom, force) => { if (!force) { const atomState = getAtomState(state, atom); if (atomState) { atomState.d.forEach((_, a) => { if (a !== atom) { const aState = getAtomState(state, a); if (aState && !aState.e && // no read error !aState.p && // no read promise aState.r === aState.i // revision is invalidated ) { readAtomState(state, a, true); } } }); if (Array.from(atomState.d.entries()).every(([a, r]) => { const aState = getAtomState(state, a); return aState && !aState.e && // no read error !aState.p && // no read promise aState.r !== aState.i && // revision is not invalidated aState.r === r // revision is equal to the last one ; })) { return atomState; } } } let error; let promise; let value; const dependencies = new Set(); try { const promiseOrValue = atom.read(a => { dependencies.add(a); if (a !== atom) { const aState = readAtomState(state, a); if (aState.e) { throw aState.e; // read error } if (aState.p) { throw aState.p; // read promise } return aState.v; // value } // a === atom const aState = getAtomState(state, a); if (aState) { if (aState.p) { throw aState.p; // read promise } return aState.v; // value } if (hasInitialValue(a)) { return a.init; } throw new Error('no atom init'); }); if (promiseOrValue instanceof Promise) { promise = promiseOrValue.then(value => { setAtomValue(state, atom, value, dependencies, promise); flushPending(state); }).catch(e => { if (e instanceof Promise) { scheduleReadAtomState(state, atom, e); return e; } setAtomReadError(state, atom, e instanceof Error ? e : new Error(e), dependencies, promise); flushPending(state); }); } else { value = promiseOrValue; } } catch (errorOrPromise) { if (errorOrPromise instanceof Promise) { scheduleReadAtomState(state, atom, errorOrPromise); promise = errorOrPromise; } else if (errorOrPromise instanceof Error) { error = errorOrPromise; } else { error = new Error(errorOrPromise); } } if (error) { setAtomReadError(state, atom, error, dependencies); } else if (promise) { setAtomReadPromise(state, atom, promise, dependencies); } else { setAtomValue(state, atom, value, dependencies); } return getAtomState(state, atom); }; const readAtom = (state, readingAtom) => { const atomState = readAtomState(state, readingAtom); state.p.delete(readingAtom); flushPending(state); return atomState; }; const addAtom = (state, addingAtom) => { let mounted = state.m.get(addingAtom); if (!mounted) { mounted = mountAtom(state, addingAtom); } flushPending(state); return mounted; }; // XXX doesn't work with mutally dependent atoms const canUnmountAtom = (atom, mounted) => !mounted.l.size && (!mounted.d.size || mounted.d.size === 1 && mounted.d.has(atom)); const delAtom = (state, deletingAtom) => { const mounted = state.m.get(deletingAtom); if (mounted && canUnmountAtom(deletingAtom, mounted)) { unmountAtom(state, deletingAtom); } flushPending(state); }; const invalidateDependents = (state, atom) => { const mounted = state.m.get(atom); mounted == null ? void 0 : mounted.d.forEach(dependent => { if (dependent === atom) { return; } setAtomInvalidated(state, dependent); invalidateDependents(state, dependent); }); }; const writeAtomState = (state, atom, update, pendingPromises) => { const isPendingPromisesExpired = !pendingPromises.length; const atomState = getAtomState(state, atom); if (atomState && atomState.w // write promise ) { const promise = atomState.w.then(() => { writeAtomState(state, atom, update, pendingPromises); if (isPendingPromisesExpired) { flushPending(state); } }); if (!isPendingPromisesExpired) { pendingPromises.push(promise); } return; } try { const promiseOrVoid = atom.write(a => { const aState = readAtomState(state, a); if (aState.e) { throw aState.e; // read error } if (aState.p) { if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { console.warn('Reading pending atom state in write operation. We throw a promise for now.', a); } throw aState.p; // read promise } if ('v' in aState) { return aState.v; // value } if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { console.warn('[Bug] no value found while reading atom in write operation. This probably a bug.', a); } throw new Error('no value found'); }, (a, v) => { if (a === atom) { setAtomValue(state, a, v); invalidateDependents(state, a); } else { const isPendingPromisesExpired = !pendingPromises.length; writeAtomState(state, a, v, pendingPromises); if (isPendingPromisesExpired) { flushPending(state); } } }, update); if (promiseOrVoid instanceof Promise) { const promise = promiseOrVoid.then(() => { setAtomWritePromise(state, atom); if (isPendingPromisesExpired) { flushPending(state); } }); if (!isPendingPromisesExpired) { pendingPromises.push(promise); } setAtomWritePromise(state, atom, promise); } } catch (e) { if (pendingPromises.length === 1) { // still in sync, throw it right away throw e; } else if (!isPendingPromisesExpired) { pendingPromises.push(new Promise((_resolve, reject) => { reject(e); })); } else { console.error('Uncaught exception: Use promise to catch error', e); } } }; const writeAtom = (state, writingAtom, update) => { const pendingPromises = [Promise.resolve()]; writeAtomState(state, writingAtom, update, pendingPromises); flushPending(state); if (pendingPromises.length <= 1) { pendingPromises.splice(0); } else { return new Promise((resolve, reject) => { const loop = () => { if (pendingPromises.length <= 1) { pendingPromises.splice(0); resolve(); } else { Promise.all(pendingPromises).then(() => { pendingPromises.splice(1); flushPending(state); loop(); }).catch(reject); } }; loop(); }); } }; const isActuallyWritableAtom = atom => !!atom.write; const mountAtom = (state, atom, initialDependent) => { // mount dependencies beforehand const atomState = getAtomState(state, atom); if (atomState) { atomState.d.forEach((_, a) => { if (a !== atom) { // check if not mounted if (!state.m.has(a)) { mountAtom(state, a, atom); } } }); } else if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { console.warn('[Bug] could not find atom state to mount', atom); } // mount self const mounted = { d: new Set(initialDependent && [initialDependent]), l: new Set(), u: undefined }; state.m.set(atom, mounted); if (isActuallyWritableAtom(atom) && atom.onMount) { const setAtom = update => writeAtom(state, atom, update); mounted.u = atom.onMount(setAtom); } return mounted; }; const unmountAtom = (state, atom) => { var _state$m$get; // unmount self const onUnmount = (_state$m$get = state.m.get(atom)) == null ? void 0 : _state$m$get.u; if (onUnmount) { onUnmount(); } state.m.delete(atom); // unmount dependencies afterward const atomState = getAtomState(state, atom); if (atomState) { if (atomState.p && // read promise typeof process === 'object' && process.env.NODE_ENV !== 'production') { console.warn('[Bug] deleting atomState with read promise', atom); } atomState.d.forEach((_, a) => { if (a !== atom) { const mounted = state.m.get(a); if (mounted) { mounted.d.delete(atom); if (canUnmountAtom(a, mounted)) { unmountAtom(state, a); } } } }); } else if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { console.warn('[Bug] could not find atom state to unmount', atom); } }; const mountDependencies = (state, atom, atomState, prevDependencies) => { if (prevDependencies !== atomState.d) { const dependencies = new Set(atomState.d.keys()); if (prevDependencies) { prevDependencies.forEach((_, a) => { const mounted = state.m.get(a); if (dependencies.has(a)) { // not changed dependencies.delete(a); } else if (mounted) { mounted.d.delete(atom); if (canUnmountAtom(a, mounted)) { unmountAtom(state, a); } } else if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { console.warn('[Bug] a dependency is not mounted', a); } }); } dependencies.forEach(a => { const mounted = state.m.get(a); if (mounted) { const dependents = mounted.d; dependents.add(atom); } else { mountAtom(state, a, atom); } }); } }; const commitAtomState = (state, atom, atomState) => { if (typeof process === 'object' && process.env.NODE_ENV !== 'production') { Object.freeze(atomState); } const isNewAtom = state.n && !state.a.has(atom); state.a.set(atom, atomState); if (isNewAtom) { state.n(atom); } ++state.v; state.p.add(atom); }; const flushPending = state => { state.p.forEach(atom => { const mounted = state.m.get(atom); mounted == null ? void 0 : mounted.l.forEach(listener => listener()); }); state.p.clear(); }; const subscribeAtom = (state, atom, callback) => { const mounted = addAtom(state, atom); const listeners = mounted.l; listeners.add(callback); return () => { listeners.delete(callback); delAtom(state, atom); }; }; /* export { unstable_createMutableSource as createMutableSource, unstable_useMutableSource as useMutableSource, } from 'react' */ const TARGET = Symbol(); const GET_VERSION = Symbol(); const createMutableSource = (target, getVersion) => ({ [TARGET]: target, [GET_VERSION]: getVersion }); const useMutableSource = (source, getSnapshot, subscribe) => { const lastVersion = useRef(0); const currentVersion = source[GET_VERSION](source[TARGET]); const [state, setState] = useState(() => [ /* [0] */ source, /* [1] */ getSnapshot, /* [2] */ subscribe, /* [3] */ currentVersion, /* [4] */ getSnapshot(source[TARGET])]); let currentSnapshot = state[4]; if (state[0] !== source || state[1] !== getSnapshot || state[2] !== subscribe) { currentSnapshot = getSnapshot(source[TARGET]); setState([ /* [0] */ source, /* [1] */ getSnapshot, /* [2] */ subscribe, /* [3] */ currentVersion, /* [4] */ currentSnapshot]); } else if (currentVersion !== state[3] && currentVersion !== lastVersion.current) { currentSnapshot = getSnapshot(source[TARGET]); if (!Object.is(currentSnapshot, state[4])) { setState([ /* [0] */ source, /* [1] */ getSnapshot, /* [2] */ subscribe, /* [3] */ currentVersion, /* [4] */ currentSnapshot]); } } useEffect(() => { let didUnsubscribe = false; const checkForUpdates = () => { if (didUnsubscribe) { return; } try { const nextSnapshot = getSnapshot(source[TARGET]); const nextVersion = source[GET_VERSION](source[TARGET]); lastVersion.current = nextVersion; setState(prev => { if (prev[0] !== source || prev[1] !== getSnapshot || prev[2] !== subscribe) { return prev; } if (Object.is(prev[4], nextSnapshot)) { return prev; } return [ /* [0] */ prev[0], /* [1] */ prev[1], /* [2] */ prev[2], /* [3] */ nextVersion, /* [4] */ nextSnapshot]; }); } catch (e) { // schedule update setState(prev => [...prev]); } }; const unsubscribe = subscribe(source[TARGET], checkForUpdates); checkForUpdates(); return () => { didUnsubscribe = true; unsubscribe(); }; }, [source, getSnapshot, subscribe]); return currentSnapshot; }; const createStore = (initialValues, newAtomReceiver) => { const state = createState(initialValues, newAtomReceiver); const mutableSource = createMutableSource(state, () => state.v); const updateAtom = (atom, update) => writeAtom(state, atom, update); return [mutableSource, updateAtom]; }; const StoreContextMap = new Map(); const getStoreContext = scope => { if (!StoreContextMap.has(scope)) { StoreContextMap.set(scope, createContext(createStore())); } return StoreContextMap.get(scope); }; const Provider = ({ initialValues, scope, children }) => { const storeRef = useRef(null); if (typeof process === 'object' && process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'test') { /* eslint-disable react-hooks/rules-of-hooks */ const atomsRef = useRef([]); if (storeRef.current === null) { // lazy initialization storeRef.current = createStore(initialValues, newAtom => { atomsRef.current.push(newAtom); }); } useDebugState(storeRef.current, atomsRef.current); /* eslint-enable react-hooks/rules-of-hooks */ } else { if (storeRef.current === null) { // lazy initialization storeRef.current = createStore(initialValues); } } const StoreContext = getStoreContext(scope); return createElement(StoreContext.Provider, { value: storeRef.current }, children); }; const atomToPrintable = atom => atom.debugLabel || atom.toString(); const stateToPrintable = ([state, atoms]) => Object.fromEntries(atoms.flatMap(atom => { const mounted = state.m.get(atom); if (!mounted) { return []; } const dependents = mounted.d; const atomState = state.a.get(atom) || {}; return [[atomToPrintable(atom), { value: atomState.e || atomState.p || atomState.w || atomState.v, dependents: Array.from(dependents).map(atomToPrintable) }]]; })); const getState = state => _extends({}, state); // shallow copy // We keep a reference to the atoms in Provider's atomsRef in dev mode, // so atoms aren't garbage collected by the WeakMap of mounted atoms const useDebugState = (store, atoms) => { const subscribe = useCallback((state, callback) => { // FIXME we don't need to resubscribe, just need to subscribe for new one const unsubs = atoms.map(atom => subscribeAtom(state, atom, callback)); return () => { unsubs.forEach(unsub => unsub()); }; }, [atoms]); const state = useMutableSource(store[0], getState, subscribe); useDebugValue([state, atoms], stateToPrintable); }; let keyCount = 0; // global key count for all atoms 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 = get => get(config); config.write = (get, set, update) => { set(config, typeof update === 'function' ? update(get(config)) : update); }; } if (write) { config.write = write; } return config; } const isWritable = atom => !!atom.write; function useAtom(atom) { const getAtomValue = useCallback(state => { const atomState = readAtom(state, atom); if (atomState.e) { throw atomState.e; // read error } if (atomState.p) { throw atomState.p; // read promise } if (atomState.w) { throw atomState.w; // write promise } if ('v' in atomState) { return atomState.v; } throw new Error('no atom value'); }, [atom]); const subscribe = useCallback((state, callback) => subscribeAtom(state, atom, callback), [atom]); const StoreContext = getStoreContext(atom.scope); const [mutableSource, updateAtom] = useContext(StoreContext); const value = useMutableSource(mutableSource, getAtomValue, subscribe); const setAtom = useCallback(update => { if (isWritable(atom)) { return updateAtom(atom, update); } else { throw new Error('not writable atom'); } }, [updateAtom, atom]); useDebugValue(value); return [value, setAtom]; } export { Provider, getStoreContext as SECRET_INTERNAL_getStoreContext, atom, useAtom };