module React module Generators class InstallGenerator < ::Rails::Generators::Base source_root File.expand_path '../../templates', __FILE__ desc 'Create default react.js folder layout and prep application.js' class_option :skip_git, type: :boolean, aliases: '-g', default: false, desc: 'Skip Git keeps' class_option :skip_server_rendering, type: :boolean, default: false, desc: "Don't generate server_rendering.js or config/initializers/react_server_rendering.rb" # Make an empty `components/` directory in the right place: def create_directory components_dir = if webpacker? Pathname.new(javascript_dir).parent.to_s else javascript_dir end empty_directory File.join(components_dir, 'components') unless options[:skip_git] create_file File.join(components_dir, 'components/.gitkeep') end end # Add requires, setup UJS def setup_react if webpacker? setup_react_webpacker else setup_react_sprockets end end def create_server_rendering if options[:skip_server_rendering] return elsif webpacker? ssr_manifest_path = File.join(javascript_dir, 'server_rendering.js') template('server_rendering_pack.js', ssr_manifest_path) else ssr_manifest_path = File.join(javascript_dir, 'server_rendering.js') template('server_rendering.js', ssr_manifest_path) initializer_path = 'config/initializers/react_server_rendering.rb' template('react_server_rendering.rb', initializer_path) end end private def webpacker? !!defined?(Webpacker) end def javascript_dir if webpacker? webpack_source_path .relative_path_from(::Rails.root) .to_s else 'app/assets/javascripts' end end def manifest Pathname.new(destination_root).join(javascript_dir, 'application.js') end def setup_react_sprockets require_react = "//= require react\n//= require react_ujs\n//= require components\n" if manifest.exist? manifest_contents = File.read(manifest) if match = manifest_contents.match(/\/\/=\s+require\s+turbolinks\s+\n/) inject_into_file manifest, require_react, { after: match[0] } elsif match = manifest_contents.match(/\/\/=\s+require_tree[^\n]*/) inject_into_file manifest, require_react, { before: match[0] } else append_file manifest, require_react end else create_file manifest, require_react end components_js = "//= require_tree ./components\n" components_file = File.join(javascript_dir, 'components.js') create_file components_file, components_js end WEBPACKER_SETUP_UJS = <<-JS // Support component names relative to this directory: var componentRequireContext = require.context("components", true) var ReactRailsUJS = require("react_ujs") ReactRailsUJS.useContext(componentRequireContext) JS def setup_react_webpacker `yarn add react_ujs` if manifest.exist? append_file(manifest, WEBPACKER_SETUP_UJS) else create_file(manifest, WEBPACKER_SETUP_UJS) end end private def webpack_source_path if Webpacker.respond_to?(:config) Webpacker.config.source_entry_path # Webpacker >3 else Webpacker::Configuration.source_path.join(Webpacker::Configuration.entry_path) # Webpacker <3 end end end end end