react-on-rails
Version:
react-on-rails JavaScript for react_on_rails Ruby gem
267 lines (264 loc) • 10.6 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
const ClientStartup = require("./clientStartup");
const ComponentRegistry_1 = require("./ComponentRegistry");
const StoreRegistry_1 = require("./StoreRegistry");
const buildConsoleReplay_1 = require("./buildConsoleReplay");
const createReactOutput_1 = require("./createReactOutput");
const Authenticity_1 = require("./Authenticity");
const context_1 = require("./context");
const reactHydrateOrRender_1 = require("./reactHydrateOrRender");
const ctx = (0, context_1.default)();
if (ctx === undefined) {
throw new Error("The context (usually Window or NodeJS's Global) is undefined.");
}
if (ctx.ReactOnRails !== undefined) {
throw new Error(`
The ReactOnRails value exists in the ${ctx} scope, it may not be safe to overwrite it.
This could be caused by setting Webpack's optimization.runtimeChunk to "true" or "multiple," rather than "single." Check your Webpack configuration.
Read more at https://github.com/shakacode/react_on_rails/issues/1558.
`);
}
const DEFAULT_OPTIONS = {
traceTurbolinks: false,
turbo: false,
};
ctx.ReactOnRails = {
options: {},
/**
* Main entry point to using the react-on-rails npm package. This is how Rails will be able to
* find you components for rendering.
* @param components (key is component name, value is component)
*/
register(components) {
ComponentRegistry_1.default.register(components);
},
registerStore(stores) {
this.registerStoreGenerators(stores);
},
/**
* Allows registration of store generators to be used by multiple React components on one Rails
* view. store generators are functions that take one arg, props, and return a store. Note that
* the setStore API is different in that it's the actual store hydrated with props.
* @param storeGenerators (keys are store names, values are the store generators)
*/
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_1.default.register(storeGenerators);
},
/**
* Allows retrieval of the store by name. This store will be hydrated by any Rails form props.
* Pass optional param throwIfMissing = false if you want to use this call to get back null if the
* store with name is not registered.
* @param name
* @param throwIfMissing Defaults to true. Set to false to have this call return undefined if
* there is no store with the given name.
* @returns Redux Store, possibly hydrated
*/
getStore(name, throwIfMissing = true) {
return StoreRegistry_1.default.getStore(name, throwIfMissing);
},
/**
* Renders or hydrates the react element passed. In case react version is >=18 will use the new api.
* @param domNode
* @param reactElement
* @param hydrate if true will perform hydration, if false will render
* @returns {Root|ReactComponent|ReactElement|null}
*/
reactHydrateOrRender(domNode, reactElement, hydrate) {
return (0, reactHydrateOrRender_1.default)(domNode, reactElement, hydrate);
},
/**
* Set options for ReactOnRails, typically before you call ReactOnRails.register
* Available Options:
* `traceTurbolinks: true|false Gives you debugging messages on Turbolinks events
* `turbo: true|false Turbo (the follower of Turbolinks) events will be registered, if set to true.
*/
setOptions(newOptions) {
if (typeof newOptions.traceTurbolinks !== 'undefined') {
this.options.traceTurbolinks = newOptions.traceTurbolinks;
// eslint-disable-next-line no-param-reassign
delete newOptions.traceTurbolinks;
}
if (typeof newOptions.turbo !== 'undefined') {
this.options.turbo = newOptions.turbo;
// eslint-disable-next-line no-param-reassign
delete newOptions.turbo;
}
if (Object.keys(newOptions).length > 0) {
throw new Error(`Invalid options passed to ReactOnRails.options: ${JSON.stringify(newOptions)}`);
}
},
/**
* Allow directly calling the page loaded script in case the default events that trigger react
* rendering are not sufficient, such as when loading JavaScript asynchronously with TurboLinks:
* More details can be found here:
* https://github.com/shakacode/react_on_rails/blob/master/docs/additional-reading/turbolinks.md
*/
reactOnRailsPageLoaded() {
ClientStartup.reactOnRailsPageLoaded();
},
reactOnRailsComponentLoaded(domId) {
ClientStartup.reactOnRailsComponentLoaded(domId);
},
/**
* Returns CSRF authenticity token inserted by Rails csrf_meta_tags
* @returns String or null
*/
authenticityToken() {
return Authenticity_1.default.authenticityToken();
},
/**
* Returns header with csrf authenticity token and XMLHttpRequest
* @param otherHeaders Other headers
* @returns {*} header
*/
authenticityHeaders(otherHeaders = {}) {
return Authenticity_1.default.authenticityHeaders(otherHeaders);
},
// /////////////////////////////////////////////////////////////////////////////
// INTERNALLY USED APIs
// /////////////////////////////////////////////////////////////////////////////
/**
* Retrieve an option by key.
* @param key
* @returns option value
*/
option(key) {
return this.options[key];
},
/**
* Allows retrieval of the store generator by name. This is used internally by ReactOnRails after
* a Rails form loads to prepare stores.
* @param name
* @returns Redux Store generator function
*/
getStoreGenerator(name) {
return StoreRegistry_1.default.getStoreGenerator(name);
},
/**
* Allows saving the store populated by Rails form props. Used internally by ReactOnRails.
* @param name
* @returns Redux Store, possibly hydrated
*/
setStore(name, store) {
return StoreRegistry_1.default.setStore(name, store);
},
/**
* Clears hydratedStores to avoid accidental usage of wrong store hydrated in previous/parallel
* request.
*/
clearHydratedStores() {
StoreRegistry_1.default.clearHydratedStores();
},
/**
* @example
* ReactOnRails.render("HelloWorldApp", {name: "Stranger"}, 'app');
*
* Does this:
* ```js
* ReactDOM.render(React.createElement(HelloWorldApp, {name: "Stranger"}),
* document.getElementById('app'))
* ```
* under React 16/17 and
* ```js
* const root = ReactDOMClient.createRoot(document.getElementById('app'))
* root.render(React.createElement(HelloWorldApp, {name: "Stranger"}))
* return root
* ```
* under React 18+.
*
* @param name Name of your registered component
* @param props Props to pass to your component
* @param domNodeId
* @param hydrate Pass truthy to update server rendered html. Default is falsy
* @returns {Root|ReactComponent|ReactElement} Under React 18+: the created React root
* (see "What is a root?" in https://github.com/reactwg/react-18/discussions/5).
* Under React 16/17: Reference to your component's backing instance or `null` for stateless components.
*/
render(name, props, domNodeId, hydrate) {
const componentObj = ComponentRegistry_1.default.get(name);
const reactElement = (0, createReactOutput_1.default)({ componentObj, props, domNodeId });
return (0, reactHydrateOrRender_1.default)(document.getElementById(domNodeId), reactElement, hydrate);
},
/**
* Get the component that you registered
* @param name
* @returns {name, component, renderFunction, isRenderer}
*/
getComponent(name) {
return ComponentRegistry_1.default.get(name);
},
/**
* Used by server rendering by Rails
* @param options
*/
serverRenderReactComponent() {
throw new Error('serverRenderReactComponent is not available in "react-on-rails/client". Import "react-on-rails" server-side.');
},
/**
* Used by server rendering by Rails
* @param options
*/
streamServerRenderedReactComponent() {
throw new Error('streamServerRenderedReactComponent is only supported when using a bundle built for Node.js environments');
},
/**
* Used by Rails to catch errors in rendering
* @param options
*/
handleError() {
throw new Error('handleError is not available in "react-on-rails/client". Import "react-on-rails" server-side.');
},
/**
* Used by Rails server rendering to replay console messages.
*/
buildConsoleReplay() {
return (0, buildConsoleReplay_1.default)();
},
/**
* Get an Object containing all registered components. Useful for debugging.
* @returns {*}
*/
registeredComponents() {
return ComponentRegistry_1.default.components();
},
/**
* Get an Object containing all registered store generators. Useful for debugging.
* @returns {*}
*/
storeGenerators() {
return StoreRegistry_1.default.storeGenerators();
},
/**
* Get an Object containing all hydrated stores. Useful for debugging.
* @returns {*}
*/
stores() {
return StoreRegistry_1.default.stores();
},
resetOptions() {
this.options = Object.assign({}, DEFAULT_OPTIONS);
},
};
ctx.ReactOnRails.resetOptions();
ClientStartup.clientStartup(ctx);
__exportStar(require("./types"), exports);
exports.default = ctx.ReactOnRails;