react-on-rails 13.0.2 → 13.2.0
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 +44 -19
- package/node_package/lib/ReactOnRails.d.ts +1 -1
- package/node_package/lib/ReactOnRails.js +27 -8
- package/node_package/lib/clientStartup.d.ts +6 -2
- package/node_package/lib/clientStartup.js +42 -29
- package/node_package/lib/reactApis.d.ts +1 -0
- package/node_package/lib/reactApis.js +13 -0
- package/node_package/lib/reactHydrateOrRender.d.ts +7 -0
- package/node_package/lib/reactHydrateOrRender.js +43 -0
- package/node_package/lib/types/index.d.ts +9 -3
- package/package.json +2 -2
- package/CHANGELOG.md +0 -1141
- package/node_package/lib/reactHydrate.d.ts +0 -2
- package/node_package/lib/reactHydrate.js +0 -15
- package/node_package/lib/reactRender.d.ts +0 -2
- package/node_package/lib/reactRender.js +0 -18
- package/node_package/lib/supportsReactCreateRoot.d.ts +0 -3
- package/node_package/lib/supportsReactCreateRoot.js +0 -11
package/README.md
CHANGED
|
@@ -9,7 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
[](LICENSE.md)
|
|
12
|
+
[](LICENSE.md)[](https://badge.fury.io/rb/react_on_rails) [](https://badge.fury.io/js/react-on-rails) [](https://codeclimate.com/github/shakacode/react_on_rails) [](https://coveralls.io/github/shakacode/react_on_rails?branch=master) [](https://rubygems.org/gems/react_on_rails)
|
|
13
|
+
|
|
14
|
+
[](https://github.com/shakacode/react_on_rails/actions/workflows/main.yml)
|
|
15
|
+
[](https://github.com/shakacode/react_on_rails/actions/workflows/package-js-tests.yml)
|
|
16
|
+
[](https://github.com/shakacode/react_on_rails/actions/workflows/rspec-package-specs.yml)
|
|
17
|
+
[](https://github.com/shakacode/react_on_rails/actions/workflows/lint-js-and-ruby.yml)
|
|
13
18
|
|
|
14
19
|
# News
|
|
15
20
|
* ShakaCode now maintains the official successor to `rails/webpacker`, [`shakapacker`](https://github.com/shakacode/shakapacker).
|
|
@@ -27,7 +32,7 @@ This project is maintained by the software consulting firm [ShakaCode](https://w
|
|
|
27
32
|
Are you interested in optimizing your webpack setup for React on Rails including code
|
|
28
33
|
splitting with [react-router](https://github.com/ReactTraining/react-router#readme) and
|
|
29
34
|
[loadable-components](https://loadable-components.com/) with server-side rendering for SEO and hot-reloading for developers?
|
|
30
|
-
We did this for Popmenu, [lowering Heroku costs 20-25% while getting a 73% decrease in average response times](https://www.shakacode.com/recent-work/popmenu/). Several years later, Popmenu is serving millions of SSR requests per day React on Rails.
|
|
35
|
+
We did this for Popmenu, [lowering Heroku costs 20-25% while getting a 73% decrease in average response times](https://www.shakacode.com/recent-work/popmenu/). Several years later, Popmenu is serving millions of SSR requests per day with React on Rails.
|
|
31
36
|
|
|
32
37
|
Check out [React on Rails Pro](https://www.shakacode.com/react-on-rails-pro/). For more information, feel free to contact Justin Gordon, [justin@shakacode.com](mailto:justin@shakacode.com), maintainer of React on Rails.
|
|
33
38
|
|
|
@@ -43,9 +48,12 @@ To provide a high performance framework for integrating Ruby on Rails with React
|
|
|
43
48
|
|
|
44
49
|
Given that `rails/webpacker` gem already provides basic React integration, why would you use "React on Rails"?
|
|
45
50
|
|
|
51
|
+
1. Automatic configuration of what bundles are added to the page based on what React components are on the page. This results in faster browser loading time via smaller bundle sizes.
|
|
52
|
+
1. Keep up with the latest changes of different versions of React. React 18 is supported.
|
|
46
53
|
1. Easy passing of props directly from your Rails view to your React components rather than having your Rails view load and then make a separate request to your API.
|
|
47
|
-
|
|
54
|
+
Tight integration with [shakapacker](https://github.com/shakacode/shakapacker) (or it's predecessor [rails/webpacker](https://github.com/rails/webpacker)).
|
|
48
55
|
1. Server-Side Rendering (SSR), often used for SEO crawler indexing and UX performance.
|
|
56
|
+
1. [Automated optimized entry-point creation and bundle inclusion when placing a component on a page. With this feature, you no longer need to configure `javascript_pack_tags` and `stylesheet_pack_tags` on your layouts based on what’s shown. “It just works!”](https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md)
|
|
49
57
|
1. [Redux](https://github.com/reactjs/redux) and [React Router](https://github.com/ReactTraining/react-router#readme) integration with server-side-rendering.
|
|
50
58
|
1. [Internationalization (I18n) and (localization)](https://www.shakacode.com/react-on-rails/docs/guides/i18n)
|
|
51
59
|
1. A supportive community. This [web search shows how live public sites are using React on Rails](https://publicwww.com/websites/%22react-on-rails%22++-undeveloped.com+depth%3Aall/).
|
|
@@ -65,7 +73,7 @@ _Requires creating a free account._
|
|
|
65
73
|
|
|
66
74
|
## Prerequisites
|
|
67
75
|
|
|
68
|
-
Ruby on Rails >=5, rails/webpacker >= 4.2, Ruby >= 2.7
|
|
76
|
+
Ruby on Rails >=5, rails/webpacker >= 4.2 or shakapacker > 6, Ruby >= 2.7
|
|
69
77
|
|
|
70
78
|
# Support
|
|
71
79
|
|
|
@@ -81,24 +89,41 @@ Ruby on Rails >=5, rails/webpacker >= 4.2, Ruby >= 2.7
|
|
|
81
89
|
|
|
82
90
|
Bug reports and pull requests are welcome. See [Contributing](https://github.com/shakacode/react_on_rails/tree/master/CONTRIBUTING.md) to get started, and the [list of help wanted issues](https://github.com/shakacode/react_on_rails/labels/contributions%3A%20up%20for%20grabs%21).
|
|
83
91
|
|
|
84
|
-
# Supporters
|
|
85
|
-
|
|
86
|
-
The following companies support this open source project, and ShakaCode uses their products! Justin writes React on Rails on [RubyMine](https://www.jetbrains.com/ruby/). We use [Scout](https://scoutapp.com/) to monitor the live performance of [HiChee.com](https://HiChee.com), [Rails AutoScale](https://railsautoscale.com) to scale the dynos of HiChee, and [HoneyBadger](https://www.honeybadger.io/) to monitor application errors. We love [BrowserStack](https://www.browserstack.com) to solve problems with oddball browsers. [Status Hero](https://statushero.com/) keeps the team posted on daily progress; it's so much better than live standups.
|
|
87
|
-
|
|
88
|
-
[](https://www.jetbrains.com/ruby/)
|
|
89
|
-
[](https://scoutapp.com/)
|
|
90
|
-
[](https://railsautoscale.com/)
|
|
91
|
-
[](https://www.browserstack.com)
|
|
92
|
-
[](https://www.honeybadger.io/)
|
|
93
|
-
[](https://statushero.com/)
|
|
94
|
-
|
|
95
|
-
ShakaCode's favorite project tracking tool is [Shortcut](https://shortcut.com/). If you want to **try Shortcut and get 2 months free beyond the 14-day trial period**, click [here to use ShakaCode's referral code](http://r.clbh.se/mvfoNeH). We're participating in their awesome triple-sided referral program, which you can read about [here](https://clubhouse.io/referral/). By using our [referral code](http://r.clbh.se/mvfoNeH) you'll be supporting ShakaCode and, thus, React on Rails!
|
|
96
|
-
|
|
97
|
-
Aloha and best wishes from Justin and the ShakaCode team!
|
|
98
|
-
|
|
99
92
|
# Work with Us
|
|
100
93
|
ShakaCode is **[hiring passionate software engineers](http://www.shakacode.com/career)** to work on our projects, including [HiChee](https://hichee.com)!
|
|
101
94
|
|
|
102
95
|
# License
|
|
103
96
|
|
|
104
97
|
The gem is available as open source under the terms of the [MIT License](https://github.com/shakacode/react_on_rails/tree/master/LICENSE.md).
|
|
98
|
+
|
|
99
|
+
# Supporters
|
|
100
|
+
|
|
101
|
+
<a href="https://www.jetbrains.com">
|
|
102
|
+
<img src="https://user-images.githubusercontent.com/4244251/184881139-42e4076b-024b-4b30-8c60-c3cd0e758c0a.png" alt="JetBrains" height="120px">
|
|
103
|
+
</a>
|
|
104
|
+
<a href="https://scoutapp.com">
|
|
105
|
+
<picture>
|
|
106
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/4244251/184881147-0d077438-3978-40da-ace9-4f650d2efe2e.png">
|
|
107
|
+
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/4244251/184881152-9f2d8fba-88ac-4ba6-873b-22387f8711c5.png">
|
|
108
|
+
<img alt="ScoutAPM" src="https://user-images.githubusercontent.com/4244251/184881152-9f2d8fba-88ac-4ba6-873b-22387f8711c5.png" height="120px">
|
|
109
|
+
</picture>
|
|
110
|
+
</a>
|
|
111
|
+
<br />
|
|
112
|
+
<a href="https://www.browserstack.com">
|
|
113
|
+
<picture>
|
|
114
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/4244251/184881122-407dcc29-df78-4b20-a9ad-f597b56f6cdb.png">
|
|
115
|
+
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/4244251/184881129-e1edf4b7-3ae1-4ea8-9e6d-3595cf01609e.png">
|
|
116
|
+
<img alt="BrowserStack" src="https://user-images.githubusercontent.com/4244251/184881129-e1edf4b7-3ae1-4ea8-9e6d-3595cf01609e.png" height="55px">
|
|
117
|
+
</picture>
|
|
118
|
+
</a>
|
|
119
|
+
<a href="https://railsautoscale.com">
|
|
120
|
+
<img src="https://user-images.githubusercontent.com/4244251/184881144-95c2c25c-9879-4069-864d-4e67d6ed39d2.png" alt="Rails Autoscale" height="55px">
|
|
121
|
+
</a>
|
|
122
|
+
<a href="https://www.honeybadger.io">
|
|
123
|
+
<img src="https://user-images.githubusercontent.com/4244251/184881133-79ee9c3c-8165-4852-958e-31687b9536f4.png" alt="Honeybadger" height="55px">
|
|
124
|
+
</a>
|
|
125
|
+
|
|
126
|
+
<br />
|
|
127
|
+
<br />
|
|
128
|
+
|
|
129
|
+
The following companies support our open source projects, and ShakaCode uses their products!
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("./types
|
|
1
|
+
declare const _default: import("./types").ReactOnRails;
|
|
2
2
|
export default _default;
|
|
@@ -31,8 +31,7 @@ var buildConsoleReplay_1 = __importDefault(require("./buildConsoleReplay"));
|
|
|
31
31
|
var createReactOutput_1 = __importDefault(require("./createReactOutput"));
|
|
32
32
|
var Authenticity_1 = __importDefault(require("./Authenticity"));
|
|
33
33
|
var context_1 = __importDefault(require("./context"));
|
|
34
|
-
var
|
|
35
|
-
var reactRender_1 = __importDefault(require("./reactRender"));
|
|
34
|
+
var reactHydrateOrRender_1 = __importDefault(require("./reactHydrateOrRender"));
|
|
36
35
|
var ctx = context_1.default();
|
|
37
36
|
if (ctx === undefined) {
|
|
38
37
|
throw new Error("The context (usually Window or NodeJS's Global) is undefined.");
|
|
@@ -77,6 +76,16 @@ ctx.ReactOnRails = {
|
|
|
77
76
|
if (throwIfMissing === void 0) { throwIfMissing = true; }
|
|
78
77
|
return StoreRegistry_1.default.getStore(name, throwIfMissing);
|
|
79
78
|
},
|
|
79
|
+
/**
|
|
80
|
+
* Renders or hydrates the react element passed. In case react version is >=18 will use the new api.
|
|
81
|
+
* @param domNode
|
|
82
|
+
* @param reactElement
|
|
83
|
+
* @param hydrate if true will perform hydration, if false will render
|
|
84
|
+
* @returns {Root|ReactComponent|ReactElement|null}
|
|
85
|
+
*/
|
|
86
|
+
reactHydrateOrRender: function (domNode, reactElement, hydrate) {
|
|
87
|
+
return reactHydrateOrRender_1.default(domNode, reactElement, hydrate);
|
|
88
|
+
},
|
|
80
89
|
/**
|
|
81
90
|
* Set options for ReactOnRails, typically before you call ReactOnRails.register
|
|
82
91
|
* Available Options:
|
|
@@ -159,24 +168,34 @@ ctx.ReactOnRails = {
|
|
|
159
168
|
StoreRegistry_1.default.clearHydratedStores();
|
|
160
169
|
},
|
|
161
170
|
/**
|
|
171
|
+
* @example
|
|
162
172
|
* ReactOnRails.render("HelloWorldApp", {name: "Stranger"}, 'app');
|
|
163
173
|
*
|
|
164
174
|
* Does this:
|
|
165
|
-
*
|
|
166
|
-
*
|
|
175
|
+
* ```js
|
|
176
|
+
* ReactDOM.render(React.createElement(HelloWorldApp, {name: "Stranger"}),
|
|
177
|
+
* document.getElementById('app'))
|
|
178
|
+
* ```
|
|
179
|
+
* under React 16/17 and
|
|
180
|
+
* ```js
|
|
181
|
+
* const root = ReactDOMClient.createRoot(document.getElementById('app'))
|
|
182
|
+
* root.render(React.createElement(HelloWorldApp, {name: "Stranger"}))
|
|
183
|
+
* return root
|
|
184
|
+
* ```
|
|
185
|
+
* under React 18+.
|
|
167
186
|
*
|
|
168
187
|
* @param name Name of your registered component
|
|
169
188
|
* @param props Props to pass to your component
|
|
170
189
|
* @param domNodeId
|
|
171
190
|
* @param hydrate Pass truthy to update server rendered html. Default is falsy
|
|
172
|
-
* @returns {
|
|
191
|
+
* @returns {Root|ReactComponent|ReactElement} Under React 18+: the created React root
|
|
192
|
+
* (see "What is a root?" in https://github.com/reactwg/react-18/discussions/5).
|
|
193
|
+
* Under React 16/17: Reference to your component's backing instance or `null` for stateless components.
|
|
173
194
|
*/
|
|
174
195
|
render: function (name, props, domNodeId, hydrate) {
|
|
175
196
|
var componentObj = ComponentRegistry_1.default.get(name);
|
|
176
197
|
var reactElement = createReactOutput_1.default({ componentObj: componentObj, props: props, domNodeId: domNodeId });
|
|
177
|
-
|
|
178
|
-
// eslint-disable-next-line react/no-render-return-value
|
|
179
|
-
return render(document.getElementById(domNodeId), reactElement);
|
|
198
|
+
return reactHydrateOrRender_1.default(document.getElementById(domNodeId), reactElement, hydrate);
|
|
180
199
|
},
|
|
181
200
|
/**
|
|
182
201
|
* Get the component that you registered
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import type { ReactOnRails as ReactOnRailsType } from './types
|
|
1
|
+
import type { ReactOnRails as ReactOnRailsType, Root } from './types';
|
|
2
2
|
declare global {
|
|
3
3
|
interface Window {
|
|
4
4
|
ReactOnRails: ReactOnRailsType;
|
|
5
5
|
__REACT_ON_RAILS_EVENT_HANDLERS_RAN_ONCE__?: boolean;
|
|
6
|
+
roots: Root[];
|
|
6
7
|
}
|
|
7
8
|
namespace NodeJS {
|
|
8
9
|
interface Global {
|
|
9
10
|
ReactOnRails: ReactOnRailsType;
|
|
11
|
+
roots: Root[];
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
namespace Turbolinks {
|
|
@@ -15,5 +17,7 @@ declare global {
|
|
|
15
17
|
}
|
|
16
18
|
}
|
|
17
19
|
}
|
|
20
|
+
declare type Context = Window | NodeJS.Global;
|
|
18
21
|
export declare function reactOnRailsPageLoaded(): void;
|
|
19
|
-
export declare function clientStartup(context:
|
|
22
|
+
export declare function clientStartup(context: Context): void;
|
|
23
|
+
export {};
|
|
@@ -12,8 +12,8 @@ exports.clientStartup = exports.reactOnRailsPageLoaded = void 0;
|
|
|
12
12
|
var react_dom_1 = __importDefault(require("react-dom"));
|
|
13
13
|
var createReactOutput_1 = __importDefault(require("./createReactOutput"));
|
|
14
14
|
var isServerRenderResult_1 = require("./isServerRenderResult");
|
|
15
|
-
var
|
|
16
|
-
var
|
|
15
|
+
var reactHydrateOrRender_1 = __importDefault(require("./reactHydrateOrRender"));
|
|
16
|
+
var reactApis_1 = require("./reactApis");
|
|
17
17
|
var REACT_ON_RAILS_STORE_ATTRIBUTE = 'data-js-react-on-rails-store';
|
|
18
18
|
function findContext() {
|
|
19
19
|
if (typeof window.ReactOnRails !== 'undefined') {
|
|
@@ -50,24 +50,17 @@ function turboInstalled() {
|
|
|
50
50
|
function reactOnRailsHtmlElements() {
|
|
51
51
|
return document.getElementsByClassName('js-react-on-rails-component');
|
|
52
52
|
}
|
|
53
|
-
function
|
|
54
|
-
var
|
|
55
|
-
for (var i = 0; i < els.length; i += 1) {
|
|
56
|
-
fn(els[i], railsContext);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function initializeStore(el, railsContext) {
|
|
60
|
-
var context = findContext();
|
|
61
|
-
var name = el.getAttribute(REACT_ON_RAILS_STORE_ATTRIBUTE) || "";
|
|
53
|
+
function initializeStore(el, context, railsContext) {
|
|
54
|
+
var name = el.getAttribute(REACT_ON_RAILS_STORE_ATTRIBUTE) || '';
|
|
62
55
|
var props = (el.textContent !== null) ? JSON.parse(el.textContent) : {};
|
|
63
56
|
var storeGenerator = context.ReactOnRails.getStoreGenerator(name);
|
|
64
57
|
var store = storeGenerator(props, railsContext);
|
|
65
58
|
context.ReactOnRails.setStore(name, store);
|
|
66
59
|
}
|
|
67
|
-
function forEachStore(railsContext) {
|
|
60
|
+
function forEachStore(context, railsContext) {
|
|
68
61
|
var els = document.querySelectorAll("[" + REACT_ON_RAILS_STORE_ATTRIBUTE + "]");
|
|
69
62
|
for (var i = 0; i < els.length; i += 1) {
|
|
70
|
-
initializeStore(els[i], railsContext);
|
|
63
|
+
initializeStore(els[i], context, railsContext);
|
|
71
64
|
}
|
|
72
65
|
}
|
|
73
66
|
function turbolinksVersion5() {
|
|
@@ -88,20 +81,18 @@ function delegateToRenderer(componentObj, props, railsContext, domNodeId, trace)
|
|
|
88
81
|
return false;
|
|
89
82
|
}
|
|
90
83
|
function domNodeIdForEl(el) {
|
|
91
|
-
return el.getAttribute('data-dom-id') ||
|
|
84
|
+
return el.getAttribute('data-dom-id') || '';
|
|
92
85
|
}
|
|
93
86
|
/**
|
|
94
87
|
* Used for client rendering by ReactOnRails. Either calls ReactDOM.hydrate, ReactDOM.render, or
|
|
95
88
|
* delegates to a renderer registered by the user.
|
|
96
|
-
* @param el
|
|
97
89
|
*/
|
|
98
|
-
function render(el, railsContext) {
|
|
99
|
-
var context = findContext();
|
|
90
|
+
function render(el, context, railsContext) {
|
|
100
91
|
// This must match lib/react_on_rails/helper.rb
|
|
101
|
-
var name = el.getAttribute('data-component-name') ||
|
|
92
|
+
var name = el.getAttribute('data-component-name') || '';
|
|
102
93
|
var domNodeId = domNodeIdForEl(el);
|
|
103
94
|
var props = (el.textContent !== null) ? JSON.parse(el.textContent) : {};
|
|
104
|
-
var trace = el.getAttribute('data-trace') ===
|
|
95
|
+
var trace = el.getAttribute('data-trace') === 'true';
|
|
105
96
|
try {
|
|
106
97
|
var domNode = document.getElementById(domNodeId);
|
|
107
98
|
if (domNode) {
|
|
@@ -123,11 +114,11 @@ function render(el, railsContext) {
|
|
|
123
114
|
if (isServerRenderResult_1.isServerRenderHash(reactElementOrRouterResult)) {
|
|
124
115
|
throw new Error("You returned a server side type of react-router error: " + JSON.stringify(reactElementOrRouterResult) + "\nYou should return a React.Component always for the client side entry point.");
|
|
125
116
|
}
|
|
126
|
-
else if (shouldHydrate) {
|
|
127
|
-
reactHydrate_1.default(domNode, reactElementOrRouterResult);
|
|
128
|
-
}
|
|
129
117
|
else {
|
|
130
|
-
|
|
118
|
+
var rootOrElement = reactHydrateOrRender_1.default(domNode, reactElementOrRouterResult, shouldHydrate);
|
|
119
|
+
if (reactApis_1.supportsRootApi) {
|
|
120
|
+
context.roots.push(rootOrElement);
|
|
121
|
+
}
|
|
131
122
|
}
|
|
132
123
|
}
|
|
133
124
|
}
|
|
@@ -137,6 +128,12 @@ function render(el, railsContext) {
|
|
|
137
128
|
throw e;
|
|
138
129
|
}
|
|
139
130
|
}
|
|
131
|
+
function forEachReactOnRailsComponentRender(context, railsContext) {
|
|
132
|
+
var els = reactOnRailsHtmlElements();
|
|
133
|
+
for (var i = 0; i < els.length; i += 1) {
|
|
134
|
+
render(els[i], context, railsContext);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
140
137
|
function parseRailsContext() {
|
|
141
138
|
var el = document.getElementById('js-react-on-rails-context');
|
|
142
139
|
if (!el) {
|
|
@@ -145,7 +142,7 @@ function parseRailsContext() {
|
|
|
145
142
|
return null;
|
|
146
143
|
}
|
|
147
144
|
if (!el.textContent) {
|
|
148
|
-
throw new Error(
|
|
145
|
+
throw new Error('The HTML element with ID \'js-react-on-rails-context\' has no textContent');
|
|
149
146
|
}
|
|
150
147
|
return JSON.parse(el.textContent);
|
|
151
148
|
}
|
|
@@ -155,8 +152,12 @@ function reactOnRailsPageLoaded() {
|
|
|
155
152
|
// If no react on rails components
|
|
156
153
|
if (!railsContext)
|
|
157
154
|
return;
|
|
158
|
-
|
|
159
|
-
|
|
155
|
+
var context = findContext();
|
|
156
|
+
if (reactApis_1.supportsRootApi) {
|
|
157
|
+
context.roots = [];
|
|
158
|
+
}
|
|
159
|
+
forEachStore(context, railsContext);
|
|
160
|
+
forEachReactOnRailsComponentRender(context, railsContext);
|
|
160
161
|
}
|
|
161
162
|
exports.reactOnRailsPageLoaded = reactOnRailsPageLoaded;
|
|
162
163
|
function unmount(el) {
|
|
@@ -174,9 +175,21 @@ function unmount(el) {
|
|
|
174
175
|
}
|
|
175
176
|
function reactOnRailsPageUnloaded() {
|
|
176
177
|
debugTurbolinks('reactOnRailsPageUnloaded');
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
if (reactApis_1.supportsRootApi) {
|
|
179
|
+
var roots = findContext().roots;
|
|
180
|
+
// If no react on rails components
|
|
181
|
+
if (!roots)
|
|
182
|
+
return;
|
|
183
|
+
for (var _i = 0, roots_1 = roots; _i < roots_1.length; _i++) {
|
|
184
|
+
var root = roots_1[_i];
|
|
185
|
+
root.unmount();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
var els = reactOnRailsHtmlElements();
|
|
190
|
+
for (var i = 0; i < els.length; i += 1) {
|
|
191
|
+
unmount(els[i]);
|
|
192
|
+
}
|
|
180
193
|
}
|
|
181
194
|
}
|
|
182
195
|
function renderInit() {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const supportsRootApi: boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
var _a;
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.supportsRootApi = void 0;
|
|
8
|
+
var react_dom_1 = __importDefault(require("react-dom"));
|
|
9
|
+
var reactMajorVersion = ((_a = react_dom_1.default.version) === null || _a === void 0 ? void 0 : _a.split('.')[0]) || 16;
|
|
10
|
+
// TODO: once we require React 18, we can remove this and inline everything guarded by it.
|
|
11
|
+
// Not the default export because others may be added for future React versions.
|
|
12
|
+
// eslint-disable-next-line import/prefer-default-export
|
|
13
|
+
exports.supportsRootApi = reactMajorVersion >= 18;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { RenderReturnType } from './types';
|
|
3
|
+
declare type HydrateOrRenderType = (domNode: Element, reactElement: ReactElement) => RenderReturnType;
|
|
4
|
+
export declare const reactHydrate: HydrateOrRenderType;
|
|
5
|
+
export declare function reactRender(domNode: Element, reactElement: ReactElement): RenderReturnType;
|
|
6
|
+
export default function reactHydrateOrRender(domNode: Element, reactElement: ReactElement, hydrate: boolean): RenderReturnType;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.reactRender = exports.reactHydrate = void 0;
|
|
7
|
+
var react_dom_1 = __importDefault(require("react-dom"));
|
|
8
|
+
var reactApis_1 = require("./reactApis");
|
|
9
|
+
// TODO: once React dependency is updated to >= 18, we can remove this and just
|
|
10
|
+
// import ReactDOM from 'react-dom/client';
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
var reactDomClient;
|
|
13
|
+
if (reactApis_1.supportsRootApi) {
|
|
14
|
+
// This will never throw an exception, but it's the way to tell Webpack the dependency is optional
|
|
15
|
+
// https://github.com/webpack/webpack/issues/339#issuecomment-47739112
|
|
16
|
+
// Unfortunately, it only converts the error to a warning.
|
|
17
|
+
try {
|
|
18
|
+
// eslint-disable-next-line global-require,import/no-unresolved
|
|
19
|
+
reactDomClient = require('react-dom/client');
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
// We should never get here, but if we do, we'll just use the default ReactDOM
|
|
23
|
+
// and live with the warning.
|
|
24
|
+
reactDomClient = react_dom_1.default;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.reactHydrate = reactApis_1.supportsRootApi ?
|
|
28
|
+
reactDomClient.hydrateRoot :
|
|
29
|
+
function (domNode, reactElement) { return react_dom_1.default.hydrate(reactElement, domNode); };
|
|
30
|
+
function reactRender(domNode, reactElement) {
|
|
31
|
+
if (reactApis_1.supportsRootApi) {
|
|
32
|
+
var root = reactDomClient.createRoot(domNode);
|
|
33
|
+
root.render(reactElement);
|
|
34
|
+
return root;
|
|
35
|
+
}
|
|
36
|
+
// eslint-disable-next-line react/no-render-return-value
|
|
37
|
+
return react_dom_1.default.render(reactElement, domNode);
|
|
38
|
+
}
|
|
39
|
+
exports.reactRender = reactRender;
|
|
40
|
+
function reactHydrateOrRender(domNode, reactElement, hydrate) {
|
|
41
|
+
return hydrate ? exports.reactHydrate(domNode, reactElement) : reactRender(domNode, reactElement);
|
|
42
|
+
}
|
|
43
|
+
exports.default = reactHydrateOrRender;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReactElement, Component, FunctionComponent, ComponentClass } from 'react';
|
|
1
|
+
import type { ReactElement, ReactNode, Component, FunctionComponent, ComponentClass } from 'react';
|
|
2
2
|
declare type Store = any;
|
|
3
3
|
declare type ReactComponent = FunctionComponent | ComponentClass | string;
|
|
4
4
|
export interface RailsContext {
|
|
@@ -86,6 +86,11 @@ export interface RenderResult {
|
|
|
86
86
|
hasErrors: boolean;
|
|
87
87
|
renderingError?: RenderingError;
|
|
88
88
|
}
|
|
89
|
+
export interface Root {
|
|
90
|
+
render(children: ReactNode): void;
|
|
91
|
+
unmount(): void;
|
|
92
|
+
}
|
|
93
|
+
export declare type RenderReturnType = void | Element | Component | Root;
|
|
89
94
|
export interface ReactOnRails {
|
|
90
95
|
register(components: {
|
|
91
96
|
[id: string]: ReactComponentOrRenderFunction;
|
|
@@ -93,10 +98,11 @@ export interface ReactOnRails {
|
|
|
93
98
|
registerStore(stores: {
|
|
94
99
|
[id: string]: Store;
|
|
95
100
|
}): void;
|
|
96
|
-
getStore(name: string, throwIfMissing
|
|
101
|
+
getStore(name: string, throwIfMissing?: boolean): Store | undefined;
|
|
97
102
|
setOptions(newOptions: {
|
|
98
103
|
traceTurbolinks: boolean;
|
|
99
104
|
}): void;
|
|
105
|
+
reactHydrateOrRender(domNode: Element, reactElement: ReactElement, hydrate: boolean): RenderReturnType;
|
|
100
106
|
reactOnRailsPageLoaded(): void;
|
|
101
107
|
authenticityToken(): string | null;
|
|
102
108
|
authenticityHeaders(otherHeaders: {
|
|
@@ -106,7 +112,7 @@ export interface ReactOnRails {
|
|
|
106
112
|
getStoreGenerator(name: string): StoreGenerator;
|
|
107
113
|
setStore(name: string, store: Store): void;
|
|
108
114
|
clearHydratedStores(): void;
|
|
109
|
-
render(name: string, props: Record<string, string>, domNodeId: string, hydrate: boolean):
|
|
115
|
+
render(name: string, props: Record<string, string>, domNodeId: string, hydrate: boolean): RenderReturnType;
|
|
110
116
|
getComponent(name: string): RegisteredComponent;
|
|
111
117
|
serverRenderReactComponent(options: RenderParams): null | string | Promise<RenderResult>;
|
|
112
118
|
handleError(options: ErrorOptions): string | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-on-rails",
|
|
3
|
-
"version": "13.0
|
|
3
|
+
"version": "13.2.0",
|
|
4
4
|
"description": "react-on-rails JavaScript for react_on_rails Ruby gem",
|
|
5
5
|
"main": "node_package/lib/ReactOnRails.js",
|
|
6
6
|
"directories": {
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"@babel/preset-react": "^7.12.10",
|
|
16
16
|
"@babel/types": "^7.12.10",
|
|
17
17
|
"@types/jest": "^26.0.18",
|
|
18
|
-
"@types/node": "^14.14.11",
|
|
19
18
|
"@types/react": "^16.9.23",
|
|
20
19
|
"@types/react-dom": "^16.9.5",
|
|
21
20
|
"@types/turbolinks": "^5.2.0",
|
|
21
|
+
"@types/webpack-env": "^1.17.0",
|
|
22
22
|
"@typescript-eslint/eslint-plugin": "^4.10.0",
|
|
23
23
|
"@typescript-eslint/parser": "^4.10.0",
|
|
24
24
|
"babelify": "^10.0.0",
|