@@ -14,6 +14,7 @@ def setup_js_dependencies
1414 @added_dependencies_to_package_json ||= false
1515 @ran_direct_installs ||= false
1616 add_js_dependencies
17+ # Only run final install if package_json gem was used and no direct installs ran
1718 install_js_dependencies if @added_dependencies_to_package_json && !@ran_direct_installs
1819 end
1920
@@ -27,25 +28,24 @@ def add_js_dependencies
2728 def add_react_on_rails_package
2829 major_minor_patch_only = /\A \d +\. \d +\. \d +\z /
2930
30- # Try to use package_json gem first, fall back to direct npm commands
3131 react_on_rails_pkg = if ReactOnRails ::VERSION . match? ( major_minor_patch_only )
32- [ "react-on-rails@#{ ReactOnRails ::VERSION } " ]
32+ "react-on-rails@#{ ReactOnRails ::VERSION } "
3333 else
3434 puts "Adding the latest react-on-rails NPM module. " \
3535 "Double check this is correct in package.json"
36- [ "react-on-rails" ]
36+ "react-on-rails"
3737 end
3838
3939 puts "Installing React on Rails package..."
40- if add_npm_dependencies ( react_on_rails_pkg )
40+ if add_js_dependency ( react_on_rails_pkg )
4141 @added_dependencies_to_package_json = true
42- return
42+ else
43+ # Fallback to direct npm install
44+ puts "Using direct npm commands as fallback"
45+ success = system ( "npm" , "install" , react_on_rails_pkg )
46+ @ran_direct_installs = true if success
47+ handle_npm_failure ( "react-on-rails package" , [ react_on_rails_pkg ] ) unless success
4348 end
44-
45- puts "Using direct npm commands as fallback"
46- success = system ( "npm" , "install" , *react_on_rails_pkg )
47- @ran_direct_installs = true if success
48- handle_npm_failure ( "react-on-rails package" , react_on_rails_pkg ) unless success
4949 end
5050
5151 def add_react_dependencies
@@ -58,14 +58,15 @@ def add_react_dependencies
5858 babel-plugin-transform-react-remove-prop-types
5959 babel-plugin-macros
6060 ]
61- if add_npm_dependencies ( react_deps )
61+
62+ if add_js_dependencies_batch ( react_deps )
6263 @added_dependencies_to_package_json = true
63- return
64+ else
65+ # Fallback to direct npm install
66+ success = system ( "npm" , "install" , *react_deps )
67+ @ran_direct_installs = true if success
68+ handle_npm_failure ( "React dependencies" , react_deps ) unless success
6469 end
65-
66- success = system ( "npm" , "install" , *react_deps )
67- @ran_direct_installs = true if success
68- handle_npm_failure ( "React dependencies" , react_deps ) unless success
6970 end
7071
7172 def add_css_dependencies
@@ -76,14 +77,15 @@ def add_css_dependencies
7677 mini-css-extract-plugin
7778 style-loader
7879 ]
79- if add_npm_dependencies ( css_deps )
80+
81+ if add_js_dependencies_batch ( css_deps )
8082 @added_dependencies_to_package_json = true
81- return
83+ else
84+ # Fallback to direct npm install
85+ success = system ( "npm" , "install" , *css_deps )
86+ @ran_direct_installs = true if success
87+ handle_npm_failure ( "CSS dependencies" , css_deps ) unless success
8288 end
83-
84- success = system ( "npm" , "install" , *css_deps )
85- @ran_direct_installs = true if success
86- handle_npm_failure ( "CSS dependencies" , css_deps ) unless success
8789 end
8890
8991 def add_dev_dependencies
@@ -92,29 +94,72 @@ def add_dev_dependencies
9294 @pmmmwh/react-refresh-webpack-plugin
9395 react-refresh
9496 ]
95- if add_npm_dependencies ( dev_deps , dev : true )
97+
98+ if add_js_dependencies_batch ( dev_deps , dev : true )
9699 @added_dependencies_to_package_json = true
97- return
100+ else
101+ # Fallback to direct npm install
102+ success = system ( "npm" , "install" , "--save-dev" , *dev_deps )
103+ @ran_direct_installs = true if success
104+ handle_npm_failure ( "development dependencies" , dev_deps , dev : true ) unless success
98105 end
106+ end
107+
108+ # Add a single dependency using package_json gem
109+ def add_js_dependency ( package , dev : false )
110+ return false unless package_json_available?
111+
112+ pj = package_json
113+ return false unless pj
114+
115+ begin
116+ if dev
117+ pj . manager . add ( package , type : :dev )
118+ else
119+ pj . manager . add ( package )
120+ end
121+ true
122+ rescue StandardError => e
123+ puts "Warning: Could not add #{ package } via package_json gem: #{ e . message } "
124+ false
125+ end
126+ end
99127
100- success = system ( "npm" , "install" , "--save-dev" , *dev_deps )
101- @ran_direct_installs = true if success
102- handle_npm_failure ( "development dependencies" , dev_deps , dev : true ) unless success
128+ # Add multiple dependencies at once using package_json gem
129+ def add_js_dependencies_batch ( packages , dev : false )
130+ return false unless package_json_available?
131+
132+ # Use the add_npm_dependencies helper from GeneratorHelper
133+ add_npm_dependencies ( packages , dev : dev )
134+ end
135+
136+ # Check if package_json gem is available and loaded
137+ def package_json_available?
138+ # Check if Shakapacker or package_json gem is available
139+ return true if defined? ( PackageJson )
140+
141+ begin
142+ require "package_json"
143+ true
144+ rescue LoadError
145+ false
146+ end
103147 end
104148
105149 def install_js_dependencies
106- # Detect which package manager to use
107- success = if File . exist? ( File . join ( destination_root , "yarn.lock" ) )
108- system ( "yarn" , "install" )
109- elsif File . exist? ( File . join ( destination_root , "pnpm-lock.yaml" ) )
110- system ( "pnpm" , "install" )
111- elsif File . exist? ( File . join ( destination_root , "package-lock.json" ) ) ||
112- File . exist? ( File . join ( destination_root , "package.json" ) )
113- # Use npm for package-lock.json or as default fallback
114- system ( "npm" , "install" )
115- else
116- true # No package manager detected, skip
117- end
150+ # First try to use package_json gem's install method if available
151+ if package_json_available? && package_json
152+ begin
153+ package_json . manager . install
154+ return true
155+ rescue StandardError => e
156+ puts "Warning: package_json gem install failed: #{ e . message } "
157+ # Fall through to manual detection
158+ end
159+ end
160+
161+ # Fallback to detecting package manager and running install
162+ success = detect_and_run_package_manager_install
118163
119164 unless success
120165 GeneratorMessages . add_warning ( <<~MSG . strip )
@@ -131,6 +176,21 @@ def install_js_dependencies
131176 success
132177 end
133178
179+ def detect_and_run_package_manager_install
180+ # Detect which package manager to use based on lock files
181+ if File . exist? ( File . join ( destination_root , "yarn.lock" ) )
182+ system ( "yarn" , "install" )
183+ elsif File . exist? ( File . join ( destination_root , "pnpm-lock.yaml" ) )
184+ system ( "pnpm" , "install" )
185+ elsif File . exist? ( File . join ( destination_root , "package-lock.json" ) ) ||
186+ File . exist? ( File . join ( destination_root , "package.json" ) )
187+ # Use npm for package-lock.json or as default fallback
188+ system ( "npm" , "install" )
189+ else
190+ true # No package manager detected, skip
191+ end
192+ end
193+
134194 def handle_npm_failure ( dependency_type , packages , dev : false )
135195 install_command = dev ? "npm install --save-dev" : "npm install"
136196 GeneratorMessages . add_warning ( <<~MSG . strip )
0 commit comments