react-on-rails 16.6.0 → 16.7.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/lib/ReactDOMServer.d.cts +2 -0
- package/lib/ReactOnRails.client.js +14 -2
- package/lib/ReactOnRails.full.js +12 -2
- package/lib/RenderUtils.js +2 -5
- package/lib/base/client.d.ts +5 -1
- package/lib/base/client.js +9 -0
- package/lib/base/full.d.ts +5 -1
- package/lib/base/full.js +11 -0
- package/lib/base/full.rsc.d.ts +4 -0
- package/lib/base/full.rsc.js +7 -0
- package/lib/capabilities/core.d.ts +58 -0
- package/lib/capabilities/core.js +188 -0
- package/lib/capabilities/lifecycle.d.ts +9 -0
- package/lib/capabilities/lifecycle.js +19 -0
- package/lib/capabilities/ssr.d.ts +11 -0
- package/lib/capabilities/ssr.js +31 -0
- package/lib/capabilities/ssr.rsc.d.ts +10 -0
- package/lib/capabilities/ssr.rsc.js +19 -0
- package/lib/createReactOnRails.d.ts +18 -5
- package/lib/createReactOnRails.js +97 -63
- package/lib/pageLifecycle.js +23 -11
- package/lib/reactApis.cjs +3 -1
- package/lib/reactApis.d.cts +11 -0
- package/lib/sanitizeNonce.d.ts +15 -0
- package/lib/sanitizeNonce.js +18 -0
- package/lib/scriptSanitizedVal.d.ts +2 -2
- package/lib/scriptSanitizedVal.js +2 -1
- package/lib/serverRenderReactComponent.d.ts +2 -2
- package/lib/serverRenderReactComponent.js +4 -4
- package/lib/serverRenderUtils.d.ts +22 -2
- package/lib/serverRenderUtils.js +89 -4
- package/lib/types/index.d.ts +37 -1
- package/lib/webpackHelpers.cjs +29 -0
- package/lib/webpackHelpers.d.cts +25 -0
- package/package.json +24 -12
- package/LICENSE.md +0 -83
package/README.md
CHANGED
|
@@ -14,6 +14,14 @@ pnpm add react-on-rails
|
|
|
14
14
|
|
|
15
15
|
**Using React on Rails Pro?** Install [`react-on-rails-pro`](https://www.npmjs.com/package/react-on-rails-pro) instead. The Pro package re-exports everything from this package plus Pro-exclusive features. The `react_on_rails_pro` gem requires the Pro npm package.
|
|
16
16
|
|
|
17
|
+
## Need More Than OSS?
|
|
18
|
+
|
|
19
|
+
If you want React Server Components, streaming SSR, fragment caching, or faster Node-based SSR, try [`react-on-rails-pro`](https://www.npmjs.com/package/react-on-rails-pro). It is free to evaluate in development, CI/CD, and staging; production licenses are required only for production deployments.
|
|
20
|
+
|
|
21
|
+
- [Compare OSS vs Pro](https://reactonrails.com/docs/getting-started/oss-vs-pro/)
|
|
22
|
+
- [Pro quick start](https://reactonrails.com/docs/getting-started/pro-quick-start/)
|
|
23
|
+
- [React on Rails Pro overview](https://reactonrails.com/docs/pro/)
|
|
24
|
+
|
|
17
25
|
## Quick Start
|
|
18
26
|
|
|
19
27
|
### Register Components
|
|
@@ -1,7 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createCoreCapability } from "./capabilities/core.js";
|
|
2
|
+
import { createLifecycleCapability } from "./capabilities/lifecycle.js";
|
|
2
3
|
import createReactOnRails from "./createReactOnRails.js";
|
|
4
|
+
import ComponentRegistry from "./ComponentRegistry.js";
|
|
5
|
+
import StoreRegistry from "./StoreRegistry.js";
|
|
6
|
+
import { clientStartup } from "./clientStartup.js";
|
|
7
|
+
const registries = { ComponentRegistry, StoreRegistry };
|
|
3
8
|
const currentGlobal = globalThis.ReactOnRails || null;
|
|
4
|
-
const ReactOnRails = createReactOnRails(
|
|
9
|
+
const ReactOnRails = createReactOnRails([createCoreCapability(registries), createLifecycleCapability()], {
|
|
10
|
+
currentGlobal,
|
|
11
|
+
// Defer startup to the next tick so all synchronous <script> tags finish evaluating
|
|
12
|
+
// before we scan the DOM for components. Pro's proClientStartup runs synchronously
|
|
13
|
+
// because streaming hydration needs to attach listeners before the first paint.
|
|
14
|
+
startup: typeof window !== 'undefined' ? () => setTimeout(() => clientStartup(), 0) : null,
|
|
15
|
+
registries,
|
|
16
|
+
});
|
|
5
17
|
export * from "./types/index.js";
|
|
6
18
|
export default ReactOnRails;
|
|
7
19
|
//# sourceMappingURL=ReactOnRails.client.js.map
|
package/lib/ReactOnRails.full.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createCoreCapability } from "./capabilities/core.js";
|
|
2
|
+
import { createLifecycleCapability } from "./capabilities/lifecycle.js";
|
|
3
|
+
import { createSSRCapability } from "./capabilities/ssr.js";
|
|
2
4
|
import createReactOnRails from "./createReactOnRails.js";
|
|
5
|
+
import ComponentRegistry from "./ComponentRegistry.js";
|
|
6
|
+
import StoreRegistry from "./StoreRegistry.js";
|
|
7
|
+
import { clientStartup } from "./clientStartup.js";
|
|
8
|
+
const registries = { ComponentRegistry, StoreRegistry };
|
|
3
9
|
const currentGlobal = globalThis.ReactOnRails || null;
|
|
4
|
-
const ReactOnRails = createReactOnRails(
|
|
10
|
+
const ReactOnRails = createReactOnRails([createCoreCapability(registries), createLifecycleCapability(), createSSRCapability()], {
|
|
11
|
+
currentGlobal,
|
|
12
|
+
startup: typeof window !== 'undefined' ? () => setTimeout(() => clientStartup(), 0) : null,
|
|
13
|
+
registries,
|
|
14
|
+
});
|
|
5
15
|
export * from "./types/index.js";
|
|
6
16
|
export default ReactOnRails;
|
|
7
17
|
//# sourceMappingURL=ReactOnRails.full.js.map
|
package/lib/RenderUtils.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
+
import sanitizeNonce from "./sanitizeNonce.js";
|
|
1
2
|
// eslint-disable-next-line import/prefer-default-export -- only one export for now, but others may be added later
|
|
2
3
|
export function wrapInScriptTags(scriptId, scriptBody, nonce) {
|
|
3
4
|
if (!scriptBody) {
|
|
4
5
|
return '';
|
|
5
6
|
}
|
|
6
|
-
|
|
7
|
-
// CSP nonces should be base64/base64url-like strings with optional trailing padding.
|
|
8
|
-
// NOTE: keep this logic in sync with sanitizeNonce() in react-on-rails-pro/src/utils.ts
|
|
9
|
-
const nonceWithAllowedCharsOnly = nonce?.replace(/[^a-zA-Z0-9+/=_-]/g, '');
|
|
10
|
-
const sanitizedNonce = nonceWithAllowedCharsOnly?.match(/^[a-zA-Z0-9+/_-]+={0,2}$/)?.[0];
|
|
7
|
+
const sanitizedNonce = sanitizeNonce(nonce);
|
|
11
8
|
const nonceAttr = sanitizedNonce ? ` nonce="${sanitizedNonce}"` : '';
|
|
12
9
|
return `
|
|
13
10
|
<script id="${scriptId}"${nonceAttr}>
|
package/lib/base/client.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use `capabilities/core.ts` instead. This file is kept for backward compatibility
|
|
3
|
+
* with older versions of react-on-rails-pro that import from `react-on-rails/@internal/base/client`.
|
|
4
|
+
*/
|
|
1
5
|
import type { RegisteredComponent, ReactComponentOrRenderFunction, Store, StoreGenerator, ReactOnRailsInternal } from '../types/index.ts';
|
|
2
6
|
interface Registries {
|
|
3
7
|
ComponentRegistry: {
|
|
@@ -19,7 +23,7 @@ interface Registries {
|
|
|
19
23
|
* Base client object type that includes all core ReactOnRails methods except Pro-specific ones.
|
|
20
24
|
* Derived from ReactOnRailsInternal by omitting Pro-only methods.
|
|
21
25
|
*/
|
|
22
|
-
export type BaseClientObjectType = Omit<ReactOnRailsInternal, 'getOrWaitForComponent' | 'getOrWaitForStore' | 'getOrWaitForStoreGenerator' | 'reactOnRailsStoreLoaded' | 'streamServerRenderedReactComponent' | 'serverRenderRSCReactComponent'>;
|
|
26
|
+
export type BaseClientObjectType = Omit<ReactOnRailsInternal, 'getOrWaitForComponent' | 'getOrWaitForStore' | 'getOrWaitForStoreGenerator' | 'reactOnRailsStoreLoaded' | 'streamServerRenderedReactComponent' | 'serverRenderRSCReactComponent' | 'addAsyncPropsCapabilityToComponentProps' | 'getOrCreateAsyncPropsManager'>;
|
|
23
27
|
export declare function createBaseClientObject(registries: Registries, currentObject?: BaseClientObjectType | null): BaseClientObjectType;
|
|
24
28
|
export {};
|
|
25
29
|
//# sourceMappingURL=client.d.ts.map
|
package/lib/base/client.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use `capabilities/core.ts` instead. This file is kept for backward compatibility
|
|
3
|
+
* with older versions of react-on-rails-pro that import from `react-on-rails/@internal/base/client`.
|
|
4
|
+
*/
|
|
1
5
|
import * as Authenticity from "../Authenticity.js";
|
|
2
6
|
import buildConsoleReplay, { consoleReplay } from "../buildConsoleReplay.js";
|
|
3
7
|
import reactHydrateOrRender from "../reactHydrateOrRender.js";
|
|
@@ -201,6 +205,11 @@ Fix: Use only react-on-rails OR react-on-rails-pro, not both.`);
|
|
|
201
205
|
void args; // Mark as used
|
|
202
206
|
throw new Error('handleError is not available in "react-on-rails/client". Import "react-on-rails" server-side.');
|
|
203
207
|
},
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
209
|
+
prepareRenderResult(...args) {
|
|
210
|
+
void args; // Mark as used
|
|
211
|
+
throw new Error('prepareRenderResult is not available in "react-on-rails/client". Import "react-on-rails" server-side.');
|
|
212
|
+
},
|
|
204
213
|
};
|
|
205
214
|
// Cache the object and registries
|
|
206
215
|
cachedObject = obj;
|
package/lib/base/full.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use `capabilities/ssr.ts` instead. This file is kept for backward compatibility
|
|
3
|
+
* with older versions of react-on-rails-pro that import from `react-on-rails/@internal/base/full`.
|
|
4
|
+
*/
|
|
1
5
|
import { createBaseClientObject, type BaseClientObjectType } from './client.ts';
|
|
2
6
|
import type { ReactOnRailsInternal } from '../types/index.ts';
|
|
3
7
|
/**
|
|
4
8
|
* SSR-specific functions that extend the base client object to create a full object.
|
|
5
9
|
* Typed explicitly to ensure type safety when mutating the base object.
|
|
6
10
|
*/
|
|
7
|
-
export type ReactOnRailsFullSpecificFunctions = Pick<ReactOnRailsInternal, 'handleError' | 'serverRenderReactComponent'>;
|
|
11
|
+
export type ReactOnRailsFullSpecificFunctions = Pick<ReactOnRailsInternal, 'handleError' | 'serverRenderReactComponent' | 'prepareRenderResult'>;
|
|
8
12
|
/**
|
|
9
13
|
* Full object type that includes all base methods plus real SSR implementations.
|
|
10
14
|
* Derived from ReactOnRailsInternal by picking base methods and SSR methods.
|
package/lib/base/full.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use `capabilities/ssr.ts` instead. This file is kept for backward compatibility
|
|
3
|
+
* with older versions of react-on-rails-pro that import from `react-on-rails/@internal/base/full`.
|
|
4
|
+
*/
|
|
1
5
|
import { createBaseClientObject } from "./client.js";
|
|
2
6
|
import handleError from "../handleError.js";
|
|
3
7
|
import serverRenderReactComponent from "../serverRenderReactComponent.js";
|
|
8
|
+
import { buildLengthPrefixedResult } from "../serverRenderUtils.js";
|
|
4
9
|
// Warn about bundle size when included in browser bundles
|
|
5
10
|
if (typeof window !== 'undefined') {
|
|
6
11
|
console.warn('Optimization opportunity: "react-on-rails" includes ~14KB of server-rendering code. ' +
|
|
@@ -19,6 +24,12 @@ export function createBaseFullObject(registries, currentObject = null) {
|
|
|
19
24
|
serverRenderReactComponent(options) {
|
|
20
25
|
return serverRenderReactComponent(options);
|
|
21
26
|
},
|
|
27
|
+
prepareRenderResult(html, consoleReplayScript, hasErrors, renderingError) {
|
|
28
|
+
return buildLengthPrefixedResult(html, consoleReplayScript, {
|
|
29
|
+
hasErrors,
|
|
30
|
+
error: renderingError ?? undefined,
|
|
31
|
+
});
|
|
32
|
+
},
|
|
22
33
|
};
|
|
23
34
|
// Type assertion is safe here because:
|
|
24
35
|
// 1. We start with BaseClientObjectType (from createBaseClientObject)
|
package/lib/base/full.rsc.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use `capabilities/ssr.rsc.ts` instead. This file is kept for backward compatibility
|
|
3
|
+
* with older versions of react-on-rails-pro that import from `react-on-rails/@internal/base/full`.
|
|
4
|
+
*/
|
|
1
5
|
import { createBaseClientObject, type BaseClientObjectType } from './client.ts';
|
|
2
6
|
import type { BaseFullObjectType } from './full.ts';
|
|
3
7
|
export type * from './full.ts';
|
package/lib/base/full.rsc.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use `capabilities/ssr.rsc.ts` instead. This file is kept for backward compatibility
|
|
3
|
+
* with older versions of react-on-rails-pro that import from `react-on-rails/@internal/base/full`.
|
|
4
|
+
*/
|
|
1
5
|
import { createBaseClientObject } from "./client.js";
|
|
2
6
|
export function createBaseFullObject(registries, currentObject = null) {
|
|
3
7
|
// Get or create client object (with caching logic)
|
|
@@ -11,6 +15,9 @@ export function createBaseFullObject(registries, currentObject = null) {
|
|
|
11
15
|
serverRenderReactComponent() {
|
|
12
16
|
throw new Error('"serverRenderReactComponent" function is not supported in RSC bundle');
|
|
13
17
|
},
|
|
18
|
+
prepareRenderResult() {
|
|
19
|
+
throw new Error('"prepareRenderResult" function is not supported in RSC bundle');
|
|
20
|
+
},
|
|
14
21
|
};
|
|
15
22
|
// Type assertion is safe here because:
|
|
16
23
|
// 1. We start with BaseClientObjectType (from createBaseClientObject)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { RegisteredComponent, RenderReturnType, ReactComponentOrRenderFunction, AuthenticityHeaders, Store, StoreGenerator, ReactOnRailsOptions } from '../types/index.ts';
|
|
3
|
+
export interface Registries {
|
|
4
|
+
ComponentRegistry: {
|
|
5
|
+
register: (components: Record<string, ReactComponentOrRenderFunction>) => void;
|
|
6
|
+
get: (name: string) => RegisteredComponent;
|
|
7
|
+
components: () => Map<string, RegisteredComponent>;
|
|
8
|
+
};
|
|
9
|
+
StoreRegistry: {
|
|
10
|
+
register: (storeGenerators: Record<string, StoreGenerator>) => void;
|
|
11
|
+
getStore: (name: string, throwIfMissing?: boolean) => Store | undefined;
|
|
12
|
+
getStoreGenerator: (name: string) => StoreGenerator;
|
|
13
|
+
setStore: (name: string, store: Store) => void;
|
|
14
|
+
clearHydratedStores: () => void;
|
|
15
|
+
storeGenerators: () => Map<string, StoreGenerator>;
|
|
16
|
+
stores: () => Map<string, Store>;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates the core capability containing all base ReactOnRails methods.
|
|
21
|
+
* These are the methods that exist in every bundle variant (client, full, node, RSC).
|
|
22
|
+
*/
|
|
23
|
+
export declare function createCoreCapability(registries: Registries): {
|
|
24
|
+
options: Partial<ReactOnRailsOptions>;
|
|
25
|
+
isRSCBundle: boolean;
|
|
26
|
+
authenticityToken(): string | null;
|
|
27
|
+
authenticityHeaders(otherHeaders?: Record<string, string>): AuthenticityHeaders;
|
|
28
|
+
reactHydrateOrRender(domNode: Element, reactElement: ReactElement, hydrate: boolean): RenderReturnType;
|
|
29
|
+
setOptions(newOptions: Partial<ReactOnRailsOptions>): void;
|
|
30
|
+
option<K extends keyof ReactOnRailsOptions>(key: K): ReactOnRailsOptions[K];
|
|
31
|
+
buildConsoleReplay(): string;
|
|
32
|
+
getConsoleReplayScript(): string;
|
|
33
|
+
resetOptions(): void;
|
|
34
|
+
register(components: Record<string, ReactComponentOrRenderFunction>): void;
|
|
35
|
+
registerStore(stores: Record<string, StoreGenerator>): void;
|
|
36
|
+
registerStoreGenerators(storeGenerators: Record<string, StoreGenerator>): void;
|
|
37
|
+
getStore(name: string, throwIfMissing?: boolean): Store | undefined;
|
|
38
|
+
getStoreGenerator(name: string): StoreGenerator;
|
|
39
|
+
setStore(name: string, store: Store): void;
|
|
40
|
+
clearHydratedStores(): void;
|
|
41
|
+
getComponent(name: string): RegisteredComponent;
|
|
42
|
+
registeredComponents(): Map<string, RegisteredComponent>;
|
|
43
|
+
storeGenerators(): Map<string, StoreGenerator>;
|
|
44
|
+
stores(): Map<string, Store>;
|
|
45
|
+
render(name: string, props: Record<string, string>, domNodeId: string, hydrate: boolean): RenderReturnType;
|
|
46
|
+
serverRenderReactComponent(...args: any[]): any;
|
|
47
|
+
handleError(...args: any[]): any;
|
|
48
|
+
prepareRenderResult(...args: any[]): any;
|
|
49
|
+
getOrWaitForComponent(): Promise<RegisteredComponent>;
|
|
50
|
+
getOrWaitForStore(): Promise<Store>;
|
|
51
|
+
getOrWaitForStoreGenerator(): Promise<StoreGenerator>;
|
|
52
|
+
reactOnRailsStoreLoaded(): Promise<void>;
|
|
53
|
+
streamServerRenderedReactComponent(...args: any[]): any;
|
|
54
|
+
serverRenderRSCReactComponent(...args: any[]): any;
|
|
55
|
+
addAsyncPropsCapabilityToComponentProps(...args: any[]): any;
|
|
56
|
+
getOrCreateAsyncPropsManager(...args: any[]): any;
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import * as Authenticity from "../Authenticity.js";
|
|
2
|
+
import buildConsoleReplay, { consoleReplay } from "../buildConsoleReplay.js";
|
|
3
|
+
import reactHydrateOrRender from "../reactHydrateOrRender.js";
|
|
4
|
+
import createReactOutput from "../createReactOutput.js";
|
|
5
|
+
const DEFAULT_OPTIONS = {
|
|
6
|
+
traceTurbolinks: false,
|
|
7
|
+
turbo: false,
|
|
8
|
+
debugMode: false,
|
|
9
|
+
logComponentRegistration: false,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Creates the core capability containing all base ReactOnRails methods.
|
|
13
|
+
* These are the methods that exist in every bundle variant (client, full, node, RSC).
|
|
14
|
+
*/
|
|
15
|
+
export function createCoreCapability(registries) {
|
|
16
|
+
const { ComponentRegistry, StoreRegistry } = registries;
|
|
17
|
+
return {
|
|
18
|
+
options: {},
|
|
19
|
+
isRSCBundle: false,
|
|
20
|
+
// ===================================================================
|
|
21
|
+
// STABLE METHOD IMPLEMENTATIONS - Core package implementations
|
|
22
|
+
// ===================================================================
|
|
23
|
+
authenticityToken() {
|
|
24
|
+
return Authenticity.authenticityToken();
|
|
25
|
+
},
|
|
26
|
+
authenticityHeaders(otherHeaders = {}) {
|
|
27
|
+
return Authenticity.authenticityHeaders(otherHeaders);
|
|
28
|
+
},
|
|
29
|
+
reactHydrateOrRender(domNode, reactElement, hydrate) {
|
|
30
|
+
return reactHydrateOrRender(domNode, reactElement, hydrate);
|
|
31
|
+
},
|
|
32
|
+
setOptions(newOptions) {
|
|
33
|
+
const { traceTurbolinks, turbo, debugMode, logComponentRegistration, ...rest } = newOptions;
|
|
34
|
+
if (typeof traceTurbolinks !== 'undefined') {
|
|
35
|
+
this.options.traceTurbolinks = traceTurbolinks;
|
|
36
|
+
}
|
|
37
|
+
if (typeof turbo !== 'undefined') {
|
|
38
|
+
this.options.turbo = turbo;
|
|
39
|
+
}
|
|
40
|
+
if (typeof debugMode !== 'undefined') {
|
|
41
|
+
this.options.debugMode = debugMode;
|
|
42
|
+
if (debugMode) {
|
|
43
|
+
console.log('[ReactOnRails] Debug mode enabled');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (typeof logComponentRegistration !== 'undefined') {
|
|
47
|
+
this.options.logComponentRegistration = logComponentRegistration;
|
|
48
|
+
if (logComponentRegistration) {
|
|
49
|
+
console.log('[ReactOnRails] Component registration logging enabled');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (Object.keys(rest).length > 0) {
|
|
53
|
+
throw new Error(`Invalid options passed to ReactOnRails.options: ${JSON.stringify(rest)}`);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
option(key) {
|
|
57
|
+
return this.options[key];
|
|
58
|
+
},
|
|
59
|
+
buildConsoleReplay() {
|
|
60
|
+
return buildConsoleReplay();
|
|
61
|
+
},
|
|
62
|
+
getConsoleReplayScript() {
|
|
63
|
+
return consoleReplay();
|
|
64
|
+
},
|
|
65
|
+
resetOptions() {
|
|
66
|
+
this.options = { ...DEFAULT_OPTIONS };
|
|
67
|
+
},
|
|
68
|
+
// ===================================================================
|
|
69
|
+
// REGISTRY METHOD IMPLEMENTATIONS - Using provided registries
|
|
70
|
+
// ===================================================================
|
|
71
|
+
register(components) {
|
|
72
|
+
if (this.options.debugMode || this.options.logComponentRegistration) {
|
|
73
|
+
// Use performance.now() if available, otherwise fallback to Date.now()
|
|
74
|
+
const perf = typeof performance !== 'undefined' ? performance : { now: () => Date.now() };
|
|
75
|
+
const startTime = perf.now();
|
|
76
|
+
const componentNames = Object.keys(components);
|
|
77
|
+
console.log(`[ReactOnRails] Registering ${componentNames.length} component(s): ${componentNames.join(', ')}`);
|
|
78
|
+
ComponentRegistry.register(components);
|
|
79
|
+
const endTime = perf.now();
|
|
80
|
+
console.log(`[ReactOnRails] Component registration completed in ${(endTime - startTime).toFixed(2)}ms`);
|
|
81
|
+
// Log individual component details if in full debug mode
|
|
82
|
+
if (this.options.debugMode) {
|
|
83
|
+
componentNames.forEach((name) => {
|
|
84
|
+
const component = components[name];
|
|
85
|
+
const size = component.toString().length;
|
|
86
|
+
console.log(`[ReactOnRails] ✅ Registered: ${name} (${size} chars)`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
ComponentRegistry.register(components);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
registerStore(stores) {
|
|
95
|
+
this.registerStoreGenerators(stores);
|
|
96
|
+
},
|
|
97
|
+
registerStoreGenerators(storeGenerators) {
|
|
98
|
+
if (!storeGenerators) {
|
|
99
|
+
throw new Error('Called ReactOnRails.registerStoreGenerators with a null or undefined, rather than ' +
|
|
100
|
+
'an Object with keys being the store names and the values are the store generators.');
|
|
101
|
+
}
|
|
102
|
+
StoreRegistry.register(storeGenerators);
|
|
103
|
+
},
|
|
104
|
+
getStore(name, throwIfMissing = true) {
|
|
105
|
+
return StoreRegistry.getStore(name, throwIfMissing);
|
|
106
|
+
},
|
|
107
|
+
getStoreGenerator(name) {
|
|
108
|
+
return StoreRegistry.getStoreGenerator(name);
|
|
109
|
+
},
|
|
110
|
+
setStore(name, store) {
|
|
111
|
+
StoreRegistry.setStore(name, store);
|
|
112
|
+
},
|
|
113
|
+
clearHydratedStores() {
|
|
114
|
+
StoreRegistry.clearHydratedStores();
|
|
115
|
+
},
|
|
116
|
+
getComponent(name) {
|
|
117
|
+
return ComponentRegistry.get(name);
|
|
118
|
+
},
|
|
119
|
+
registeredComponents() {
|
|
120
|
+
return ComponentRegistry.components();
|
|
121
|
+
},
|
|
122
|
+
storeGenerators() {
|
|
123
|
+
return StoreRegistry.storeGenerators();
|
|
124
|
+
},
|
|
125
|
+
stores() {
|
|
126
|
+
return StoreRegistry.stores();
|
|
127
|
+
},
|
|
128
|
+
render(name, props, domNodeId, hydrate) {
|
|
129
|
+
const componentObj = ComponentRegistry.get(name);
|
|
130
|
+
const reactElement = createReactOutput({ componentObj, props, domNodeId });
|
|
131
|
+
return this.reactHydrateOrRender(document.getElementById(domNodeId), reactElement, hydrate);
|
|
132
|
+
},
|
|
133
|
+
// ===================================================================
|
|
134
|
+
// SSR STUBS — overridden by createSSRCapability() in full/node bundles
|
|
135
|
+
// ===================================================================
|
|
136
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
137
|
+
serverRenderReactComponent(...args) {
|
|
138
|
+
void args;
|
|
139
|
+
throw new Error('serverRenderReactComponent is not available in the client bundle. Import "react-on-rails" server-side.');
|
|
140
|
+
},
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
142
|
+
handleError(...args) {
|
|
143
|
+
void args;
|
|
144
|
+
throw new Error('handleError is not available in the client bundle. Import "react-on-rails" server-side.');
|
|
145
|
+
},
|
|
146
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
147
|
+
prepareRenderResult(...args) {
|
|
148
|
+
void args;
|
|
149
|
+
throw new Error('prepareRenderResult is not available in the client bundle. Import "react-on-rails" server-side.');
|
|
150
|
+
},
|
|
151
|
+
// ===================================================================
|
|
152
|
+
// PRO STUBS — overridden by Pro capabilities in react-on-rails-pro
|
|
153
|
+
// ===================================================================
|
|
154
|
+
getOrWaitForComponent() {
|
|
155
|
+
throw new Error('getOrWaitForComponent requires the react-on-rails-pro package.');
|
|
156
|
+
},
|
|
157
|
+
getOrWaitForStore() {
|
|
158
|
+
throw new Error('getOrWaitForStore requires the react-on-rails-pro package.');
|
|
159
|
+
},
|
|
160
|
+
getOrWaitForStoreGenerator() {
|
|
161
|
+
throw new Error('getOrWaitForStoreGenerator requires the react-on-rails-pro package.');
|
|
162
|
+
},
|
|
163
|
+
reactOnRailsStoreLoaded() {
|
|
164
|
+
throw new Error('reactOnRailsStoreLoaded requires the react-on-rails-pro package.');
|
|
165
|
+
},
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
167
|
+
streamServerRenderedReactComponent(...args) {
|
|
168
|
+
void args;
|
|
169
|
+
throw new Error('streamServerRenderedReactComponent requires the react-on-rails-pro package.');
|
|
170
|
+
},
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
172
|
+
serverRenderRSCReactComponent(...args) {
|
|
173
|
+
void args;
|
|
174
|
+
throw new Error('serverRenderRSCReactComponent requires the react-on-rails-pro package.');
|
|
175
|
+
},
|
|
176
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
177
|
+
addAsyncPropsCapabilityToComponentProps(...args) {
|
|
178
|
+
void args;
|
|
179
|
+
throw new Error('addAsyncPropsCapabilityToComponentProps requires the react-on-rails-pro package.');
|
|
180
|
+
},
|
|
181
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
182
|
+
getOrCreateAsyncPropsManager(...args) {
|
|
183
|
+
void args;
|
|
184
|
+
throw new Error('getOrCreateAsyncPropsManager requires the react-on-rails-pro package.');
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core lifecycle capability.
|
|
3
|
+
* Provides the core (non-Pro) implementations for page/component loaded callbacks.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createLifecycleCapability(): {
|
|
6
|
+
reactOnRailsPageLoaded(): Promise<void>;
|
|
7
|
+
reactOnRailsComponentLoaded(domId: string): Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export -- named export for consistency with capability API */
|
|
2
|
+
import { reactOnRailsPageLoaded } from "../clientStartup.js";
|
|
3
|
+
import { reactOnRailsComponentLoaded } from "../ClientRenderer.js";
|
|
4
|
+
/**
|
|
5
|
+
* Core lifecycle capability.
|
|
6
|
+
* Provides the core (non-Pro) implementations for page/component loaded callbacks.
|
|
7
|
+
*/
|
|
8
|
+
export function createLifecycleCapability() {
|
|
9
|
+
return {
|
|
10
|
+
reactOnRailsPageLoaded() {
|
|
11
|
+
reactOnRailsPageLoaded();
|
|
12
|
+
return Promise.resolve();
|
|
13
|
+
},
|
|
14
|
+
reactOnRailsComponentLoaded(domId) {
|
|
15
|
+
return reactOnRailsComponentLoaded(domId);
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RenderParams, ErrorOptions, RenderingError } from '../types/index.ts';
|
|
2
|
+
/**
|
|
3
|
+
* SSR capability.
|
|
4
|
+
* Provides server-side rendering methods (serverRenderReactComponent, handleError).
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSSRCapability(): {
|
|
7
|
+
handleError(options: ErrorOptions): string | undefined;
|
|
8
|
+
serverRenderReactComponent(options: RenderParams): null | string | Promise<string>;
|
|
9
|
+
prepareRenderResult(html: string, consoleReplayScript: string, hasErrors: boolean, renderingError: RenderingError | null): string;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=ssr.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export -- named export for consistency with capability API */
|
|
2
|
+
import handleError from "../handleError.js";
|
|
3
|
+
import serverRenderReactComponent from "../serverRenderReactComponent.js";
|
|
4
|
+
import { buildLengthPrefixedResult } from "../serverRenderUtils.js";
|
|
5
|
+
// Warn about bundle size when included in browser bundles
|
|
6
|
+
if (typeof window !== 'undefined') {
|
|
7
|
+
console.warn('Optimization opportunity: this bundle includes ~14KB of server-rendering code that browsers may not need. ' +
|
|
8
|
+
'See https://forum.shakacode.com/t/how-to-use-different-versions-of-a-file-for-client-and-server-rendering/1352 ' +
|
|
9
|
+
'(Requires creating a free account). Click this for the stack trace.');
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* SSR capability.
|
|
13
|
+
* Provides server-side rendering methods (serverRenderReactComponent, handleError).
|
|
14
|
+
*/
|
|
15
|
+
export function createSSRCapability() {
|
|
16
|
+
return {
|
|
17
|
+
handleError(options) {
|
|
18
|
+
return handleError(options);
|
|
19
|
+
},
|
|
20
|
+
serverRenderReactComponent(options) {
|
|
21
|
+
return serverRenderReactComponent(options);
|
|
22
|
+
},
|
|
23
|
+
prepareRenderResult(html, consoleReplayScript, hasErrors, renderingError) {
|
|
24
|
+
return buildLengthPrefixedResult(html, consoleReplayScript, {
|
|
25
|
+
hasErrors,
|
|
26
|
+
error: renderingError ?? undefined,
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=ssr.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR capability for RSC bundles.
|
|
3
|
+
* SSR methods throw because they are not supported in the RSC bundle.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createSSRCapability(): {
|
|
6
|
+
handleError(): never;
|
|
7
|
+
serverRenderReactComponent(): never;
|
|
8
|
+
prepareRenderResult(): never;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=ssr.rsc.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable import/prefer-default-export -- named export for consistency with capability API */
|
|
2
|
+
/**
|
|
3
|
+
* SSR capability for RSC bundles.
|
|
4
|
+
* SSR methods throw because they are not supported in the RSC bundle.
|
|
5
|
+
*/
|
|
6
|
+
export function createSSRCapability() {
|
|
7
|
+
return {
|
|
8
|
+
handleError() {
|
|
9
|
+
throw new Error('"handleError" function is not supported in RSC bundle');
|
|
10
|
+
},
|
|
11
|
+
serverRenderReactComponent() {
|
|
12
|
+
throw new Error('"serverRenderReactComponent" function is not supported in RSC bundle');
|
|
13
|
+
},
|
|
14
|
+
prepareRenderResult() {
|
|
15
|
+
throw new Error('"prepareRenderResult" function is not supported in RSC bundle');
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=ssr.rsc.js.map
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createBaseFullObject } from './base/full.ts';
|
|
1
|
+
import type { Registries } from './capabilities/core.ts';
|
|
3
2
|
import type { ReactOnRailsInternal } from './types/index.ts';
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
export type { Registries };
|
|
4
|
+
/**
|
|
5
|
+
* Assembles the ReactOnRails global object from an array of capabilities.
|
|
6
|
+
*
|
|
7
|
+
* Each capability is a partial implementation of ReactOnRailsInternal.
|
|
8
|
+
* Capabilities are merged in array order (last wins for overlapping keys).
|
|
9
|
+
*
|
|
10
|
+
* @param capabilities - Array of capability objects to merge.
|
|
11
|
+
* @param options.currentGlobal - Current globalThis.ReactOnRails value (for misconfiguration detection).
|
|
12
|
+
* @param options.startup - Callback invoked once on first initialization, after the global is set.
|
|
13
|
+
* @param options.registries - The registries used by the core capability (for mixing detection).
|
|
14
|
+
*/
|
|
15
|
+
export default function createReactOnRails(capabilities: Partial<ReactOnRailsInternal>[], options: {
|
|
16
|
+
currentGlobal: ReactOnRailsInternal | null;
|
|
17
|
+
startup: (() => void) | null;
|
|
18
|
+
registries: Registries;
|
|
19
|
+
}): ReactOnRailsInternal;
|
|
7
20
|
//# sourceMappingURL=createReactOnRails.d.ts.map
|