react-on-rails
Version:
react-on-rails JavaScript for react_on_rails Ruby gem
81 lines • 3.26 kB
JavaScript
import { remapSourceMappedStack } from "./errorUtils.js";
export { convertToError } from "./errorUtils.js";
export function buildRenderMetadata(consoleReplayScript, renderState) {
return {
consoleReplayScript,
clientProps: renderState.clientProps,
hasErrors: renderState.hasErrors,
renderingError: renderState.error && {
message: renderState.error.message,
stack: remapSourceMappedStack(renderState.error.stack),
},
isShellReady: 'isShellReady' in renderState ? renderState.isShellReady : undefined,
};
}
/**
* Returns the UTF-8 byte length of a string.
* Uses native Buffer.byteLength when available (Node.js, Pro node renderer).
* Falls back to a pure-JS implementation for environments without Buffer (mini_racer).
*/
function utf8ByteLength(str) {
if (typeof Buffer !== 'undefined' && typeof Buffer.byteLength === 'function') {
return Buffer.byteLength(str, 'utf-8');
}
let bytes = 0;
for (let i = 0; i < str.length; i += 1) {
const code = str.charCodeAt(i);
if (code <= 0x7f) {
bytes += 1;
}
else if (code <= 0x7ff) {
bytes += 2;
}
else if (code >= 0xd800 && code <= 0xdbff) {
const next = i + 1 < str.length ? str.charCodeAt(i + 1) : 0;
if (next >= 0xdc00 && next <= 0xdfff) {
bytes += 4; // valid surrogate pair
i += 1;
}
else {
bytes += 3; // lone high surrogate → U+FFFD
}
}
else {
bytes += 3; // BMP char (0x800-0xFFFF) or lone low surrogate
}
}
return bytes;
}
/**
* Builds a length-prefixed result string from html content and render state.
* Format: <metadata JSON>\t<content byte length hex>\n<raw html content>
*
* Used by the non-streaming rendering path. The streaming path uses
* buildRenderMetadata directly with Buffer operations for efficiency.
*/
export function buildLengthPrefixedResult(html, consoleReplayScript, renderState) {
// payloadType tells Ruby how to interpret the content bytes:
// "string" — raw HTML, use as-is (the common case)
// "object" — JSON-serialized value, needs JSON.parse (ServerRenderHash or null)
const metadataObj = buildRenderMetadata(consoleReplayScript, renderState);
let htmlStr;
if (typeof html === 'string') {
metadataObj.payloadType = 'string';
htmlStr = html;
}
else {
// Handles null, ServerRenderHashRenderedHtml objects, etc.
// JSON.stringify(null) → "null", which Ruby will JSON.parse back.
metadataObj.payloadType = 'object';
htmlStr = JSON.stringify(html);
}
const metadata = JSON.stringify(metadataObj);
const byteLength = utf8ByteLength(htmlStr);
return `${metadata}\t${byteLength.toString(16).padStart(8, '0')}\n${htmlStr}`;
}
export function validateComponent(componentObj, componentName) {
if (componentObj.isRenderer) {
throw new Error(`Detected a renderer while server rendering component '${componentName}'. See https://github.com/shakacode/react_on_rails#renderer-functions`);
}
}
//# sourceMappingURL=serverRenderUtils.js.map