react-rails 2.7.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +85 -42
- data/lib/assets/javascripts/react_ujs.js +1 -1
- data/lib/assets/react-source/development/react-server.js +333 -10
- data/lib/assets/react-source/development/react.js +19 -28
- data/lib/assets/react-source/production/react-server.js +1 -1
- data/lib/assets/react-source/production/react.js +1 -1
- data/lib/generators/react/component_generator.rb +126 -121
- data/lib/generators/react/install_generator.rb +50 -72
- data/lib/generators/templates/component.es6.jsx +8 -8
- data/lib/generators/templates/component.js.jsx +14 -14
- data/lib/generators/templates/react_server_rendering.rb +3 -1
- data/lib/react/jsx/babel_transformer.rb +12 -6
- data/lib/react/jsx/jsx_transformer.rb +7 -5
- data/lib/react/jsx/processor.rb +3 -1
- data/lib/react/jsx/sprockets_strategy.rb +17 -11
- data/lib/react/jsx/template.rb +7 -6
- data/lib/react/jsx.rb +9 -7
- data/lib/react/rails/asset_variant.rb +7 -6
- data/lib/react/rails/component_mount.rb +37 -29
- data/lib/react/rails/controller_lifecycle.rb +2 -0
- data/lib/react/rails/controller_renderer.rb +3 -1
- data/lib/react/rails/railtie.rb +19 -22
- data/lib/react/rails/test_helper.rb +3 -1
- data/lib/react/rails/version.rb +3 -1
- data/lib/react/rails/view_helper.rb +3 -1
- data/lib/react/rails.rb +9 -7
- data/lib/react/server_rendering/bundle_renderer.rb +34 -39
- data/lib/react/server_rendering/environment_container.rb +2 -0
- data/lib/react/server_rendering/exec_js_renderer.rb +15 -6
- data/lib/react/server_rendering/manifest_container.rb +6 -2
- data/lib/react/server_rendering/separate_server_bundle_container.rb +19 -0
- data/lib/react/server_rendering/yaml_manifest_container.rb +4 -2
- data/lib/react/server_rendering.rb +11 -9
- data/lib/react-rails.rb +8 -6
- data/lib/react.rb +2 -0
- metadata +5 -47
- data/lib/react/server_rendering/webpacker_manifest_container.rb +0 -96
| @@ -1,10 +1,12 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module React
         | 
| 2 4 | 
             
              module Generators
         | 
| 3 5 | 
             
                class ComponentGenerator < ::Rails::Generators::NamedBase
         | 
| 4 | 
            -
                  source_root File.expand_path  | 
| 6 | 
            +
                  source_root File.expand_path "../templates", __dir__
         | 
| 5 7 | 
             
                  desc <<-DESC.strip_heredoc
         | 
| 6 8 | 
             
                  Description:
         | 
| 7 | 
            -
                      Scaffold a React component into `components/` of your  | 
| 9 | 
            +
                      Scaffold a React component into `components/` of your Shakapacker source or asset pipeline.
         | 
| 8 10 | 
             
                      The generated component will include a basic render function and a PropTypes
         | 
| 9 11 | 
             
                      hash to help with development.
         | 
| 10 12 |  | 
| @@ -46,110 +48,101 @@ module React | |
| 46 48 | 
             
                  DESC
         | 
| 47 49 |  | 
| 48 50 | 
             
                  argument :attributes,
         | 
| 49 | 
            -
                           : | 
| 50 | 
            -
                           : | 
| 51 | 
            -
                           : | 
| 51 | 
            +
                           type: :array,
         | 
| 52 | 
            +
                           default: [],
         | 
| 53 | 
            +
                           banner: "field[:type] field[:type] ..."
         | 
| 52 54 |  | 
| 53 55 | 
             
                  class_option :es6,
         | 
| 54 56 | 
             
                               type: :boolean,
         | 
| 55 57 | 
             
                               default: false,
         | 
| 56 | 
            -
                               desc:  | 
| 58 | 
            +
                               desc: "Output es6 class based component"
         | 
| 57 59 |  | 
| 58 60 | 
             
                  class_option :ts,
         | 
| 59 61 | 
             
                               type: :boolean,
         | 
| 60 62 | 
             
                               default: false,
         | 
| 61 | 
            -
                               desc:  | 
| 63 | 
            +
                               desc: "Output tsx class based component"
         | 
| 62 64 |  | 
| 63 65 | 
             
                  class_option :coffee,
         | 
| 64 66 | 
             
                               type: :boolean,
         | 
| 65 67 | 
             
                               default: false,
         | 
| 66 | 
            -
                               desc:  | 
| 68 | 
            +
                               desc: "Output coffeescript based component"
         | 
