react-on-rails
Version:
react-on-rails JavaScript for react_on_rails Ruby gem
212 lines • 10.6 kB
JavaScript
import * as Authenticity from "../Authenticity.js";
import buildConsoleReplay, { consoleReplay } from "../buildConsoleReplay.js";
import reactHydrateOrRender from "../reactHydrateOrRender.js";
import createReactOutput from "../createReactOutput.js";
import componentRegistrationMetric from "../componentRegistrationMetric.js";
import { buildRootErrorCallbackOptions, getRootErrorHandlers, resetRootErrorHandlers, setRootErrorHandlers, } from "../rootErrorHandlers.js";
const DEFAULT_OPTIONS = {
traceTurbolinks: false,
turbo: false,
debugMode: false,
logComponentRegistration: false,
};
/**
* Creates the core capability containing all base ReactOnRails methods.
* These are the methods that exist in every bundle variant (client, full, node, RSC).
*/
export function createCoreCapability(registries) {
const { ComponentRegistry, StoreRegistry } = registries;
return {
options: {},
isRSCBundle: false,
// ===================================================================
// STABLE METHOD IMPLEMENTATIONS - Core package implementations
// ===================================================================
authenticityToken() {
return Authenticity.authenticityToken();
},
authenticityHeaders(otherHeaders = {}) {
return Authenticity.authenticityHeaders(otherHeaders);
},
reactHydrateOrRender(domNode, reactElement, hydrate) {
// The component name is unknown on this low-level path; the dom id still ties errors to a mount.
const rootErrorCallbackOptions = buildRootErrorCallbackOptions({ domNodeId: domNode.id || undefined }, hydrate);
return reactHydrateOrRender(domNode, reactElement, hydrate, rootErrorCallbackOptions);
},
setOptions(newOptions) {
const { traceTurbolinks, turbo, debugMode, logComponentRegistration, rootErrorHandlers, ...rest } = newOptions;
if (typeof traceTurbolinks !== 'undefined') {
this.options.traceTurbolinks = traceTurbolinks;
}
if (typeof turbo !== 'undefined') {
this.options.turbo = turbo;
}
if (typeof debugMode !== 'undefined') {
this.options.debugMode = debugMode;
if (debugMode) {
console.log('[ReactOnRails] Debug mode enabled');
}
}
if (typeof logComponentRegistration !== 'undefined') {
this.options.logComponentRegistration = logComponentRegistration;
if (logComponentRegistration) {
console.log('[ReactOnRails] Component registration logging enabled');
}
}
if (Object.prototype.hasOwnProperty.call(newOptions, 'rootErrorHandlers')) {
// Validates and merges the handlers per key (partial updates keep previously registered
// callbacks); warns when the React runtime cannot support them. Store the merged result so
// `option('rootErrorHandlers')` reflects the effective registration.
if (typeof rootErrorHandlers === 'undefined') {
resetRootErrorHandlers();
this.options.rootErrorHandlers = undefined;
}
else {
setRootErrorHandlers(rootErrorHandlers);
this.options.rootErrorHandlers = getRootErrorHandlers();
}
}
if (Object.keys(rest).length > 0) {
throw new Error(`Invalid options passed to ReactOnRails.options: ${JSON.stringify(rest)}`);
}
},
option(key) {
return this.options[key];
},
buildConsoleReplay() {
return buildConsoleReplay();
},
getConsoleReplayScript() {
return consoleReplay();
},
resetOptions() {
this.options = { ...DEFAULT_OPTIONS };
resetRootErrorHandlers();
},
// ===================================================================
// REGISTRY METHOD IMPLEMENTATIONS - Using provided registries
// ===================================================================
register(components) {
if (this.options.debugMode || this.options.logComponentRegistration) {
// Use performance.now() if available, otherwise fallback to Date.now()
const perf = typeof performance !== 'undefined' ? performance : { now: () => Date.now() };
const startTime = perf.now();
const componentNames = Object.keys(components);
console.log(`[ReactOnRails] Registering ${componentNames.length} component(s): ${componentNames.join(', ')}`);
ComponentRegistry.register(components);
const endTime = perf.now();
console.log(`[ReactOnRails] Component registration completed in ${(endTime - startTime).toFixed(2)}ms`);
// Log individual component details if in full debug mode
if (this.options.debugMode) {
componentNames.forEach((name) => {
const component = components[name];
const registrationMetric = componentRegistrationMetric(component);
console.log(`[ReactOnRails] ✅ Registered: ${name} (${registrationMetric.value} ${registrationMetric.label})`);
});
}
}
else {
ComponentRegistry.register(components);
}
},
registerStore(stores) {
this.registerStoreGenerators(stores);
},
registerStoreGenerators(storeGenerators) {
if (!storeGenerators) {
throw new Error('Called ReactOnRails.registerStoreGenerators with a null or undefined, rather than ' +
'an Object with keys being the store names and the values are the store generators.');
}
StoreRegistry.register(storeGenerators);
},
getStore(name, throwIfMissing = true) {
return StoreRegistry.getStore(name, throwIfMissing);
},
getStoreGenerator(name) {
return StoreRegistry.getStoreGenerator(name);
},
setStore(name, store) {
StoreRegistry.setStore(name, store);
},
clearHydratedStores() {
StoreRegistry.clearHydratedStores();
},
clearStoreGenerators() {
StoreRegistry.clearStoreGenerators();
},
getComponent(name) {
return ComponentRegistry.get(name);
},
registeredComponents() {
return ComponentRegistry.components();
},
storeGenerators() {
return StoreRegistry.storeGenerators();
},
stores() {
return StoreRegistry.stores();
},
render(name, props, domNodeId, hydrate) {
const componentObj = ComponentRegistry.get(name);
const reactElement = createReactOutput({ componentObj, props, domNodeId });
return reactHydrateOrRender(document.getElementById(domNodeId), reactElement, hydrate, buildRootErrorCallbackOptions({ componentName: name || undefined, domNodeId: domNodeId || undefined }, hydrate));
},
// ===================================================================
// SSR STUBS — overridden by createSSRCapability() in full/node bundles
// ===================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any
serverRenderReactComponent(...args) {
void args;
throw new Error('serverRenderReactComponent is not available in the client bundle. Import "react-on-rails" server-side.');
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleError(...args) {
void args;
throw new Error('handleError is not available in the client bundle. Import "react-on-rails" server-side.');
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
prepareRenderResult(...args) {
void args;
throw new Error('prepareRenderResult is not available in the client bundle. Import "react-on-rails" server-side.');
},
// ===================================================================
// PRO STUBS — overridden by Pro capabilities in react-on-rails-pro
// ===================================================================
getOrWaitForComponent() {
throw new Error('getOrWaitForComponent requires the react-on-rails-pro package.');
},
getOrWaitForStore() {
throw new Error('getOrWaitForStore requires the react-on-rails-pro package.');
},
getOrWaitForStoreGenerator() {
throw new Error('getOrWaitForStoreGenerator requires the react-on-rails-pro package.');
},
reactOnRailsStoreLoaded() {
throw new Error('reactOnRailsStoreLoaded requires the react-on-rails-pro package.');
},
isServerStreamingSupported() {
throw new Error('isServerStreamingSupported requires the react-on-rails-pro package.');
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
streamServerRenderedReactComponent(...args) {
void args;
throw new Error('streamServerRenderedReactComponent requires the react-on-rails-pro package.');
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
serverRenderRSCReactComponent(...args) {
void args;
throw new Error('serverRenderRSCReactComponent requires the react-on-rails-pro package.');
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
addAsyncPropsCapabilityToComponentProps(...args) {
void args;
throw new Error('addAsyncPropsCapabilityToComponentProps requires the react-on-rails-pro package.');
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getOrCreateAsyncPropsManager(...args) {
void args;
throw new Error('getOrCreateAsyncPropsManager requires the react-on-rails-pro package.');
},
};
}
//# sourceMappingURL=core.js.map