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>
136 lines • 5.71 kB
JavaScript
import { useMemo } from 'react';
import { dequal } from 'dequal';
import { atom, useAtom } from './jotai';
import { atomFamily, useAtomValue, useUpdateAtom } from './jotai/utils';
export let useTheme;
export let usePagePaths;
export let usePageModule;
export let useStaticData;
import initialPages from '/@react-pages/pages';
import initialTheme from '/@react-pages/theme';
// 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) => {
setTheme === null || setTheme === void 0 ? void 0 : 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) => {
setPages === null || setPages === void 0 ? void 0 : setPages(module.default);
});
const pagesAtom = atom(initialPages);
const pagePathsAtom = atom(initialPagePaths.sort());
const staticDataAtom = atom(toStaticData(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 !== null && newStaticData !== void 0 ? newStaticData : (newStaticData = {});
newStaticData[path] = newPage.staticData;
}
}
// detect deleted pages
for (const path in pages) {
if (!newPages[path]) {
newStaticData !== null && newStaticData !== void 0 ? newStaticData : (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) => (get) => {
const pages = get(pagesAtom);
return pages[path];
});
const staticDataAtoms = atomFamily((path) => (get) => {
const pages = get(pagesAtom);
const page = pages[path];
return page === null || page === void 0 ? void 0 : page.staticData;
});
usePagePaths = () => {
setPages = useUpdateAtom(setPagesAtom);
return useAtomValue(pagePathsAtom);
};
usePageModule = (pagePath) => {
const data = useAtomValue(dataAtoms(pagePath));
return useMemo(() => data === null || data === void 0 ? void 0 : 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);
};
}
// Static mode
else {
useTheme = () => initialTheme;
usePagePaths = () => initialPagePaths;
usePageModule = (path) => {
const page = initialPages[path];
return useMemo(() => page === null || page === void 0 ? void 0 : page.data(), [page]);
};
useStaticData = (path, selector) => {
if (path) {
const page = initialPages[path];
const staticData = (page === null || page === void 0 ? void 0 : page.staticData) || {};
return selector ? selector(staticData) : staticData;
}
return toStaticData(initialPages);
};
}
function toStaticData(pages) {
const staticData = {};
for (const path in pages) {
staticData[path] = pages[path].staticData;
}
return staticData;
}
const globalObject = typeof window !== 'undefined' ? window : global;
if (globalObject['__vite_pages_use_static_data']) {
throw new Error(`[vite-pages] useStaticData already exists on window. There are multiple vite-pages apps in this page. Please report this to vite-pages.`);
}
else {
// make it available to vite-plugin-react-pages/client
globalObject['__vite_pages_use_static_data'] = useStaticData;
}
//# sourceMappingURL=state.js.map