Class: ReactOnRails::Generators::BaseGenerator

Inherits:
Rails::Generators::Base
  • Object
show all
Includes:
GeneratorHelper
Defined in:
lib/generators/react_on_rails/base_generator.rb

Constant Summary collapse

CONFIGURE_RSPEC_TO_COMPILE_ASSETS =
<<-STR.strip_heredoc
  RSpec.configure do |config|
    # Ensure that if we are running js tests, we are using latest webpack assets
    # This will use the defaults of :js and :server_rendering meta tags
    ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
  end
STR

Instance Method Summary collapse

Methods included from GeneratorHelper

#add_documentation_reference, #add_npm_dependencies, #component_extension, #copy_file_and_missing_parent_directories, #dest_dir_exists?, #dest_file_exists?, #empty_directory_with_keep_file, #keep_file, #package_json, #setup_file_error, #symlink_dest_file_to_dest_file

Instance Method Details

#add_base_gems_to_gemfileObject



94
95
96
# File 'lib/generators/react_on_rails/base_generator.rb', line 94

def add_base_gems_to_gemfile
  run "bundle"
end

#add_css_dependenciesObject



196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/generators/react_on_rails/base_generator.rb', line 196

def add_css_dependencies
  puts "Installing CSS handling dependencies..."
  css_deps = %w[
    css-loader
    css-minimizer-webpack-plugin
    mini-css-extract-plugin
    style-loader
  ]
  return if add_npm_dependencies(css_deps)

  success = system("npm", "install", *css_deps)
  handle_npm_failure("CSS dependencies", css_deps) unless success
end

#add_dev_dependenciesObject



210
211
212
213
214
215
216
217
218
219
220
# File 'lib/generators/react_on_rails/base_generator.rb', line 210

def add_dev_dependencies
  puts "Installing development dependencies..."
  dev_deps = %w[
    @pmmmwh/react-refresh-webpack-plugin
    react-refresh
  ]
  return if add_npm_dependencies(dev_deps, dev: true)

  success = system("npm", "install", "--save-dev", *dev_deps)
  handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
end

#add_hello_world_routeObject



22
23
24
# File 'lib/generators/react_on_rails/base_generator.rb', line 22

def add_hello_world_route
  route "get 'hello_world', to: 'hello_world#index'"
end

#add_js_dependenciesObject



98
99
100
101
102
103
# File 'lib/generators/react_on_rails/base_generator.rb', line 98

def add_js_dependencies
  add_react_on_rails_package
  add_react_dependencies
  add_css_dependencies
  add_dev_dependencies
end

#add_react_dependenciesObject



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/generators/react_on_rails/base_generator.rb', line 180

def add_react_dependencies
  puts "Installing React dependencies..."
  react_deps = %w[
    react
    react-dom
    @babel/preset-react
    prop-types
    babel-plugin-transform-react-remove-prop-types
    babel-plugin-macros
  ]
  return if add_npm_dependencies(react_deps)

  success = system("npm", "install", *react_deps)
  handle_npm_failure("React dependencies", react_deps) unless success
end

#add_react_on_rails_packageObject



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/generators/react_on_rails/base_generator.rb', line 160

def add_react_on_rails_package
  major_minor_patch_only = /\A\d+\.\d+\.\d+\z/

  # Try to use package_json gem first, fall back to direct npm commands
  react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
                         ["react-on-rails@#{ReactOnRails::VERSION}"]
                       else
                         puts "Adding the latest react-on-rails NPM module. " \
                              "Double check this is correct in package.json"
                         ["react-on-rails"]
                       end

  puts "Installing React on Rails package..."
  return if add_npm_dependencies(react_on_rails_pkg)

  puts "Using direct npm commands as fallback"
  success = system("npm", "install", *react_on_rails_pkg)
  handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
end

#append_to_spec_rails_helperObject



150
151
152
153
154
155
156
157
158
# File 'lib/generators/react_on_rails/base_generator.rb', line 150

def append_to_spec_rails_helper
  rails_helper = File.join(destination_root, "spec/rails_helper.rb")
  if File.exist?(rails_helper)
    add_configure_rspec_to_compile_assets(rails_helper)
  else
    spec_helper = File.join(destination_root, "spec/spec_helper.rb")
    add_configure_rspec_to_compile_assets(spec_helper) if File.exist?(spec_helper)
  end
