@mongez/react-atom
Version:
A simple state management tool for React Js.
82 lines (80 loc) • 2.97 kB
JavaScript
import React from "react";
import { jsx } from "react/jsx-runtime";
//#region ../@mongez/react-atom/src/ssr.tsx
/**
* The default DOM id used by {@link HydrateAtomsScript} and
* {@link readHydration}. Override per-provider if you need to embed
* multiple snapshots in one document.
*/
const DEFAULT_HYDRATION_SCRIPT_ID = "__mongez_atom_state";
/**
* Build a JSON string suitable for embedding inside an HTML `<script>`
* tag. Two safety steps beyond a plain `JSON.stringify`:
*
* 1. The closing tag sequence `</` is escaped to `<\/` so an atom value
* containing literal HTML cannot break out of the script element.
* 2. The U+2028 / U+2029 line separators (which are valid JSON but not
* valid JavaScript string literals) are escaped.
*/
function serializeSnapshot(snapshot, options = {}) {
return JSON.stringify(snapshot, options.replacer, options.space).replace(/<\/(script)/gi, "<\\/$1").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
}
/**
* Convenience that snapshots a store and serializes the result in one call.
*
* const payload = serializeStore(serverStore);
* // payload is a script-safe JSON string
*/
function serializeStore(store, options) {
return serializeSnapshot(store.snapshot(), options);
}
/**
* Renders an inline `<script type="application/json">` carrying a store
* snapshot for the client to pick up.
*
* Place this once per `<AtomStoreProvider>` you want to hydrate. The
* matching client-side call is {@link readHydration}.
*
* // server
* <AtomStoreProvider store={serverStore}>
* <App />
* <HydrateAtomsScript snapshot={serverStore.snapshot()} />
* </AtomStoreProvider>
*
* // client root
* <AtomStoreProvider initialValues={readHydration() ?? undefined}>
* <App />
* </AtomStoreProvider>
*/
function HydrateAtomsScript({ snapshot, id = DEFAULT_HYDRATION_SCRIPT_ID, nonce }) {
return /* @__PURE__ */ jsx("script", {
id,
type: "application/json",
nonce,
dangerouslySetInnerHTML: { __html: typeof snapshot === "string" ? snapshot : serializeSnapshot(snapshot) }
});
}
/**
* Read a hydration snapshot embedded via {@link HydrateAtomsScript} from
* the current document.
*
* - On the server (no `document`), returns `null`.
* - When the script tag is missing, returns `null`.
* - When the script body is not valid JSON, returns `null` and logs the
* error via `console.error` (so a malformed payload is visible during
* development but does not crash hydration).
*/
function readHydration(id = DEFAULT_HYDRATION_SCRIPT_ID) {
if (typeof document === "undefined") return null;
const el = document.getElementById(id);
if (!el) return null;
try {
return JSON.parse(el.textContent ?? "null");
} catch (err) {
console.error(`[@mongez/react-atom] Could not parse hydration script #${id}:`, err);
return null;
}
}
//#endregion
export { DEFAULT_HYDRATION_SCRIPT_ID, HydrateAtomsScript, readHydration, serializeSnapshot, serializeStore };
//# sourceMappingURL=ssr.mjs.map