diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml
index 988cb8083a..1199051de2 100644
--- a/.github/workflows/examples.yml
+++ b/.github/workflows/examples.yml
@@ -130,7 +130,7 @@ jobs:
echo "Node version: "; node -v
echo "Yarn version: "; yarn --version
echo "Bundler version: "; bundle --version
- - name: run conversion script to support shakapacker v6
+ - name: Run conversion script for older Node compatibility
if: matrix.dependency-level == 'minimum'
run: script/convert
- name: Save root ruby gems to cache
@@ -172,8 +172,12 @@ jobs:
- name: Set packer version environment variable
run: |
echo "CI_DEPENDENCY_LEVEL=${{ matrix.dependency-level }}" >> $GITHUB_ENV
- - name: Main CI
- run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples
+ - name: Main CI - Latest version examples
+ if: matrix.dependency-level == 'latest'
+ run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples_latest
+ - name: Main CI - Minimum version examples
+ if: matrix.dependency-level == 'minimum'
+ run: cd react_on_rails && bundle exec rake run_rspec:shakapacker_examples_minimum
- name: Store test results
uses: actions/upload-artifact@v4
with:
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 470bba70c8..ef0e85d076 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -132,7 +132,7 @@ jobs:
echo "Node version: "; node -v
echo "Yarn version: "; yarn --version
echo "Bundler version: "; bundle --version
- - name: run conversion script to support shakapacker v6
+ - name: Run conversion script for older Node compatibility
if: matrix.dependency-level == 'minimum'
run: script/convert
- name: Install Node modules with Yarn for renderer package
@@ -211,7 +211,7 @@ jobs:
echo "Node version: "; node -v
echo "Yarn version: "; yarn --version
echo "Bundler version: "; bundle --version
- - name: run conversion script to support shakapacker v6
+ - name: Run conversion script for older Node compatibility
if: matrix.dependency-level == 'minimum'
run: script/convert
- name: Save root ruby gems to cache
diff --git a/package.json b/package.json
index b73cf95234..9585ab1e4e 100644
--- a/package.json
+++ b/package.json
@@ -55,8 +55,8 @@
"prettier": "^3.5.2",
"prop-types": "^15.8.1",
"publint": "^0.3.4",
- "react": "18.0.0",
- "react-dom": "18.0.0",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
"react-on-rails-rsc": "19.0.2",
"redux": "^4.2.1",
"stylelint": "^16.14.0",
diff --git a/react_on_rails/rakelib/example_type.rb b/react_on_rails/rakelib/example_type.rb
index 800889884a..33de6f8a86 100644
--- a/react_on_rails/rakelib/example_type.rb
+++ b/react_on_rails/rakelib/example_type.rb
@@ -13,12 +13,22 @@ def self.all
@all ||= { shakapacker_examples: [] }
end
- attr_reader :packer_type, :name, :generator_options
+ # Minimum supported versions for compatibility testing
+ MINIMUM_REACT_VERSION = "18.0.0"
+ MINIMUM_SHAKAPACKER_VERSION = "8.2.0"
- def initialize(packer_type: nil, name: nil, generator_options: nil)
+ attr_reader :packer_type, :name, :generator_options, :minimum_versions
+
+ # Ruby convention: predicate method with ? suffix for boolean checks
+ def minimum_versions?
+ minimum_versions
+ end
+
+ def initialize(packer_type: nil, name: nil, generator_options: nil, minimum_versions: false)
@packer_type = packer_type
@name = name
@generator_options = generator_options
+ @minimum_versions = minimum_versions
self.class.all[packer_type.to_sym] << self
end
diff --git a/react_on_rails/rakelib/examples_config.yml b/react_on_rails/rakelib/examples_config.yml
index 731c9d9725..ec6a11b3cf 100644
--- a/react_on_rails/rakelib/examples_config.yml
+++ b/react_on_rails/rakelib/examples_config.yml
@@ -7,3 +7,10 @@ example_type_data:
generator_options: --redux
- name: redux-server-rendering
generator_options: --redux --example-server-rendering
+ # Minimum version compatibility tests - tests React 18 and Shakapacker 8.2.0
+ - name: basic-minimum
+ generator_options: ''
+ minimum_versions: true
+ - name: basic-server-rendering-minimum
+ generator_options: --example-server-rendering
+ minimum_versions: true
diff --git a/react_on_rails/rakelib/run_rspec.rake b/react_on_rails/rakelib/run_rspec.rake
index 88004f2073..5f45682284 100644
--- a/react_on_rails/rakelib/run_rspec.rake
+++ b/react_on_rails/rakelib/run_rspec.rake
@@ -90,6 +90,25 @@ namespace :run_rspec do
ExampleType.all[:shakapacker_examples].each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
end
+ # Helper methods for filtering examples
+ def latest_examples
+ ExampleType.all[:shakapacker_examples].reject(&:minimum_versions?)
+ end
+
+ def minimum_examples
+ ExampleType.all[:shakapacker_examples].select(&:minimum_versions?)
+ end
+
+ desc "Runs Rspec for latest version example apps only (excludes minimum version tests)"
+ task shakapacker_examples_latest: latest_examples.map(&:gen_task_name) do
+ latest_examples.each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
+ end
+
+ desc "Runs Rspec for minimum version example apps only (React 18, Shakapacker 8.2.0)"
+ task shakapacker_examples_minimum: minimum_examples.map(&:gen_task_name) do
+ minimum_examples.each { |example_type| Rake::Task[example_type.rspec_task_name].invoke }
+ end
+
Coveralls::RakeTask.new if ENV["USE_COVERALLS"] == "TRUE"
desc "run all tests no examples"
diff --git a/react_on_rails/rakelib/shakapacker_examples.rake b/react_on_rails/rakelib/shakapacker_examples.rake
index 5f5f1bb864..3d121e0a1e 100644
--- a/react_on_rails/rakelib/shakapacker_examples.rake
+++ b/react_on_rails/rakelib/shakapacker_examples.rake
@@ -8,6 +8,7 @@
require "yaml"
require "rails/version"
require "pathname"
+require "json"
require_relative "example_type"
require_relative "task_helpers"
@@ -15,8 +16,64 @@ require_relative "task_helpers"
namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
include ReactOnRails::TaskHelpers
+ # Updates package.json and Gemfile to use minimum supported versions for compatibility testing
+ # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
+ def apply_minimum_versions(dir)
+ # Update package.json
+ package_json_path = File.join(dir, "package.json")
+ if File.exist?(package_json_path)
+ begin
+ package_json = JSON.parse(File.read(package_json_path))
+ rescue JSON::ParserError => e
+ puts " ERROR: Failed to parse package.json in #{dir}: #{e.message}"
+ raise
+ end
+
+ deps = package_json["dependencies"]
+ dev_deps = package_json["devDependencies"]
+
+ # Update React versions to minimum supported
+ if deps
+ deps["react"] = ExampleType::MINIMUM_REACT_VERSION
+ deps["react-dom"] = ExampleType::MINIMUM_REACT_VERSION
+ # Shakapacker 8.2.0 requires webpack-assets-manifest ^5.x
+ deps["webpack-assets-manifest"] = "^5.0.6" if deps.key?("webpack-assets-manifest")
+ end
+
+ # Shakapacker 8.2.0 requires webpack-assets-manifest ^5.x (check devDependencies too)
+ dev_deps["webpack-assets-manifest"] = "^5.0.6" if dev_deps&.key?("webpack-assets-manifest")
+
+ # Update Shakapacker to minimum supported version in package.json
+ if dev_deps&.key?("shakapacker")
+ dev_deps["shakapacker"] = ExampleType::MINIMUM_SHAKAPACKER_VERSION
+ elsif deps&.key?("shakapacker")
+ deps["shakapacker"] = ExampleType::MINIMUM_SHAKAPACKER_VERSION
+ end
+
+ File.write(package_json_path, "#{JSON.pretty_generate(package_json)}\n")
+ end
+
+ # Update Gemfile to pin shakapacker to minimum version
+ # (must match the npm package version exactly)
+ gemfile_path = File.join(dir, "Gemfile")
+ if File.exist?(gemfile_path)
+ gemfile_content = File.read(gemfile_path)
+ # Replace any shakapacker gem line with exact version pin
+ gemfile_content = gemfile_content.gsub(
+ /gem ['"]shakapacker['"].*$/,
+ "gem 'shakapacker', '#{ExampleType::MINIMUM_SHAKAPACKER_VERSION}'"
+ )
+ File.write(gemfile_path, gemfile_content)
+ end
+
+ puts " Updated package.json with minimum versions:"
+ puts " React: #{ExampleType::MINIMUM_REACT_VERSION}"
+ puts " Shakapacker: #{ExampleType::MINIMUM_SHAKAPACKER_VERSION}"
+ end
+ # rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
+
# Define tasks for each example type
- ExampleType.all[:shakapacker_examples].each do |example_type|
+ ExampleType.all[:shakapacker_examples].each do |example_type| # rubocop:disable Metrics/BlockLength
relative_gem_root = Pathname(gem_root).relative_path_from(Pathname(example_type.dir))
# CLOBBER
desc "Clobbers (deletes) #{example_type.name_pretty}"
@@ -46,10 +103,28 @@ namespace :shakapacker_examples do # rubocop:disable Metrics/BlockLength
"REACT_ON_RAILS_SKIP_VALIDATION=true #{cmd}"
end
sh_in_dir(example_type.dir, generator_commands)
+
+ # Apply minimum versions for compatibility testing examples
+ if example_type.minimum_versions
+ apply_minimum_versions(example_type.dir)
+ # Re-run bundle install since Gemfile was updated with pinned shakapacker version
+ bundle_install_in(example_type.dir)
+ end
+
sh_in_dir(example_type.dir, "npm install")
# Generate the component packs after running the generator to ensure all
- # auto-bundled components have corresponding pack files created
- sh_in_dir(example_type.dir, "bundle exec rake react_on_rails:generate_packs")
+ # auto-bundled components have corresponding pack files created.
+ if example_type.minimum_versions
+ # For minimum version examples, use BUNDLE_GEMFILE to ensure bundler uses
+ # the generated app's Gemfile and not any parent workspace's bundle,
+ # which could have different gem versions. Also use BUNDLE_FROZEN=false
+ # to allow the lockfile to be updated.
+ gemfile_path = File.join(example_type.dir, "Gemfile")
+ sh_in_dir(example_type.dir,
+ "BUNDLE_GEMFILE=#{gemfile_path} BUNDLE_FROZEN=false bundle exec rake react_on_rails:generate_packs")
+ else
+ sh_in_dir(example_type.dir, "bundle exec rake react_on_rails:generate_packs")
+ end
end
end
diff --git a/react_on_rails/spec/dummy/Gemfile.lock b/react_on_rails/spec/dummy/Gemfile.lock
index eb919c4013..ce0a77dffb 100644
--- a/react_on_rails/spec/dummy/Gemfile.lock
+++ b/react_on_rails/spec/dummy/Gemfile.lock
@@ -345,7 +345,7 @@ GEM
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
semantic_range (3.1.0)
- shakapacker (9.3.0)
+ shakapacker (9.4.0)
activesupport (>= 5.2)
package_json
rack-proxy (>= 0.6.1)
@@ -461,7 +461,7 @@ DEPENDENCIES
sass-rails (~> 6.0)
sdoc
selenium-webdriver (= 4.9.0)
- shakapacker (= 9.3.0)
+ shakapacker (= 9.4.0)
spring (~> 4.0)
sprockets (~> 4.0)
sqlite3 (~> 1.6)
diff --git a/react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx b/react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
index b7ab770286..a96f624be7 100644
--- a/react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
+++ b/react_on_rails/spec/dummy/client/app-react16/startup/ReduxApp.client.jsx
@@ -5,7 +5,7 @@
import React from 'react';
import { combineReducers, applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
-import thunkMiddleware from 'redux-thunk';
+import { thunk } from 'redux-thunk';
import ReactDOM from 'react-dom';
import reducers from '../../app/reducers/reducersIndex';
@@ -29,7 +29,7 @@ export default (props, railsContext, domNodeId) => {
// This is where we'll put in the middleware for the async function. Placeholder.
// store will have helloWorldData as a top level property
- const store = createStore(combinedReducer, combinedProps, applyMiddleware(thunkMiddleware));
+ const store = createStore(combinedReducer, combinedProps, applyMiddleware(thunk));
// renderApp is a function required for hot reloading. see
// https://github.com/retroalgic/react-on-rails-hot-minimal/blob/master/client/src/entry.js
diff --git a/react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx b/react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
index bba49492df..ca82611935 100644
--- a/react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
+++ b/react_on_rails/spec/dummy/client/app/components/ReactHelmet.jsx
@@ -1,7 +1,10 @@
import React from 'react';
-import { Helmet } from 'react-helmet';
+import { Helmet } from '@dr.pogodin/react-helmet';
import HelloWorld from '../startup/HelloWorld';
+// Note: This component expects to be wrapped in a HelmetProvider by its parent.
+// For client-side rendering, wrap in HelmetProvider at the app root.
+// For server-side rendering, the server entry point provides the HelmetProvider.
const ReactHelmet = (props) => (
diff --git a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx
index 2c5f342d92..4dd6c26570 100644
--- a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx
+++ b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.client.jsx
@@ -1,11 +1,17 @@
// Top level component for simple client side only rendering
import React from 'react';
+import { HelmetProvider } from '@dr.pogodin/react-helmet';
import ReactHelmet from '../components/ReactHelmet';
// This works fine, React functional component:
// export default (props) => ;
-export default (props) => ;
+// HelmetProvider is required by @dr.pogodin/react-helmet for both client and server rendering
+export default (props) => (
+
+
+
+);
// Note, the server side has to be a Render-Function
diff --git a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
index f7c77e8a73..6546457bca 100644
--- a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
+++ b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetApp.server.jsx
@@ -1,8 +1,8 @@
// Top level component for simple client side only rendering
import React from 'react';
import { renderToString } from 'react-dom/server';
-import { Helmet } from 'react-helmet';
-import ReactHelmet from '../components/ReactHelmet';
+import { Helmet, HelmetProvider } from '@dr.pogodin/react-helmet';
+import HelloWorld from './HelloWorld';
/*
* Export a function that takes the props and returns an object with { renderedHtml }
@@ -16,12 +16,27 @@ import ReactHelmet from '../components/ReactHelmet';
* the function could get the property of `.renderFunction = true` added to it.
*/
export default (props, _railsContext) => {
- const componentHtml = renderToString();
- const helmet = Helmet.renderStatic();
+ // For server-side rendering with @dr.pogodin/react-helmet, we pass a context object
+ // to HelmetProvider to capture the helmet data per-request (thread-safe)
+ const helmetContext = {};
+
+ const componentHtml = renderToString(
+
+
+
+ Custom page title
+
+ Props: {JSON.stringify(props)}
+
+
+ ,
+ );
+
+ const { helmet } = helmetContext;
const renderedHtml = {
componentHtml,
- title: helmet.title.toString(),
+ title: helmet ? helmet.title.toString() : '',
};
// Note that this function returns an Object for server rendering.
diff --git a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
index 2c5f342d92..4dd6c26570 100644
--- a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
+++ b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.client.jsx
@@ -1,11 +1,17 @@
// Top level component for simple client side only rendering
import React from 'react';
+import { HelmetProvider } from '@dr.pogodin/react-helmet';
import ReactHelmet from '../components/ReactHelmet';
// This works fine, React functional component:
// export default (props) => ;
-export default (props) => ;
+// HelmetProvider is required by @dr.pogodin/react-helmet for both client and server rendering
+export default (props) => (
+
+
+
+);
// Note, the server side has to be a Render-Function
diff --git a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
index d1c72af50d..f0d68d3e18 100644
--- a/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
+++ b/react_on_rails/spec/dummy/client/app/startup/ReactHelmetAppBroken.server.jsx
@@ -3,7 +3,7 @@
// function. The point of this is to provide a good error.
import React from 'react';
import { renderToString } from 'react-dom/server';
-import { Helmet } from 'react-helmet';
+import { HelmetProvider } from '@dr.pogodin/react-helmet';
import ReactHelmet from '../components/ReactHelmet';
/*
@@ -18,12 +18,17 @@ import ReactHelmet from '../components/ReactHelmet';
* Alternately, the function could get the property of `.renderFunction = true` added to it.
*/
export default (props) => {
- const componentHtml = renderToString();
- const helmet = Helmet.renderStatic();
+ const helmetContext = {};
+ const componentHtml = renderToString(
+
+
+ ,
+ );
+ const { helmet } = helmetContext;
const renderedHtml = {
componentHtml,
- title: helmet.title.toString(),
+ title: helmet ? helmet.title.toString() : '',
};
return { renderedHtml };
};
diff --git a/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx b/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx
index 3e8ddc211b..cfe9e24a93 100644
--- a/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx
+++ b/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx
@@ -5,7 +5,7 @@
import React from 'react';
import { combineReducers, applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
-import thunkMiddleware from 'redux-thunk';
+import { thunk } from 'redux-thunk';
import ReactDOMClient from 'react-dom/client';
import reducers from '../reducers/reducersIndex';
@@ -34,7 +34,7 @@ export default (props, railsContext, domNodeId) => {
// This is where we'll put in the middleware for the async function. Placeholder.
// store will have helloWorldData as a top level property
- const store = createStore(combinedReducer, combinedProps, applyMiddleware(thunkMiddleware));
+ const store = createStore(combinedReducer, combinedProps, applyMiddleware(thunk));
// renderApp is a function required for hot reloading. see
// https://github.com/retroalgic/react-on-rails-hot-minimal/blob/master/client/src/entry.js
diff --git a/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx b/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
index bdcc317962..a26b2969f0 100644
--- a/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
+++ b/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx
@@ -6,7 +6,7 @@
import React from 'react';
import { combineReducers, applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
-import middleware from 'redux-thunk';
+import { thunk } from 'redux-thunk';
// Uses the index
import reducers from '../reducers/reducersIndex';
@@ -28,7 +28,7 @@ export default (props, railsContext) => {
// This is where we'll put in the middleware for the async function. Placeholder.
// store will have helloWorldData as a top level property
- const store = applyMiddleware(middleware)(createStore)(combinedReducer, combinedProps);
+ const store = applyMiddleware(thunk)(createStore)(combinedReducer, combinedProps);
// Provider uses the this.props.children, so we're not typical React syntax.
// This allows redux to add additional props to the HelloWorldContainer.
diff --git a/react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx b/react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
index 33dcc680ed..3d463ff891 100644
--- a/react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
+++ b/react_on_rails/spec/dummy/client/app/stores/SharedReduxStore.jsx
@@ -1,5 +1,5 @@
import { combineReducers, applyMiddleware, createStore } from 'redux';
-import middleware from 'redux-thunk';
+import { thunk } from 'redux-thunk';
import reducers from '../reducers/reducersIndex';
@@ -12,5 +12,5 @@ export default (props, railsContext) => {
delete props.prerender;
const combinedReducer = combineReducers(reducers);
const newProps = { ...props, railsContext };
- return applyMiddleware(middleware)(createStore)(combinedReducer, newProps);
+ return applyMiddleware(thunk)(createStore)(combinedReducer, newProps);
};
diff --git a/react_on_rails/spec/dummy/package.json b/react_on_rails/spec/dummy/package.json
index 752ccef475..b3602e226f 100644
--- a/react_on_rails/spec/dummy/package.json
+++ b/react_on_rails/spec/dummy/package.json
@@ -18,14 +18,14 @@
"node-libs-browser": "^2.2.1",
"null-loader": "^4.0.0",
"prop-types": "^15.7.2",
- "react": "18.0.0",
- "react-dom": "18.0.0",
- "react-helmet": "^6.1.0",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "@dr.pogodin/react-helmet": "^3.0.4",
"react-on-rails": "link:.yalc/react-on-rails",
- "react-redux": "^8.0.2",
+ "react-redux": "^9.2.0",
"react-router-dom": "^6.0.0",
- "redux": "^4.0.1",
- "redux-thunk": "^2.2.0",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
"regenerator-runtime": "^0.13.4"
},
"devDependencies": {
@@ -38,7 +38,6 @@
"@rescript/react": "^0.13.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
- "@types/react-helmet": "^6.1.5",
"babel-loader": "8.2.4",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"compression-webpack-plugin": "9",
diff --git a/react_on_rails/spec/dummy/yarn.lock b/react_on_rails/spec/dummy/yarn.lock
index b7fc70ea04..281c1ff57c 100644
--- a/react_on_rails/spec/dummy/yarn.lock
+++ b/react_on_rails/spec/dummy/yarn.lock
@@ -1008,13 +1008,18 @@
"@babel/plugin-transform-react-jsx-source" "^7.10.4"
"@babel/plugin-transform-react-pure-annotations" "^7.10.4"
-"@babel/runtime@7.17.9", "@babel/runtime@^7.12.1", "@babel/runtime@^7.8.4":
+"@babel/runtime@7.17.9", "@babel/runtime@^7.8.4":
version "7.17.9"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.28.4":
+ version "7.28.4"
+ resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326"
+ integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==
+
"@babel/template@^7.16.7", "@babel/template@^7.18.10", "@babel/template@^7.26.9", "@babel/template@^7.27.0", "@babel/template@^7.3.3":
version "7.27.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.0.tgz#b253e5406cc1df1c57dcd18f11760c2dbf40c0b4"
@@ -1055,6 +1060,13 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f"
integrity sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==
+"@dr.pogodin/react-helmet@^3.0.4":
+ version "3.0.4"
+ resolved "https://registry.npmjs.org/@dr.pogodin/react-helmet/-/react-helmet-3.0.4.tgz#d11d763fe07a2a11329438c2f892cd15c30239a9"
+ integrity sha512-TesfNpzO12qcbyqKyWGDIYTdwVxD3pJv75rE/zhKUq/k9yxeP0BpOdHQ5cc1zA3j/GyY7CuIZjAUXmsxqI1/yw==
+ dependencies:
+ "@babel/runtime" "^7.28.4"
+
"@hotwired/turbo-rails@^8.0.4":
version "8.0.5"
resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-8.0.5.tgz#18c2f0e4f7f952307650308590edf5eb9544b0d3"
@@ -1479,14 +1491,6 @@
dependencies:
"@types/node" "*"
-"@types/hoist-non-react-statics@^3.3.1":
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
- integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
- dependencies:
- "@types/react" "*"
- hoist-non-react-statics "^3.3.0"
-
"@types/http-proxy@^1.17.8":
version "1.17.9"
resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.9.tgz#7f0e7931343761efde1e2bf48c40f02f3f75705a"
@@ -1543,14 +1547,7 @@
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.3.tgz#0804dfd279a165d5a0ad8b53a5b9e65f338050a4"
integrity sha512-0Knk+HJiMP/qOZgMyNFamlIjw9OFCsyC2ZbigmEEyXXixgre6IQpm/4V+r3qH4GC1JPvRJKInw+on2rV6YZLeA==
-"@types/react-helmet@^6.1.5":
- version "6.1.5"
- resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-6.1.5.tgz#35f89a6b1646ee2bc342a33a9a6c8777933f9083"
- integrity sha512-/ICuy7OHZxR0YCAZLNg9r7I9aijWUWvxaPR6uTuyxe8tAj5RL4Sw1+R6NhXUtOsarkGYPmaHdBDvuXh2DIN/uA==
- dependencies:
- "@types/react" "*"
-
-"@types/react@*", "@types/react@^19.0.0":
+"@types/react@^19.0.0":
version "19.0.7"
resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.7.tgz#c451968b999d1cb2d9207dc5ff56496164cf511d"
integrity sha512-MoFsEJKkAtZCrC1r6CM8U22GzhG7u2Wir8ons/aCKH6MBdD1ibV24zOSSkdZVUKqN5i396zG5VKLYZ3yaUZdLA==
@@ -1589,10 +1586,10 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
-"@types/use-sync-external-store@^0.0.3":
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
- integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+"@types/use-sync-external-store@^0.0.6":
+ version "0.0.6"
+ resolved "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc"
+ integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==
"@types/ws@^8.5.1":
version "8.5.4"
@@ -3474,13 +3471,6 @@ hmac-drbg@^1.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
-hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
- integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
- dependencies:
- react-is "^16.7.0"
-
hpack.js@^2.1.6:
version "2.1.6"
resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
@@ -4425,7 +4415,7 @@ lodash@^4.17.19, lodash@^4.17.4:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
-loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -5198,30 +5188,14 @@ raw-body@2.5.1:
iconv-lite "0.4.24"
unpipe "1.0.0"
-react-dom@18.0.0:
- version "18.0.0"
- resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0.tgz#26b88534f8f1dbb80853e1eabe752f24100d8023"
- integrity sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==
+react-dom@^19.0.0:
+ version "19.2.0"
+ resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz#00ed1e959c365e9a9d48f8918377465466ec3af8"
+ integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==
dependencies:
- loose-envify "^1.1.0"
- scheduler "^0.21.0"
-
-react-fast-compare@^3.1.1:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
- integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
+ scheduler "^0.27.0"
-react-helmet@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
- integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==
- dependencies:
- object-assign "^4.1.1"
- prop-types "^15.7.2"
- react-fast-compare "^3.1.1"
- react-side-effect "^2.1.0"
-
-react-is@^16.7.0, react-is@^16.8.1:
+react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -5235,17 +5209,13 @@ react-is@^18.0.0:
version "0.0.0"
uid ""
-react-redux@^8.0.2:
- version "8.0.2"
- resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.0.2.tgz#bc2a304bb21e79c6808e3e47c50fe1caf62f7aad"
- integrity sha512-nBwiscMw3NoP59NFCXFf02f8xdo+vSHT/uZ1ldDwF7XaTpzm+Phk97VT4urYBl5TYAPNVaFm12UHAEyzkpNzRA==
+react-redux@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5"
+ integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==
dependencies:
- "@babel/runtime" "^7.12.1"
- "@types/hoist-non-react-statics" "^3.3.1"
- "@types/use-sync-external-store" "^0.0.3"
- hoist-non-react-statics "^3.3.2"
- react-is "^18.0.0"
- use-sync-external-store "^1.0.0"
+ "@types/use-sync-external-store" "^0.0.6"
+ use-sync-external-store "^1.4.0"
react-refresh@^0.11.0:
version "0.11.0"
@@ -5267,17 +5237,10 @@ react-router@6.30.1:
dependencies:
"@remix-run/router" "1.23.0"
-react-side-effect@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.0.tgz#1ce4a8b4445168c487ed24dab886421f74d380d3"
- integrity sha512-IgmcegOSi5SNX+2Snh1vqmF0Vg/CbkycU9XZbOHJlZ6kMzTmi3yc254oB1WCkgA7OQtIAoLmcSFuHTc/tlcqXg==
-
-react@18.0.0:
- version "18.0.0"
- resolved "https://registry.npmjs.org/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96"
- integrity sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==
- dependencies:
- loose-envify "^1.1.0"
+react@^19.0.0:
+ version "19.2.0"
+ resolved "https://registry.npmjs.org/react/-/react-19.2.0.tgz#d33dd1721698f4376ae57a54098cb47fc75d93a5"
+ integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==
readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.3, readable-stream@^2.3.6:
version "2.3.7"
@@ -5324,18 +5287,15 @@ rechoir@^0.7.0:
dependencies:
resolve "^1.9.0"
-redux-thunk@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
- integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
+redux-thunk@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3"
+ integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
-redux@^4.0.1:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
- integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
- dependencies:
- loose-envify "^1.4.0"
- symbol-observable "^1.2.0"
+redux@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b"
+ integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
regenerate-unicode-properties@^9.0.0:
version "9.0.0"
@@ -5535,12 +5495,10 @@ sass@^1.43.4:
dependencies:
chokidar ">=3.0.0 <4.0.0"
-scheduler@^0.21.0:
- version "0.21.0"
- resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz#6fd2532ff5a6d877b6edb12f00d8ab7e8f308820"
- integrity sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==
- dependencies:
- loose-envify "^1.1.0"
+scheduler@^0.27.0:
+ version "0.27.0"
+ resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd"
+ integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==
schema-utils@^2.6.5:
version "2.7.0"
@@ -5999,11 +5957,6 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-symbol-observable@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
- integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
-
tapable@^2.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
@@ -6213,10 +6166,10 @@ url@^0.11.0:
punycode "1.3.2"
querystring "0.2.0"
-use-sync-external-store@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
- integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+use-sync-external-store@^1.4.0:
+ version "1.6.0"
+ resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d"
+ integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==
use@^3.1.0:
version "3.1.1"
diff --git a/script/convert b/script/convert
index b99413323f..45e1e8d35f 100755
--- a/script/convert
+++ b/script/convert
@@ -1,6 +1,14 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
+# This script converts the codebase to use minimum supported dependency versions.
+# It's run during CI when testing the "minimum" dependency matrix to ensure
+# backward compatibility.
+#
+# React/Shakapacker version compatibility is now tested through generator smoke tests
+# (see examples_config.yml for minimum version examples like basic-minimum).
+# This script only handles Node.js/tooling compatibility and Pro package test adjustments.
+
def gsub_file_content(path, old_content, new_content)
path = File.expand_path(path, __dir__)
@@ -17,19 +25,6 @@ def gsub_file_content(path, old_content, new_content)
File.binwrite(path, content)
end
-def move(old_path, new_path)
- old_path = File.expand_path(old_path, __dir__)
- new_path = File.expand_path(new_path, __dir__)
- File.rename(old_path, new_path)
-end
-
-# Keep shakapacker.yml since we're using Shakapacker 8+
-# move("../react_on_rails/spec/dummy/config/shakapacker.yml", "../react_on_rails/spec/dummy/config/webpacker.yml")
-
-# Shakapacker - use version with async script loading support (8.2.0+)
-gsub_file_content("../react_on_rails/Gemfile.development_dependencies", /gem "shakapacker", "[^"]*"/, 'gem "shakapacker", "8.2.0"')
-gsub_file_content("../react_on_rails/spec/dummy/package.json", /"shakapacker": "[^"]*",/, '"shakapacker": "8.2.0",')
-
# The below packages don't work on the oldest supported Node version and aren't needed there anyway
# Note: All dev dependencies remain in root package.json even after workspace migration
gsub_file_content("../package.json", /"[^"]*eslint[^"]*": "[^"]*",?/, "")
@@ -42,35 +37,16 @@ gsub_file_content("../package.json", %r{"@testing-library/[^"]*": "[^"]*",}, "")
# Clean up any trailing commas before closing braces
gsub_file_content("../package.json", /,(\s*})/, "\\1")
-# Switch to minimum supported React version (React 18 since we removed PropTypes)
-gsub_file_content("../package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
-gsub_file_content("../package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')
-gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react": "[^"]*",/, '"react": "18.0.0",')
-gsub_file_content("../react_on_rails/spec/dummy/package.json", /"react-dom": "[^"]*",/, '"react-dom": "18.0.0",')
+# Pro package: Skip RSC tests on React 18 since RSC requires React 19
gsub_file_content(
"../packages/react-on-rails-pro/package.json",
/"test:non-rsc": "(?:\\"|[^"])*",/,
'"test:non-rsc": "jest tests --testPathIgnorePatterns=\".*(RSC|stream|' \
'registerServerComponent|serverRenderReactComponent|SuspenseHydration).*\"",'
)
-# Make test:rsc script do nothing
+# Make test:rsc script do nothing on React 18
gsub_file_content(
"../packages/react-on-rails-pro/package.json",
/"test:rsc": "(?:\\"|[^"])*",/,
'"test:rsc": "exit 0",'
)
-# Keep modern JSX transform for React 18+
-# gsub_file_content("../tsconfig.json", "react-jsx", "react")
-# gsub_file_content("../spec/dummy/babel.config.js", "runtime: 'automatic'", "runtime: 'classic'")
-# Keep modern ReScript configuration for React 18+
-# gsub_file_content("../spec/dummy/rescript.json", '"version": 4', '"version": 4, "mode": "classic"')
-# Skip React 16 file replacements since we're using React 18+
-# Dir.glob(File.expand_path("../spec/dummy/**/app-react16/**/*.*", __dir__)).each do |file|
-# move(file, file.gsub("-react16", ""))
-# end
-
-# These replacements were incorrect - generateWebpackConfig() is the correct function from shakapacker
-# gsub_file_content("../spec/dummy/config/webpack/commonWebpackConfig.js", /generateWebpackConfig(\(\))?/,
-# "webpackConfig")
-#
-# gsub_file_content("../spec/dummy/config/webpack/webpack.config.js", /generateWebpackConfig(\(\))?/, "webpackConfig")
diff --git a/yarn.lock b/yarn.lock
index f2d38fd05c..8c5de04e67 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6272,7 +6272,7 @@ lodash@^4.17.4, lodash@^4.7.0:
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
+loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -7218,13 +7218,12 @@ raw-body@2.5.2:
iconv-lite "0.4.24"
unpipe "1.0.0"
-react-dom@18.0.0:
- version "18.0.0"
- resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.0.0.tgz#26b88534f8f1dbb80853e1eabe752f24100d8023"
- integrity sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==
+react-dom@^19.0.0:
+ version "19.2.0"
+ resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz#00ed1e959c365e9a9d48f8918377465466ec3af8"
+ integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==
dependencies:
- loose-envify "^1.1.0"
- scheduler "^0.21.0"
+ scheduler "^0.27.0"
react-is@^16.13.1:
version "16.13.1"
@@ -7255,12 +7254,10 @@ react-on-rails@*:
resolved "https://registry.npmjs.org/react-on-rails/-/react-on-rails-16.1.2.tgz#27308d7d5806e73354eea2355c5c4036ade443d4"
integrity sha512-SiE168FgUtp9Sld2MAZUs2+R/D7B+SlNGX4zl9T2rB1QluzgTY042a4/i6v+ivQpBIhNjJujlVFIHYp+uVqjoQ==
-react@18.0.0:
- version "18.0.0"
- resolved "https://registry.npmjs.org/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96"
- integrity sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==
- dependencies:
- loose-envify "^1.1.0"
+react@^19.0.0:
+ version "19.2.0"
+ resolved "https://registry.npmjs.org/react/-/react-19.2.0.tgz#d33dd1721698f4376ae57a54098cb47fc75d93a5"
+ integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==
readline-sync@^1.4.7:
version "1.4.10"
@@ -7538,12 +7535,10 @@ saxes@^6.0.0:
dependencies:
xmlchars "^2.2.0"
-scheduler@^0.21.0:
- version "0.21.0"
- resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz#6fd2532ff5a6d877b6edb12f00d8ab7e8f308820"
- integrity sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==
- dependencies:
- loose-envify "^1.1.0"
+scheduler@^0.27.0:
+ version "0.27.0"
+ resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd"
+ integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==
secure-json-parse@^4.0.0:
version "4.1.0"