end

#copy_base_filesObject



34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/generators/react_on_rails/base_generator.rb', line 34

def copy_base_files
  base_path = "base/base/"
  base_files = %w[app/controllers/hello_world_controller.rb
                  app/views/layouts/hello_world.html.erb
                  Procfile.dev
                  Procfile.dev-static-assets
                  Procfile.dev-prod-assets]
  base_templates = %w[config/initializers/react_on_rails.rb]
  base_files.each { |file| copy_file("#{base_path}#{file}", file) }
  base_templates.each do |file|
    template("#{base_path}/#{file}.tt", file, { packer_type: ReactOnRails::PackerUtils.packer_type })
  end
end

#copy_js_bundle_filesObject



48
49
50
51
52
53
54
55
56
57
# File 'lib/generators/react_on_rails/base_generator.rb', line 48

def copy_js_bundle_files
  base_path = "base/base/"
  base_files = %w[app/javascript/packs/server-bundle.js]

  # Only copy HelloWorld.module.css for non-Redux components
  # Redux components handle their own CSS files
  base_files << "app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css" unless options.redux?

  base_files.each { |file| copy_file("#{base_path}#{file}", file) }
end

#copy_packer_configObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/generators/react_on_rails/base_generator.rb', line 79

def copy_packer_config
  # Skip copying if Shakapacker was just installed (to avoid conflicts)
  # Check for a temporary marker file that indicates fresh Shakapacker install
  if File.exist?(".shakapacker_just_installed")
    puts "Skipping Shakapacker config copy (already installed by Shakapacker installer)"
    File.delete(".shakapacker_just_installed") # Clean up marker
    return
  end

  puts "Adding Shakapacker #{ReactOnRails::PackerUtils.shakapacker_version} config"
  base_path = "base/base/"
  config = "config/shakapacker.yml"
  copy_file("#{base_path}#{config}", config)
end

#copy_webpack_configObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/generators/react_on_rails/base_generator.rb', line 59

def copy_webpack_config
  puts "Adding Webpack config"
  base_path = "base/base"
  base_files = %w[babel.config.js
                  config/webpack/clientWebpackConfig.js
                  config/webpack/commonWebpackConfig.js
                  config/webpack/test.js
                  config/webpack/development.js
                  config/webpack/production.js
                  config/webpack/serverWebpackConfig.js
                  config/webpack/generateWebpackConfigs.js]
  config = {
    message: "// The source code including full typescript support is available at:"
  }
  base_files.each { |file| template("#{base_path}/#{file}.tt", file, config) }

  # Handle webpack.config.js separately with smart replacement
  copy_webpack_main_config(base_path, config)
end

#create_react_directoriesObject



26
27
28
29
30
31
32
# File 'lib/generators/react_on_rails/base_generator.rb', line 26

def create_react_directories
  # Create auto-registration directory structure for non-Redux components only
  # Redux components handle their own directory structure
  return if options.redux?

  empty_directory("app/javascript/src/HelloWorld/ror_components")
end

#install_js_dependenciesObject



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/generators/react_on_rails/base_generator.rb', line 105

def install_js_dependencies
  # Detect which package manager to use
  success = if File.exist?(File.join(destination_root, "yarn.lock"))
              system("yarn", "install")
            elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
              system("pnpm", "install")
            elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
                  File.exist?(File.join(destination_root, "package.json"))
              # Use npm for package-lock.json or as default fallback
              system("npm", "install")
            else
              true # No package manager detected, skip
            end

  unless success
    GeneratorMessages.add_warning(<<~MSG.strip)
      ⚠️  JavaScript dependencies installation failed.

      This could be due to network issues or missing package manager.
      You can install dependencies manually later by running:
      • npm install (if using npm)
      • yarn install (if using yarn)
      • pnpm install (if using pnpm)
    MSG
  end

  success
end

#update_gitignore_for_auto_registrationObject



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/generators/react_on_rails/base_generator.rb', line 134

def update_gitignore_for_auto_registration
  gitignore_path = File.join(destination_root, ".gitignore")
  return unless File.exist?(gitignore_path)

  gitignore_content = File.read(gitignore_path)
  return if gitignore_content.include?("**/generated/**")

  append_to_file ".gitignore" do
    <<~GITIGNORE

      # Generated React on Rails packs
      **/generated/**
    GITIGNORE
  end
end