diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e6155a915..632ef9621f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,6 +22,10 @@ Changes since the last non-beta release.
#### Fixed
- Fixed a bug where the `load` event was not firing in Safari by postponing hydration to the next JavaScript task using `setTimeout(callback, 0)`. [PR 1729](https://github.com/shakacode/react_on_rails/pull/1729) by [Romex91](https://github.com/Romex91).
+- Generated client packs now import from `react-on-rails/client` instead of `react-on-rails`. [PR 1706](https://github.com/shakacode/react_on_rails/pull/1706) by [alexeyr-ci](https://github.com/alexeyr-ci).
+ - The "optimization opportunity" message when importing the server-side `react-on-rails` instead of `react-on-rails/client` in browsers is now a warning for two reasons:
+ - Make it more prominent
+ - Include a stack trace when clicked
### [14.2.0] - 2025-03-03
diff --git a/Gemfile.lock b/Gemfile.lock
index 85315a3126..f26f4062bf 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- react_on_rails (14.1.1)
+ react_on_rails (14.2.1)
addressable
connection_pool
execjs (~> 2.5)
diff --git a/docs/guides/how-to-use-different-files-for-client-and-server-rendering.md b/docs/guides/how-to-use-different-files-for-client-and-server-rendering.md
index 0e318c1c65..1ddb9fdd77 100644
--- a/docs/guides/how-to-use-different-files-for-client-and-server-rendering.md
+++ b/docs/guides/how-to-use-different-files-for-client-and-server-rendering.md
@@ -8,7 +8,7 @@ Many projects will have different entry points for client and server rendering.
Your Client Entry can look like this:
```js
-import ReactOnRails from 'react-on-rails';
+import ReactOnRails from 'react-on-rails/client';
import App from './ClientApp';
ReactOnRails.register({ App })
```
@@ -21,7 +21,7 @@ import App from './ServerApp';
ReactOnRails.register({ App })
```
-Note that the only difference is on the second line of each of these examples.
+Note that the only difference is in the imports.
## B. Two Options for Using Webpack Resolve Alias in the Webpack Config
Per [Webpack Docs](https://webpack.js.org/configuration/resolve/#resolve-alias).
diff --git a/docs/javascript/code-splitting.md b/docs/javascript/code-splitting.md
index 8eb2733f23..5b259b9642 100644
--- a/docs/javascript/code-splitting.md
+++ b/docs/javascript/code-splitting.md
@@ -37,7 +37,7 @@ Here's an example of how you might use this in practice:
#### clientRegistration.js
```js
-import ReactOnRails from 'node_package/lib/ReactOnRails';
+import ReactOnRails from 'react-on-rails/client';
import NavigationApp from './NavigationApp';
// Note that we're importing a different RouterApp than in serverRegistration.js
@@ -71,7 +71,7 @@ Note that you should not register a renderer on the server, since there won't be
#### RouterAppRenderer.jsx
```jsx
-import ReactOnRails from 'react-on-rails';
+import ReactOnRails from 'react-on-rails/client';
import React from 'react';
import ReactDOM from 'react-dom';
import Router from 'react-router/lib/Router';
diff --git a/lib/generators/react_on_rails/dev_tests_generator.rb b/lib/generators/react_on_rails/dev_tests_generator.rb
index 68cd97fab7..3a20a2b72e 100644
--- a/lib/generators/react_on_rails/dev_tests_generator.rb
+++ b/lib/generators/react_on_rails/dev_tests_generator.rb
@@ -47,14 +47,10 @@ def replace_prerender_if_server_rendering
def add_yarn_relative_install_script_in_package_json
package_json = File.join(destination_root, "package.json")
- contents = File.read(package_json)
- replacement_value = <<-STRING
- "scripts": {
- "postinstall": "yalc link react-on-rails",
- STRING
- new_client_package_json_contents = contents.gsub(/ {2}"scripts": {/,
- replacement_value)
- File.open(package_json, "w+") { |f| f.puts new_client_package_json_contents }
+ contents = JSON.parse(File.read(package_json))
+ contents["scripts"] ||= {}
+ contents["scripts"]["postinstall"] = "yalc link react-on-rails"
+ File.open(package_json, "w+") { |f| f.puts JSON.pretty_generate(contents) }
end
end
end
diff --git a/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt b/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt
index 379de1f4fa..d20e720f2d 100644
--- a/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt
+++ b/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt
@@ -1,4 +1,4 @@
-import ReactOnRails from 'react-on-rails';
+import ReactOnRails from 'react-on-rails/client';
import <%= config[:component_name] %> from '<%= config[:app_relative_path] %>';
diff --git a/lib/react_on_rails/packs_generator.rb b/lib/react_on_rails/packs_generator.rb
index 2db3d6b0c9..de149ecf1c 100644
--- a/lib/react_on_rails/packs_generator.rb
+++ b/lib/react_on_rails/packs_generator.rb
@@ -47,7 +47,7 @@ def create_pack(file_path)
def pack_file_contents(file_path)
registered_component_name = component_name(file_path)
<<~FILE_CONTENT
- import ReactOnRails from 'react-on-rails';
+ import ReactOnRails from 'react-on-rails/client';
import #{registered_component_name} from '#{relative_component_path_from_generated_pack(file_path)}';
ReactOnRails.register({#{registered_component_name}});
diff --git a/node_package/src/ReactOnRails.full.ts b/node_package/src/ReactOnRails.full.ts
index c80c8dd5be..aac25a44cf 100644
--- a/node_package/src/ReactOnRails.full.ts
+++ b/node_package/src/ReactOnRails.full.ts
@@ -9,7 +9,10 @@ import type {
import Client from './ReactOnRails.client';
if (typeof window !== 'undefined') {
- console.log('Optimization opportunity: "react-on-rails" includes ~14KB of server-rendering code. Browsers may not need it. See https://forum.shakacode.com/t/how-to-use-different-versions-of-a-file-for-client-and-server-rendering/1352 (Requires creating a free account)');
+ // warn to include a collapsed stack trace
+ console.warn(
+ 'Optimization opportunity: "react-on-rails" includes ~14KB of server-rendering code. Browsers may not need it. See https://forum.shakacode.com/t/how-to-use-different-versions-of-a-file-for-client-and-server-rendering/1352 (Requires creating a free account). Click this for the stack trace.',
+ );
}
/**
diff --git a/script/convert b/script/convert
index a18548f808..334635e0fc 100755
--- a/script/convert
+++ b/script/convert
@@ -13,13 +13,13 @@ new_config = File.expand_path("../spec/dummy/config/webpacker.yml", __dir__)
File.rename(old_config, new_config)
-gsub_file_content("../Gemfile.development_dependencies", 'gem "shakapacker", "8.0.0"', 'gem "shakapacker", "6.6.0"')
+gsub_file_content("../Gemfile.development_dependencies", /gem "shakapacker", "[^"]*"/, 'gem "shakapacker", "6.6.0"')
# The below packages don't work on the oldest supported Node version and aren't needed there anyway
gsub_file_content("../package.json", /"knip": "[^"]*",/, "")
gsub_file_content("../package.json", %r{"@arethetypeswrong/cli": "[^"]*",}, "")
-gsub_file_content("../spec/dummy/package.json", '"shakapacker": "8.0.0",', '"shakapacker": "6.6.0",')
+gsub_file_content("../spec/dummy/package.json", /"shakapacker": "[^"]*",/, '"shakapacker": "6.6.0",')
gsub_file_content("../spec/dummy/config/webpack/commonWebpackConfig.js", /generateWebpackConfig(\(\))?/,
"webpackConfig")
diff --git a/spec/dummy/app/views/pages/client_side_hello_world.html.erb b/spec/dummy/app/views/pages/client_side_hello_world.html.erb
index 596ff1d5b4..06e291d79b 100644
--- a/spec/dummy/app/views/pages/client_side_hello_world.html.erb
+++ b/spec/dummy/app/views/pages/client_side_hello_world.html.erb
@@ -22,7 +22,7 @@
import HelloWorld from '../components/HelloWorld';
- import ReactOnRails from 'react-on-rails';
+ import ReactOnRails from 'react-on-rails/client';
ReactOnRails.register({ HelloWorld });
diff --git a/spec/dummy/app/views/pages/server_side_hello_world.html.erb b/spec/dummy/app/views/pages/server_side_hello_world.html.erb
index f77853e041..8dcb1ea96e 100644
--- a/spec/dummy/app/views/pages/server_side_hello_world.html.erb
+++ b/spec/dummy/app/views/pages/server_side_hello_world.html.erb
@@ -48,7 +48,7 @@
import HelloWorld from '../components/HelloWorld';
- import ReactOnRails from 'react-on-rails';
+ import ReactOnRails from 'react-on-rails/client';
ReactOnRails.register({ HelloWorld });
diff --git a/spec/dummy/app/views/pages/server_side_redux_app.html.erb b/spec/dummy/app/views/pages/server_side_redux_app.html.erb
index d9c96b394d..b11ad675f8 100644
--- a/spec/dummy/app/views/pages/server_side_redux_app.html.erb
+++ b/spec/dummy/app/views/pages/server_side_redux_app.html.erb
@@ -37,7 +37,7 @@
import ReduxApp from './ClientReduxApp';
- import ReactOnRails from 'react-on-rails';
+ import ReactOnRails from 'react-on-rails/client';
ReactOnRails.register({ ReduxApp });
diff --git a/spec/dummy/app/views/pages/server_side_redux_app_cached.html.erb b/spec/dummy/app/views/pages/server_side_redux_app_cached.html.erb
index 494610d561..dec8fb17db 100644
--- a/spec/dummy/app/views/pages/server_side_redux_app_cached.html.erb
+++ b/spec/dummy/app/views/pages/server_side_redux_app_cached.html.erb
@@ -43,7 +43,7 @@
import ReduxApp from './ClientReduxApp';
- import ReactOnRails from 'react-on-rails';
+ import ReactOnRails from 'react-on-rails/client';
ReactOnRails.register({ ReduxApp });
diff --git a/spec/dummy/app/views/pages/xhr_refresh.html.erb b/spec/dummy/app/views/pages/xhr_refresh.html.erb
index f46cf080cc..fdad0ee637 100644
--- a/spec/dummy/app/views/pages/xhr_refresh.html.erb
+++ b/spec/dummy/app/views/pages/xhr_refresh.html.erb
@@ -32,7 +32,7 @@
import HellowWorldRehydratable from '../components/HellowWorldRehydratable';
- import ReactOnRails from 'react-on-rails';
+ import ReactOnRails from 'react-on-rails/client';
ReactOnRails.register({ HellowWorldRehydratable });
diff --git a/spec/dummy/client/app/startup/HelloWorldRehydratable.jsx b/spec/dummy/client/app/startup/HelloWorldRehydratable.jsx
index e433d309ac..8ebe2f9e3b 100644
--- a/spec/dummy/client/app/startup/HelloWorldRehydratable.jsx
+++ b/spec/dummy/client/app/startup/HelloWorldRehydratable.jsx
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
-import ReactOnRails from 'react-on-rails';
+import ReactOnRails from 'react-on-rails/client';
import RailsContext from '../components/RailsContext';
class HelloWorldRehydratable extends React.Component {
diff --git a/spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx b/spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx
index c278dcd23e..1b1acdb811 100644
--- a/spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx
+++ b/spec/dummy/client/app/startup/ReduxSharedStoreApp.client.jsx
@@ -1,9 +1,9 @@
-// Top level component for client side.
-// Compare this to the ./ServerApp.jsx file which is used for server side rendering.
+// Top level component for the client side.
+// Compare this to the ./ReduxSharedStoreApp.server.jsx file which is used for server side rendering.
import React from 'react';
import { Provider } from 'react-redux';
-import ReactOnRails from 'react-on-rails';
+import ReactOnRails from 'react-on-rails/client';
import ReactDOMClient from 'react-dom/client';
import HelloWorldContainer from '../components/HelloWorldContainer';
diff --git a/spec/dummy/client/app/startup/ReduxSharedStoreApp.server.jsx b/spec/dummy/client/app/startup/ReduxSharedStoreApp.server.jsx
index 1f2d3b11c6..5982ab4415 100644
--- a/spec/dummy/client/app/startup/ReduxSharedStoreApp.server.jsx
+++ b/spec/dummy/client/app/startup/ReduxSharedStoreApp.server.jsx
@@ -1,5 +1,5 @@
-// Top level component for serer side.
-// Compare this to the ./ClientReduxSharedStoreApp.jsx file which is used for client side rendering.
+// Top level component for the server side.
+// Compare this to the ./ReduxSharedStoreApp.client.jsx file which is used for client side rendering.
import React from 'react';
import ReactOnRails from 'react-on-rails';
diff --git a/spec/dummy/spec/packs_generator_spec.rb b/spec/dummy/spec/packs_generator_spec.rb
index f7988b3370..34f4d98b0d 100644
--- a/spec/dummy/spec/packs_generator_spec.rb
+++ b/spec/dummy/spec/packs_generator_spec.rb
@@ -195,6 +195,7 @@ module ReactOnRails
it "generated pack for ComponentWithClientOnly uses client file for pack" do
pack_content = File.read(component_pack)
+ expect(pack_content).to include("react-on-rails/client")
expect(pack_content).to include("#{component_name}.client.jsx")
expect(pack_content).not_to include("#{component_name}.jsx")
expect(pack_content).not_to include("#{component_name}.server.jsx")
@@ -203,6 +204,7 @@ module ReactOnRails
it "generated server bundle do not have ComponentWithClientOnly registered" do
generated_server_bundle_content = File.read(generated_server_bundle_file_path)
+ expect(generated_server_bundle_content).not_to include("react-on-rails/client")
expect(generated_server_bundle_content).not_to include("#{component_name}.jsx")
expect(generated_server_bundle_content).not_to include("#{component_name}.client.jsx")
expect(generated_server_bundle_content).not_to include("#{component_name}.server.jsx")