| 67 69 |  | 
| 68 70 | 
             
                  REACT_PROP_TYPES = {
         | 
| 69 | 
            -
                     | 
| 70 | 
            -
                     | 
| 71 | 
            -
                     | 
| 72 | 
            -
                     | 
| 73 | 
            -
                     | 
| 74 | 
            -
                     | 
| 75 | 
            -
                     | 
| 76 | 
            -
                     | 
| 77 | 
            -
                     | 
| 78 | 
            -
                     | 
| 79 | 
            -
                     | 
| 80 | 
            -
                     | 
| 81 | 
            -
             | 
| 82 | 
            -
                     | 
| 83 | 
            -
                       | 
| 71 | 
            +
                    "node" => "PropTypes.node",
         | 
| 72 | 
            +
                    "bool" => "PropTypes.bool",
         | 
| 73 | 
            +
                    "boolean" => "PropTypes.bool",
         | 
| 74 | 
            +
                    "string" => "PropTypes.string",
         | 
| 75 | 
            +
                    "number" => "PropTypes.number",
         | 
| 76 | 
            +
                    "object" => "PropTypes.object",
         | 
| 77 | 
            +
                    "array" => "PropTypes.array",
         | 
| 78 | 
            +
                    "shape" => "PropTypes.shape({})",
         | 
| 79 | 
            +
                    "element" => "PropTypes.element",
         | 
| 80 | 
            +
                    "func" => "PropTypes.func",
         | 
| 81 | 
            +
                    "function" => "PropTypes.func",
         | 
| 82 | 
            +
                    "any" => "PropTypes.any",
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    "instanceOf" => lambda { |type|
         | 
| 85 | 
            +
                      "PropTypes.instanceOf(#{type.to_s.camelize})"
         | 
| 84 86 | 
             
                    },
         | 
| 85 87 |  | 
| 86 | 
            -
                     | 
| 87 | 
            -
                      enums = options.map{ |k| "'#{k | 
| 88 | 
            -
                       | 
| 88 | 
            +
                    "oneOf" => lambda { |*options|
         | 
| 89 | 
            +
                      enums = options.map { |k| "'#{k}'" }.join(",")
         | 
| 90 | 
            +
                      "PropTypes.oneOf([#{enums}])"
         | 
| 89 91 | 
             
                    },
         | 
| 90 92 |  | 
| 91 | 
            -
                     | 
| 92 | 
            -
                      types = options.map{ |k|  | 
| 93 | 
            -
                       | 
| 93 | 
            +
                    "oneOfType" => lambda { |*options|
         | 
| 94 | 
            +
                      types = options.map { |k| lookup(k.to_s, k.to_s).to_s }.join(",")
         | 
| 95 | 
            +
                      "PropTypes.oneOfType([#{types}])"
         | 
| 94 96 | 
             
                    }
         | 
| 95 | 
            -
                  }
         | 
| 97 | 
            +
                  }.freeze
         | 
| 96 98 |  | 
| 97 99 | 
             
                  TYPESCRIPT_TYPES = {
         | 
| 98 | 
            -
                     | 
| 99 | 
            -
                     | 
| 100 | 
            -
                     | 
| 101 | 
            -
                     | 
| 102 | 
            -
                     | 
| 103 | 
            -
                     | 
| 104 | 
            -
                     | 
| 105 | 
            -
                     | 
| 106 | 
            -
                     | 
| 107 | 
            -
                     | 
| 108 | 
            -
                     | 
| 109 | 
            -
                     | 
| 110 | 
            -
             | 
| 111 | 
            -
                     | 
| 100 | 
            +
                    "node" => "React.ReactNode",
         | 
| 101 | 
            +
                    "bool" => "boolean",
         | 
| 102 | 
            +
                    "boolean" => "boolean",
         | 
| 103 | 
            +
                    "string" => "string",
         | 
| 104 | 
            +
                    "number" => "number",
         | 
| 105 | 
            +
                    "object" => "object",
         | 
| 106 | 
            +
                    "array" => "Array<any>",
         | 
| 107 | 
            +
                    "shape" => "object",
         | 
| 108 | 
            +
                    "element" => "object",
         | 
| 109 | 
            +
                    "func" => "object",
         | 
| 110 | 
            +
                    "function" => "object",
         | 
| 111 | 
            +
                    "any" => "any",
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    "instanceOf" => lambda { |type|
         | 
| 112 114 | 
             
                      type.to_s.camelize
         | 
| 113 115 | 
             
                    },
         | 
| 114 116 |  | 
| 115 | 
            -
                     | 
| 116 | 
            -
                      opts.map{ |k| "'#{k | 
| 117 | 
            +
                    "oneOf" => lambda { |*opts|
         | 
| 118 | 
            +
                      opts.map { |k| "'#{k}'" }.join(" | ")
         | 
| 117 119 | 
             
                    },
         | 
| 118 120 |  | 
| 119 | 
            -
                     | 
| 120 | 
            -
                      opts.map{ |k|  | 
| 121 | 
            +
                    "oneOfType" => lambda { |*opts|
         | 
| 122 | 
            +
                      opts.map { |k| ts_lookup(k.to_s, k.to_s).to_s }.join(" | ")
         | 
| 121 123 | 
             
                    }
         | 
| 122 | 
            -
                  }
         | 
| 124 | 
            +
                  }.freeze
         | 
| 123 125 |  | 
| 124 126 | 
             
                  def create_component_file
         | 
| 125 | 
            -
                    template_extension =  | 
| 126 | 
            -
             | 
| 127 | 
            -
                     | 
| 128 | 
            -
                      'js.jsx.tsx'
         | 
| 129 | 
            -
                    elsif options[:es6] || webpacker?
         | 
| 130 | 
            -
                      'es6.jsx'
         | 
| 131 | 
            -
                    else
         | 
| 132 | 
            -
                      'js.jsx'
         | 
| 133 | 
            -
                    end
         | 
| 134 | 
            -
             | 
| 135 | 
            -
                    # Prefer webpacker to sprockets:
         | 
| 136 | 
            -
                    if webpacker?
         | 
| 127 | 
            +
                    template_extension = detect_template_extension
         | 
| 128 | 
            +
                    # Prefer Shakapacker to Sprockets:
         | 
| 129 | 
            +
                    if shakapacker?
         | 
| 137 130 | 
             
                      new_file_name = file_name.camelize
         | 
| 138 131 | 
             
                      extension = if options[:coffee]
         | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 132 | 
            +
                                    "coffee"
         | 
| 133 | 
            +
                                  elsif options[:ts]
         | 
| 134 | 
            +
                                    "tsx"
         | 
| 135 | 
            +
                                  else
         | 
| 136 | 
            +
                                    "js"
         | 
| 137 | 
            +
                                  end
         | 
| 145 138 | 
             
                      target_dir = webpack_configuration.source_path
         | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 139 | 
            +
                                                        .join("components")
         | 
| 140 | 
            +
                                                        .relative_path_from(::Rails.root)
         | 
| 141 | 
            +
                                                        .to_s
         | 
| 149 142 | 
             
                    else
         | 
| 150 143 | 
             
                      new_file_name = file_name
         | 
| 151 144 | 
             
                      extension = template_extension
         | 
| 152 | 
            -
                      target_dir =  | 
| 145 | 
            +
                      target_dir = "app/assets/javascripts/components"
         | 
| 153 146 | 
             
                    end
         | 
| 154 147 |  | 
| 155 148 | 
             
                    file_path = File.join(target_dir, class_path, "#{new_file_name}.#{extension}")
         | 
| @@ -159,7 +152,7 @@ module React | |
| 159 152 | 
             
                  private
         | 
| 160 153 |  | 
| 161 154 | 
             
                  def webpack_configuration
         | 
| 162 | 
            -
                     | 
| 155 | 
            +
                    Shakapacker.respond_to?(:config) ? Shakapacker.config : Shakapacker::Configuration
         | 
| 163 156 | 
             
                  end
         | 
| 164 157 |  | 
| 165 158 | 
             
                  def component_name
         | 
| @@ -167,68 +160,68 @@ module React | |
| 167 160 | 
             
                  end
         | 
| 168 161 |  | 
| 169 162 | 
             
                  def file_header
         | 
| 170 | 
            -
                    if  | 
| 171 | 
            -
                      return  | 
| 172 | 
            -
             | 
| 163 | 
            +
                    if shakapacker?
         | 
| 164 | 
            +
                      return %(import * as React from "react"\n) if options[:ts]
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                      <<~JS
         | 
| 167 | 
            +
                        import React from "react"
         | 
| 168 | 
            +
                        import PropTypes from "prop-types"
         | 
| 169 | 
            +
                      JS
         | 
| 173 170 | 
             
                    else
         | 
| 174 | 
            -
                       | 
| 171 | 
            +
                      ""
         | 
| 175 172 | 
             
                    end
         | 
| 176 173 | 
             
                  end
         | 
| 177 174 |  | 
| 178 175 | 
             
                  def file_footer
         | 
| 179 | 
            -
                    if  | 
| 180 | 
            -
                       | 
| 176 | 
            +
                    if shakapacker?
         | 
| 177 | 
            +
                      %(export default #{component_name})
         | 
| 181 178 | 
             
                    else
         | 
| 182 | 
            -
                       | 
| 179 | 
            +
                      ""
         | 
| 183 180 | 
             
                    end
         | 
| 184 181 | 
             
                  end
         | 
| 185 182 |  | 
| 186 | 
            -
                  def  | 
| 187 | 
            -
                    defined?( | 
| 183 | 
            +
                  def shakapacker?
         | 
| 184 | 
            +
                    defined?(Shakapacker)
         | 
| 188 185 | 
             
                  end
         | 
| 189 186 |  | 
| 190 187 | 
             
                  def parse_attributes!
         | 
| 191 188 | 
             
                    self.attributes = (attributes || []).map do |attr|
         | 
| 192 | 
            -
                       | 
| 193 | 
            -
                      type = ''
         | 
| 194 | 
            -
                      args = ''
         | 
| 189 | 
            +
                      args = ""
         | 
| 195 190 | 
             
                      args_regex = /(?<args>{.*})/
         | 
| 196 191 |  | 
| 197 | 
            -
                      name, type = attr.split( | 
| 192 | 
            +
                      name, type = attr.split(":")
         | 
| 198 193 |  | 
| 199 | 
            -
                      if matchdata = args_regex.match(type)
         | 
| 194 | 
            +
                      if (matchdata = args_regex.match(type))
         | 
| 200 195 | 
             
                        args = matchdata[:args]
         | 
| 201 | 
            -
                        type = type.gsub(args_regex,  | 
| 196 | 
            +
                        type = type.gsub(args_regex, "")
         | 
| 202 197 | 
             
                      end
         | 
| 203 198 |  | 
| 204 199 | 
             
                      if options[:ts]
         | 
| 205 | 
            -
                        { : | 
| 200 | 
            +
                        { name: name, type: ts_lookup(name, type, args), union: union?(args) }
         | 
| 206 201 | 
             
                      else
         | 
| 207 | 
            -
                        { : | 
| 202 | 
            +
                        { name: name, type: lookup(type, args) }
         | 
| 208 203 | 
             
                      end
         | 
| 209 204 | 
             
                    end
         | 
| 210 205 | 
             
                  end
         | 
| 211 206 |  | 
| 212 | 
            -
                  def union?(args =  | 
| 213 | 
            -
                     | 
| 207 | 
            +
                  def union?(args = "")
         | 
| 208 | 
            +
                    args.to_s.gsub(/[{}]/, "").split(",").count > 1
         | 
| 214 209 | 
             
                  end
         | 
| 215 210 |  | 
| 216 | 
            -
                  def self.ts_lookup( | 
| 211 | 
            +
                  def self.ts_lookup(_name, type = "node", args = "")
         | 
| 217 212 | 
             
                    ts_type = TYPESCRIPT_TYPES[type]
         | 
| 218 213 | 
             
                    if ts_type.blank?
         | 
| 219 | 
            -
                       | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 214 | 
            +
                      ts_type = if /^[[:upper:]]/.match?(type)
         | 
| 215 | 
            +
                                  TYPESCRIPT_TYPES["instanceOf"]
         | 
| 216 | 
            +
                                else
         | 
| 217 | 
            +
                                  TYPESCRIPT_TYPES["node"]
         | 
| 218 | 
            +
                                end
         | 
| 224 219 | 
             
                    end
         | 
| 225 220 |  | 
| 226 | 
            -
                    args = args.to_s.gsub(/[{}]/,  | 
| 221 | 
            +
                    args = args.to_s.gsub(/[{}]/, "").split(",")
         | 
| 227 222 |  | 
| 228 223 | 
             
                    if ts_type.respond_to? :call
         | 
| 229 | 
            -
                      if args.blank?
         | 
| 230 | 
            -
                        return ts_type.call(type)
         | 
| 231 | 
            -
                      end
         | 
| 224 | 
            +
                      return ts_type.call(type) if args.blank?
         | 
| 232 225 |  | 
| 233 226 | 
             
                      ts_type = ts_type.call(*args)
         | 
| 234 227 | 
             
                    end
         | 
| @@ -236,29 +229,41 @@ module React | |
| 236 229 | 
             
                    ts_type
         | 
| 237 230 | 
             
                  end
         | 
| 238 231 |  | 
| 239 | 
            -
                  def ts_lookup(name, type =  | 
| 232 | 
            +
                  def ts_lookup(name, type = "node", args = "")
         | 
| 240 233 | 
             
                    self.class.ts_lookup(name, type, args)
         | 
| 241 234 | 
             
                  end
         | 
| 242 235 |  | 
| 243 | 
            -
             | 
| 244 | 
            -
             | 
| 245 | 
            -
             | 
| 246 | 
            -
             | 
| 247 | 
            -
             | 
| 248 | 
            -
             | 
| 249 | 
            -
             | 
| 250 | 
            -
             | 
| 251 | 
            -
             | 
| 252 | 
            -
             | 
| 253 | 
            -
             | 
| 254 | 
            -
             | 
| 255 | 
            -
             | 
| 256 | 
            -
             | 
| 257 | 
            -
             | 
| 258 | 
            -
             | 
| 259 | 
            -
             | 
| 260 | 
            -
             | 
| 261 | 
            -
             | 
| 236 | 
            +
                  def self.lookup(type = "node", options = "")
         | 
| 237 | 
            +
                    react_prop_type = REACT_PROP_TYPES[type]
         | 
| 238 | 
            +
                    if react_prop_type.blank?
         | 
| 239 | 
            +
                      react_prop_type = if /^[[:upper:]]/.match?(type)
         | 
| 240 | 
            +
                                          REACT_PROP_TYPES["instanceOf"]
         | 
| 241 | 
            +
                                        else
         | 
| 242 | 
            +
                                          REACT_PROP_TYPES["node"]
         | 
| 243 | 
            +
                                        end
         | 
| 244 | 
            +
                    end
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                    options = options.to_s.gsub(/[{}]/, "").split(",")
         | 
| 247 | 
            +
             | 
| 248 | 
            +
                    react_prop_type = react_prop_type.call(*options) if react_prop_type.respond_to? :call
         | 
| 249 | 
            +
                    react_prop_type
         | 
| 250 | 
            +
                  end
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                  def lookup(type = "node", options = "")
         | 
| 253 | 
            +
                    self.class.lookup(type, options)
         | 
| 254 | 
            +
                  end
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                  def detect_template_extension
         | 
| 257 | 
            +
                    if options[:coffee]
         | 
| 258 | 
            +
                      "js.jsx.coffee"
         | 
| 259 | 
            +
                    elsif options[:ts]
         | 
| 260 | 
            +
                      "js.jsx.tsx"
         | 
| 261 | 
            +
                    elsif options[:es6] || shakapacker?
         | 
| 262 | 
            +
                      "es6.jsx"
         | 
| 263 | 
            +
                    else
         | 
| 264 | 
            +
                      "js.jsx"
         | 
| 265 | 
            +
                    end
         | 
| 266 | 
            +
                  end
         | 
| 262 267 | 
             
                end
         | 
| 263 268 | 
             
              end
         | 
| 264 269 | 
             
            end
         | 
| @@ -1,51 +1,40 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module React
         | 
| 2 4 | 
             
              module Generators
         | 
| 3 5 | 
             
                class InstallGenerator < ::Rails::Generators::Base
         | 
| 4 | 
            -
                  source_root File.expand_path  | 
| 6 | 
            +
                  source_root File.expand_path "../templates", __dir__
         | 
| 5 7 |  | 
| 6 | 
            -
                  desc  | 
| 8 | 
            +
                  desc "Create default react.js folder layout and prep application.js"
         | 
| 7 9 |  | 
| 8 10 | 
             
                  class_option :skip_git,
         | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 11 | 
            +
                               type: :boolean,
         | 
| 12 | 
            +
                               aliases: "-g",
         | 
| 13 | 
            +
                               default: false,
         | 
| 14 | 
            +
                               desc: "Skip Git keeps"
         | 
| 13 15 |  | 
| 14 16 | 
             
                  class_option :skip_server_rendering,
         | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
                  # For Shakapacker below version 7, we need to set relative path for source_entry_path
         | 
| 20 | 
            -
                  def modify_webpacker_yml
         | 
| 21 | 
            -
                    webpacker_yml_path = 'config/webpacker.yml'
         | 
| 22 | 
            -
                    if webpacker? && Pathname.new(webpacker_yml_path).exist?
         | 
| 23 | 
            -
                      gsub_file(
         | 
| 24 | 
            -
                        webpacker_yml_path,
         | 
| 25 | 
            -
                        "source_entry_path: /\n",
         | 
| 26 | 
            -
                        "source_entry_path: packs\n"
         | 
| 27 | 
            -
                      )
         | 
| 28 | 
            -
                      reloaded_webpacker_config
         | 
| 29 | 
            -
                    end
         | 
| 30 | 
            -
                  end
         | 
| 17 | 
            +
                               type: :boolean,
         | 
| 18 | 
            +
                               default: false,
         | 
| 19 | 
            +
                               desc: "Don't generate server_rendering.js or config/initializers/react_server_rendering.rb"
         | 
| 31 20 |  | 
| 32 21 | 
             
                  # Make an empty `components/` directory in the right place:
         | 
| 33 22 | 
             
                  def create_directory
         | 
| 34 | 
            -
                    components_dir = if  | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
                    empty_directory File.join(components_dir,  | 
| 40 | 
            -
                     | 
| 41 | 
            -
             | 
| 42 | 
            -
                     | 
| 23 | 
            +
                    components_dir = if shakapacker?
         | 
| 24 | 
            +
                                       Pathname.new(javascript_dir).parent.to_s
         | 
| 25 | 
            +
                                     else
         | 
| 26 | 
            +
                                       javascript_dir
         | 
| 27 | 
            +
                                     end
         | 
| 28 | 
            +
                    empty_directory File.join(components_dir, "components")
         | 
| 29 | 
            +
                    return if options[:skip_git]
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    create_file File.join(components_dir, "components/.keep")
         | 
| 43 32 | 
             
                  end
         | 
| 44 33 |  | 
| 45 34 | 
             
                  # Add requires, setup UJS
         | 
| 46 35 | 
             
                  def setup_react
         | 
| 47 | 
            -
                    if  | 
| 48 | 
            -
                       | 
| 36 | 
            +
                    if shakapacker?
         | 
| 37 | 
            +
                      setup_react_shakapacker
         | 
| 49 38 | 
             
                    else
         | 
| 50 39 | 
             
                      setup_react_sprockets
         | 
| 51 40 | 
             
                    end
         | 
| @@ -53,36 +42,36 @@ module React | |
| 53 42 |  | 
| 54 43 | 
             
                  def create_server_rendering
         | 
| 55 44 | 
             
                    if options[:skip_server_rendering]
         | 
| 56 | 
            -
                       | 
| 57 | 
            -
                    elsif  | 
| 58 | 
            -
                      ssr_manifest_path = File.join(javascript_dir,  | 
| 59 | 
            -
                      template( | 
| 45 | 
            +
                      nil
         | 
| 46 | 
            +
                    elsif shakapacker?
         | 
| 47 | 
            +
                      ssr_manifest_path = File.join(javascript_dir, "server_rendering.js")
         | 
| 48 | 
            +
                      template("server_rendering_pack.js", ssr_manifest_path)
         | 
| 60 49 | 
             
                    else
         | 
| 61 | 
            -
                      ssr_manifest_path = File.join(javascript_dir,  | 
| 62 | 
            -
                      template( | 
| 63 | 
            -
                      initializer_path =  | 
| 64 | 
            -
                      template( | 
| 50 | 
            +
                      ssr_manifest_path = File.join(javascript_dir, "server_rendering.js")
         | 
| 51 | 
            +
                      template("server_rendering.js", ssr_manifest_path)
         | 
| 52 | 
            +
                      initializer_path = "config/initializers/react_server_rendering.rb"
         | 
| 53 | 
            +
                      template("react_server_rendering.rb", initializer_path)
         | 
| 65 54 | 
             
                    end
         | 
| 66 55 | 
             
                  end
         | 
| 67 56 |  | 
| 68 57 | 
             
                  private
         | 
| 69 58 |  | 
| 70 | 
            -
                  def  | 
| 71 | 
            -
                    !!defined?( | 
| 59 | 
            +
                  def shakapacker?
         | 
| 60 | 
            +
                    !!defined?(Shakapacker)
         | 
| 72 61 | 
             
                  end
         | 
| 73 62 |  | 
| 74 63 | 
             
                  def javascript_dir
         | 
| 75 | 
            -
                    if  | 
| 76 | 
            -
                       | 
| 64 | 
            +
                    if shakapacker?
         | 
| 65 | 
            +
                      shakapacker_source_path
         | 
| 77 66 | 
             
                        .relative_path_from(::Rails.root)
         | 
| 78 67 | 
             
                        .to_s
         | 
| 79 68 | 
             
                    else
         | 
| 80 | 
            -
                       | 
| 69 | 
            +
                      "app/assets/javascripts"
         | 
| 81 70 | 
             
                    end
         | 
| 82 71 | 
             
                  end
         | 
| 83 72 |  | 
| 84 73 | 
             
                  def manifest
         | 
| 85 | 
            -
                    Pathname.new(destination_root).join(javascript_dir,  | 
| 74 | 
            +
                    Pathname.new(destination_root).join(javascript_dir, "application.js")
         | 
| 86 75 | 
             
                  end
         | 
| 87 76 |  | 
| 88 77 | 
             
                  def setup_react_sprockets
         | 
| @@ -91,9 +80,9 @@ module React | |
| 91 80 | 
             
                    if manifest.exist?
         | 
| 92 81 | 
             
                      manifest_contents = File.read(manifest)
         | 
| 93 82 |  | 
| 94 | 
            -
                      if match = manifest_contents.match( | 
| 83 | 
            +
                      if (match = manifest_contents.match(%r{//=\s+require\s+turbolinks\s+\n}))
         | 
| 95 84 | 
             
                        inject_into_file manifest, require_react, { after: match[0] }
         | 
| 96 | 
            -
                      elsif match = manifest_contents.match( | 
| 85 | 
            +
                      elsif (match = manifest_contents.match(%r{//=\s+require_tree[^\n]*}))
         | 
| 97 86 | 
             
                        inject_into_file manifest, require_react, { before: match[0] }
         | 
| 98 87 | 
             
                      else
         | 
| 99 88 | 
             
                        append_file manifest, require_react
         | 
| @@ -103,39 +92,28 @@ module React | |
| 103 92 | 
             
                    end
         | 
| 104 93 |  | 
| 105 94 | 
             
                    components_js = "//= require_tree ./components\n"
         | 
| 106 | 
            -
                    components_file = File.join(javascript_dir,  | 
| 95 | 
            +
                    components_file = File.join(javascript_dir, "components.js")
         | 
| 107 96 | 
             
                    create_file components_file, components_js
         | 
| 108 97 | 
             
                  end
         | 
| 109 98 |  | 
| 110 | 
            -
                   | 
| 111 | 
            -
            // Support component names relative to this directory:
         | 
| 112 | 
            -
            var componentRequireContext = require.context("components", true);
         | 
| 113 | 
            -
            var ReactRailsUJS = require("react_ujs");
         | 
| 114 | 
            -
            ReactRailsUJS.useContext(componentRequireContext);
         | 
| 115 | 
            -
            JS
         | 
| 99 | 
            +
                  SHAKAPACKER_SETUP_UJS = <<~JS
         | 
| 100 | 
            +
                    // Support component names relative to this directory:
         | 
| 101 | 
            +
                    var componentRequireContext = require.context("components", true);
         | 
| 102 | 
            +
                    var ReactRailsUJS = require("react_ujs");
         | 
| 103 | 
            +
                    ReactRailsUJS.useContext(componentRequireContext);
         | 
| 104 | 
            +
                  JS
         | 
| 116 105 |  | 
| 117 | 
            -
                  def  | 
| 106 | 
            +
                  def setup_react_shakapacker
         | 
| 118 107 | 
             
                    `yarn add react_ujs`
         | 
| 119 108 | 
             
                    if manifest.exist?
         | 
| 120 | 
            -
                      append_file(manifest,  | 
| 121 | 
            -
                    else
         | 
| 122 | 
            -
                      create_file(manifest, WEBPACKER_SETUP_UJS)
         | 
| 123 | 
            -
                    end
         | 
| 124 | 
            -
                  end
         | 
| 125 | 
            -
             | 
| 126 | 
            -
                  private
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                  def webpack_source_path
         | 
| 129 | 
            -
                    if Webpacker.respond_to?(:config)
         | 
| 130 | 
            -
                      Webpacker.config.source_entry_path # Webpacker >3
         | 
| 109 | 
            +
                      append_file(manifest, SHAKAPACKER_SETUP_UJS)
         | 
| 131 110 | 
             
                    else
         | 
| 132 | 
            -
                       | 
| 111 | 
            +
                      create_file(manifest, SHAKAPACKER_SETUP_UJS)
         | 
| 133 112 | 
             
                    end
         | 
| 134 113 | 
             
                  end
         | 
| 135 114 |  | 
| 136 | 
            -
                  def  | 
| 137 | 
            -
                     | 
| 138 | 
            -
                    Webpacker.config
         | 
| 115 | 
            +
                  def shakapacker_source_path
         | 
| 116 | 
            +
                    Shakapacker.config.source_entry_path
         | 
| 139 117 | 
             
                  end
         | 
| 140 118 | 
             
                end
         | 
| 141 119 | 
             
              end
         | 
| @@ -1,13 +1,12 @@ | |
| 1 | 
            -
            <%= file_header %> | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 1 | 
            +
            <%= file_header %>
         | 
| 2 | 
            +
            const <%= component_name %> = (props) => {
         | 
| 3 | 
            +
              return (
         | 
| 4 | 
            +
                <React.Fragment>
         | 
| 5 5 | 
             
            <% attributes.each do |attribute| -%>
         | 
| 6 | 
            -
             | 
| 6 | 
            +
                  <%= attribute[:name].titleize %>: {props.<%= attribute[:name].camelize(:lower) %>}
         | 
| 7 7 | 
             
            <% end -%>
         | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
              }
         | 
| 8 | 
            +
                </React.Fragment>
         | 
| 9 | 
            +
              )
         | 
| 11 10 | 
             
            }
         | 
| 12 11 |  | 
| 13 12 | 
             
            <% if attributes.size > 0 -%>
         | 
| @@ -17,4 +16,5 @@ | |
| 17 16 | 
             
            <% end -%>
         | 
| 18 17 | 
             
            };
         | 
| 19 18 | 
             
            <% end -%>
         | 
| 19 | 
            +
             | 
| 20 20 | 
             
            <%= file_footer %>
         | 
| @@ -1,20 +1,20 @@ | |
| 1 | 
            -
            <%= file_header %> | 
| 1 | 
            +
            <%= file_header %>
         | 
| 2 | 
            +
            function <%= component_name %>(props) {
         | 
| 3 | 
            +
              return (
         | 
| 4 | 
            +
                <React.Fragment>
         | 
| 5 | 
            +
            <% attributes.each do |attribute| -%>
         | 
| 6 | 
            +
                  <%= attribute[:name].titleize %>: {props.<%= attribute[:name].camelize(:lower) %>}
         | 
| 7 | 
            +
            <% end -%>
         | 
| 8 | 
            +
                </React.Fragment>
         | 
| 9 | 
            +
              );
         | 
| 10 | 
            +
            }
         | 
| 11 | 
            +
             | 
| 2 12 | 
             
            <% if attributes.size > 0 -%>
         | 
| 3 | 
            -
             | 
| 13 | 
            +
            <%= file_name.camelize %>.propTypes = {
         | 
| 4 14 | 
             
            <% attributes.each_with_index do |attribute, idx| -%>
         | 
| 5 | 
            -
             | 
| 15 | 
            +
              <%= attribute[:name].camelize(:lower) %>: <%= attribute[:type] %><% if (idx < attributes.length-1) %>,<% end %>
         | 
| 6 16 | 
             
            <% end -%>
         | 
| 7 | 
            -
             | 
| 17 | 
            +
            };
         | 
| 8 18 | 
             
            <% end -%>
         | 
| 9 19 |  | 
| 10 | 
            -
              render: function() {
         | 
| 11 | 
            -
                return (
         | 
| 12 | 
            -
                  <React.Fragment>
         | 
| 13 | 
            -
            <% attributes.each do |attribute| -%>
         | 
| 14 | 
            -
                    <%= attribute[:name].titleize %>: {this.props.<%= attribute[:name].camelize(:lower) %>}
         | 
| 15 | 
            -
            <% end -%>
         | 
| 16 | 
            -
                  </React.Fragment>
         | 
| 17 | 
            -
                );
         | 
| 18 | 
            -
              }
         | 
| 19 | 
            -
            });
         | 
| 20 20 | 
             
            <%= file_footer %>
         | 
| @@ -1,21 +1,27 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "babel/transpiler"
         | 
| 2 4 | 
             
            module React
         | 
| 3 5 | 
             
              module JSX
         | 
| 4 6 | 
             
                # A {React::JSX}-compliant transformer which uses `Babel::Transpiler` to transform JSX.
         | 
| 5 7 | 
             
                class BabelTransformer
         | 
| 6 | 
            -
                  DEPRECATED_OPTIONS = [ | 
| 7 | 
            -
                  DEFAULT_TRANSFORM_OPTIONS = { blacklist: [ | 
| 8 | 
            +
                  DEPRECATED_OPTIONS = %i[harmony strip_types asset_path].freeze
         | 
| 9 | 
            +
                  DEFAULT_TRANSFORM_OPTIONS = { blacklist: ["spec.functionName", "validation.react", "strict"] }.freeze
         | 
| 8 10 | 
             
                  def initialize(options)
         | 
| 9 11 | 
             
                    if (options.keys & DEPRECATED_OPTIONS).any?
         | 
| 10 | 
            -
                      ActiveSupport::Deprecation.warn( | 
| 11 | 
            -
             | 
| 12 | 
            +
                      ActiveSupport::Deprecation.warn(
         | 
| 13 | 
            +
                        <<-MSG
         | 
| 14 | 
            +
                          Setting config.react.jsx_transform_options for :harmony, :strip_types, and :asset_path keys is now deprecated and has no effect with the default Babel Transformer.
         | 
| 15 | 
            +
                          Please use new Babel Transformer options :whitelist, :plugin instead.
         | 
| 16 | 
            +
                        MSG
         | 
| 17 | 
            +
                      )
         | 
| 12 18 | 
             
                    end
         | 
| 13 19 |  | 
| 14 20 | 
             
                    @transform_options = DEFAULT_TRANSFORM_OPTIONS.merge(options)
         | 
| 15 21 | 
             
                  end
         | 
| 16 22 |  | 
| 17 23 | 
             
                  def transform(code)
         | 
| 18 | 
            -
                    Babel::Transpiler.transform(code, @transform_options)[ | 
| 24 | 
            +
                    Babel::Transpiler.transform(code, @transform_options)["code"]
         | 
| 19 25 | 
             
                  end
         | 
| 20 26 | 
             
                end
         | 
| 21 27 | 
             
              end
         |