hyper-component 0.12.3 → 0.99.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 +5 -5
- data/.codeclimate.yml +27 -0
- data/.gitignore +42 -41
- data/.travis.yml +29 -0
- data/CHANGELOG.md +143 -0
- data/DOCS.md +1515 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +244 -193
- data/LICENSE +5 -7
- data/README.md +49 -0
- data/Rakefile +40 -0
- data/hyper-component.gemspec +41 -31
- data/lib/hyper-component.rb +44 -9
- data/lib/rails-helpers/top_level_rails_component.rb +79 -0
- data/lib/react/api.rb +270 -0
- data/lib/react/callbacks.rb +42 -0
- data/lib/react/children.rb +38 -0
- data/lib/react/component.rb +189 -0
- data/lib/react/component/api.rb +70 -0
- data/lib/react/component/base.rb +13 -0
- data/lib/react/component/class_methods.rb +175 -0
- data/lib/react/component/dsl_instance_methods.rb +23 -0
- data/lib/react/component/params.rb +6 -0
- data/lib/react/component/props_wrapper.rb +90 -0
- data/lib/react/component/should_component_update.rb +99 -0
- data/lib/react/component/tags.rb +116 -0
- data/lib/react/config.rb +5 -0
- data/lib/react/element.rb +159 -0
- data/lib/react/event.rb +76 -0
- data/lib/react/ext/hash.rb +9 -0
- data/lib/react/ext/opal-jquery/element.rb +37 -0
- data/lib/react/ext/string.rb +8 -0
- data/lib/react/native_library.rb +87 -0
- data/lib/react/object.rb +15 -0
- data/lib/react/react-source-server.rb +3 -0
- data/lib/react/react-source.rb +17 -0
- data/lib/react/ref_callback.rb +31 -0
- data/lib/react/rendering_context.rb +149 -0
- data/lib/react/server.rb +19 -0
- data/lib/react/state_wrapper.rb +23 -0
- data/lib/react/test.rb +16 -0
- data/lib/react/test/dsl.rb +17 -0
- data/lib/react/test/matchers/render_html_matcher.rb +56 -0
- data/lib/react/test/rspec.rb +15 -0
- data/lib/react/test/session.rb +37 -0
- data/lib/react/test/utils.rb +71 -0
- data/lib/react/to_key.rb +26 -0
- data/lib/react/top_level.rb +110 -0
- data/lib/react/top_level_render.rb +28 -0
- data/lib/react/validator.rb +132 -0
- data/lib/reactive-ruby/component_loader.rb +43 -0
- data/lib/reactive-ruby/isomorphic_helpers.rb +233 -0
- data/lib/reactive-ruby/rails.rb +8 -0
- data/lib/reactive-ruby/rails/component_mount.rb +48 -0
- data/lib/reactive-ruby/rails/controller_helper.rb +14 -0
- data/lib/reactive-ruby/rails/railtie.rb +20 -0
- data/lib/reactive-ruby/serializers.rb +23 -0
- data/lib/reactive-ruby/server_rendering/contextual_renderer.rb +46 -0
- data/lib/reactive-ruby/server_rendering/hyper_asset_container.rb +46 -0
- data/lib/{hyperloop/component → reactive-ruby}/version.rb +1 -1
- data/lib/reactrb/auto-import.rb +27 -0
- data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/components.rb +3 -0
- data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/server_rendering.js +5 -0
- data/misc/generators/reactive_ruby/test_app/templates/assets/javascripts/test_application.rb +2 -0
- data/misc/generators/reactive_ruby/test_app/templates/boot.rb.erb +6 -0
- data/misc/generators/reactive_ruby/test_app/templates/script/rails +5 -0
- data/misc/generators/reactive_ruby/test_app/templates/test_application.rb.erb +13 -0
- data/misc/generators/reactive_ruby/test_app/templates/views/components/hello_world.rb +11 -0
- data/misc/generators/reactive_ruby/test_app/templates/views/components/todo.rb +14 -0
- data/misc/generators/reactive_ruby/test_app/templates/views/layouts/test_layout.html.erb +0 -0
- data/misc/generators/reactive_ruby/test_app/test_app_generator.rb +121 -0
- data/misc/how-component-name-lookup-works.md +145 -0
- data/misc/hyperloop-logo-small-pink.png +0 -0
- data/misc/logo1.png +0 -0
- data/misc/logo2.png +0 -0
- data/misc/logo3.png +0 -0
- data/path_release_steps.md +9 -0
- metadata +260 -37
- data/CODE_OF_CONDUCT.md +0 -49
@@ -0,0 +1,43 @@
|
|
1
|
+
module ReactiveRuby
|
2
|
+
class ComponentLoader
|
3
|
+
attr_reader :v8_context
|
4
|
+
private :v8_context
|
5
|
+
|
6
|
+
def initialize(v8_context)
|
7
|
+
unless v8_context
|
8
|
+
raise ArgumentError.new('Could not obtain ExecJS runtime context')
|
9
|
+
end
|
10
|
+
@v8_context = v8_context
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(file = components)
|
14
|
+
return true if loaded?
|
15
|
+
!!v8_context.eval(opal(file))
|
16
|
+
end
|
17
|
+
|
18
|
+
def load!(file = components)
|
19
|
+
return true if loaded?
|
20
|
+
self.load(file)
|
21
|
+
ensure
|
22
|
+
raise "No HyperReact components found in #{components}" unless loaded?
|
23
|
+
end
|
24
|
+
|
25
|
+
def loaded?
|
26
|
+
!!v8_context.eval('Opal.React !== undefined')
|
27
|
+
rescue ::ExecJS::Error
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def components
|
34
|
+
opts = ::Rails.configuration.react.server_renderer_options
|
35
|
+
return opts[:files].first.gsub(/.js$/,'') if opts && opts[:files]
|
36
|
+
'components'
|
37
|
+
end
|
38
|
+
|
39
|
+
def opal(file)
|
40
|
+
Opal::Sprockets.load_asset(file)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require "react/config"
|
2
|
+
|
3
|
+
module React
|
4
|
+
module IsomorphicHelpers
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
if RUBY_ENGINE != 'opal'
|
10
|
+
def self.load_context(ctx, controller, name = nil)
|
11
|
+
@context = Context.new("#{controller.object_id}-#{Time.now.to_i}", ctx, controller, name)
|
12
|
+
@context.load_opal_context
|
13
|
+
::Rails.logger.debug "************************** React Server Context Initialized #{name} #{Time.now.to_f} *********************************************"
|
14
|
+
@context
|
15
|
+
end
|
16
|
+
else
|
17
|
+
def self.load_context(unique_id = nil, name = nil)
|
18
|
+
# can be called on the client to force re-initialization for testing purposes
|
19
|
+
if !unique_id || !@context || @context.unique_id != unique_id
|
20
|
+
if on_opal_server?
|
21
|
+
`console.history = []` rescue nil
|
22
|
+
message = "************************ React Prerendering Context Initialized #{name} ***********************"
|
23
|
+
else
|
24
|
+
message = "************************ React Browser Context Initialized ****************************"
|
25
|
+
end
|
26
|
+
log(message)
|
27
|
+
@context = Context.new(unique_id)
|
28
|
+
end
|
29
|
+
@context
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.context
|
34
|
+
@context
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.log(message, message_type = :info)
|
38
|
+
message = [message] unless message.is_a? Array
|
39
|
+
|
40
|
+
if (message_type == :info || message_type == :warning) && Hyperloop.env.production?
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
if message_type == :info
|
45
|
+
if on_opal_server?
|
46
|
+
style = 'background: #00FFFF; color: red'
|
47
|
+
else
|
48
|
+
style = 'background: #222; color: #bada55'
|
49
|
+
end
|
50
|
+
message = ["%c" + message[0], style]+message[1..-1]
|
51
|
+
`console.log.apply(console, message)`
|
52
|
+
elsif message_type == :warning
|
53
|
+
`console.warn.apply(console, message)`
|
54
|
+
else
|
55
|
+
`console.error.apply(console, message)`
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if RUBY_ENGINE != 'opal'
|
60
|
+
def self.on_opal_server?
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.on_opal_client?
|
65
|
+
false
|
66
|
+
end
|
67
|
+
else
|
68
|
+
def self.on_opal_server?
|
69
|
+
`typeof Opal.global.document === 'undefined'`
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.on_opal_client?
|
73
|
+
!on_opal_server?
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def log(*args)
|
78
|
+
IsomorphicHelpers.log(*args)
|
79
|
+
end
|
80
|
+
|
81
|
+
def on_opal_server?
|
82
|
+
self.class.on_opal_server?
|
83
|
+
end
|
84
|
+
|
85
|
+
def on_opal_client?
|
86
|
+
self.class.on_opal_client?
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.prerender_footers(controller = nil)
|
90
|
+
footer = Context.prerender_footer_blocks.collect { |block| block.call controller }.join("\n")
|
91
|
+
if RUBY_ENGINE != 'opal'
|
92
|
+
footer = (footer + @context.send_to_opal(:prerender_footers).to_s) if @context
|
93
|
+
footer = footer.html_safe
|
94
|
+
end
|
95
|
+
footer
|
96
|
+
end
|
97
|
+
|
98
|
+
class Context
|
99
|
+
attr_reader :controller
|
100
|
+
attr_reader :unique_id
|
101
|
+
|
102
|
+
def self.define_isomorphic_method(method_name, &block)
|
103
|
+
@@ctx_methods ||= {}
|
104
|
+
@@ctx_methods[method_name] = block
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.before_first_mount_blocks
|
108
|
+
@before_first_mount_blocks ||= []
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.prerender_footer_blocks
|
112
|
+
@prerender_footer_blocks ||= []
|
113
|
+
end
|
114
|
+
|
115
|
+
def initialize(unique_id, ctx = nil, controller = nil, cname = nil)
|
116
|
+
@unique_id = unique_id
|
117
|
+
@cname = cname
|
118
|
+
if RUBY_ENGINE != 'opal'
|
119
|
+
@controller = controller
|
120
|
+
@ctx = ctx
|
121
|
+
if defined? @@ctx_methods
|
122
|
+
@@ctx_methods.each do |method_name, block|
|
123
|
+
@ctx.attach("ServerSideIsomorphicMethod.#{method_name}", proc{|args| block.call(args.to_json)})
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
Hyperloop::Application::Boot.run(context: self)
|
128
|
+
self.class.before_first_mount_blocks.each { |block| block.call(self) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def load_opal_context
|
132
|
+
send_to_opal(:load_context, @unique_id, @cname)
|
133
|
+
end
|
134
|
+
|
135
|
+
def eval(js)
|
136
|
+
@ctx.eval(js) if @ctx
|
137
|
+
end
|
138
|
+
|
139
|
+
def send_to_opal(method_name, *args)
|
140
|
+
return unless @ctx
|
141
|
+
args = [1] if args.length == 0
|
142
|
+
::ReactiveRuby::ComponentLoader.new(@ctx).load!
|
143
|
+
method_args = args.collect do |arg|
|
144
|
+
quarg = "#{arg}".tr('"', "'")
|
145
|
+
"\"#{quarg}\""
|
146
|
+
end.join(', ')
|
147
|
+
@ctx.eval("Opal.React.$const_get('IsomorphicHelpers').$#{method_name}(#{method_args})")
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.register_before_first_mount_block(&block)
|
151
|
+
before_first_mount_blocks << block
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.register_prerender_footer_block(&block)
|
155
|
+
prerender_footer_blocks << block
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
class IsomorphicProcCall
|
160
|
+
|
161
|
+
attr_reader :context
|
162
|
+
|
163
|
+
def result
|
164
|
+
@result.first if @result
|
165
|
+
end
|
166
|
+
|
167
|
+
def initialize(name, block, context, *args)
|
168
|
+
@name = name
|
169
|
+
@context = context
|
170
|
+
block.call(self, *args)
|
171
|
+
@result ||= send_to_server(*args)
|
172
|
+
end
|
173
|
+
|
174
|
+
def when_on_client(&block)
|
175
|
+
@result = [block.call] if IsomorphicHelpers.on_opal_client?
|
176
|
+
end
|
177
|
+
|
178
|
+
def send_to_server(*args)
|
179
|
+
if IsomorphicHelpers.on_opal_server?
|
180
|
+
method_string = "ServerSideIsomorphicMethod." + @name + "(" + args.to_json + ")"
|
181
|
+
@result = [JSON.parse(`eval(method_string)`)]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def when_on_server(&block)
|
186
|
+
@result = [block.call.to_json] unless IsomorphicHelpers.on_opal_client? || IsomorphicHelpers.on_opal_server?
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
module ClassMethods
|
191
|
+
def on_opal_server?
|
192
|
+
IsomorphicHelpers.on_opal_server?
|
193
|
+
end
|
194
|
+
|
195
|
+
def on_opal_client?
|
196
|
+
IsomorphicHelpers.on_opal_client?
|
197
|
+
end
|
198
|
+
|
199
|
+
def log(*args)
|
200
|
+
IsomorphicHelpers.log(*args)
|
201
|
+
end
|
202
|
+
|
203
|
+
def controller
|
204
|
+
IsomorphicHelpers.context.controller
|
205
|
+
end
|
206
|
+
|
207
|
+
def before_first_mount(&block)
|
208
|
+
React::IsomorphicHelpers::Context.register_before_first_mount_block(&block)
|
209
|
+
end
|
210
|
+
|
211
|
+
def prerender_footer(&block)
|
212
|
+
React::IsomorphicHelpers::Context.register_prerender_footer_block(&block)
|
213
|
+
end
|
214
|
+
|
215
|
+
if RUBY_ENGINE != 'opal'
|
216
|
+
def isomorphic_method(name, &block)
|
217
|
+
React::IsomorphicHelpers::Context.send(:define_isomorphic_method, name) do |args_as_json|
|
218
|
+
React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, self, *JSON.parse(args_as_json)).result
|
219
|
+
end
|
220
|
+
end
|
221
|
+
else
|
222
|
+
require 'json'
|
223
|
+
|
224
|
+
def isomorphic_method(name, &block)
|
225
|
+
self.class.send(:define_method, name) do | *args |
|
226
|
+
React::IsomorphicHelpers::IsomorphicProcCall.new(name, block, self, *args).result
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
require 'react-rails'
|
3
|
+
require 'reactive-ruby/server_rendering/hyper_asset_container'
|
4
|
+
require 'reactive-ruby/server_rendering/contextual_renderer'
|
5
|
+
require 'reactive-ruby/rails/component_mount'
|
6
|
+
require 'reactive-ruby/rails/railtie'
|
7
|
+
require 'reactive-ruby/rails/controller_helper'
|
8
|
+
require 'reactive-ruby/component_loader'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ReactiveRuby
|
2
|
+
module Rails
|
3
|
+
class ComponentMount < React::Rails::ComponentMount
|
4
|
+
attr_accessor :controller
|
5
|
+
|
6
|
+
def setup(controller)
|
7
|
+
self.controller = controller
|
8
|
+
end
|
9
|
+
|
10
|
+
def react_component(name, props = {}, options = {}, &block)
|
11
|
+
if options[:prerender] || [:on, 'on', true].include?(Hyperloop.prerendering)
|
12
|
+
options = context_initializer_options(options, name)
|
13
|
+
end
|
14
|
+
props = serialized_props(props, name, controller)
|
15
|
+
result = super(top_level_name, props, options, &block).gsub("\n","")
|
16
|
+
result = result.gsub(/(<script.*<\/script>)<\/div>$/,'</div>\1').html_safe
|
17
|
+
result + footers
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def context_initializer_options(options, name)
|
23
|
+
options[:prerender] = {options[:prerender] => true} unless options[:prerender].is_a? Hash
|
24
|
+
existing_context_initializer = options[:prerender][:context_initializer]
|
25
|
+
|
26
|
+
options[:prerender][:context_initializer] = lambda do |ctx|
|
27
|
+
React::IsomorphicHelpers.load_context(ctx, controller, name)
|
28
|
+
existing_context_initializer.call(ctx) if existing_context_initializer
|
29
|
+
end
|
30
|
+
|
31
|
+
options
|
32
|
+
end
|
33
|
+
|
34
|
+
def serialized_props(props, name, controller)
|
35
|
+
{ render_params: props, component_name: name,
|
36
|
+
controller: controller.class.name.gsub(/Controller$/,"") }.react_serializer
|
37
|
+
end
|
38
|
+
|
39
|
+
def top_level_name
|
40
|
+
'React.TopLevelRailsComponent'
|
41
|
+
end
|
42
|
+
|
43
|
+
def footers
|
44
|
+
React::IsomorphicHelpers.prerender_footers(controller)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
|
3
|
+
module ActionController
|
4
|
+
# adds render_component helper to ActionControllers
|
5
|
+
class Base
|
6
|
+
def render_component(*args)
|
7
|
+
@component_name = (args[0].is_a? Hash) || args.empty? ? params[:action].camelize : args.shift
|
8
|
+
@render_params = args.shift || {}
|
9
|
+
options = args[0] || {}
|
10
|
+
render inline: '<%= react_component @component_name, @render_params %>',
|
11
|
+
layout: options.key?(:layout) ? options[:layout].to_s : :default
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ReactiveRuby
|
2
|
+
module Rails
|
3
|
+
class Railtie < ::Rails::Railtie
|
4
|
+
config.before_configuration do |app|
|
5
|
+
app.config.assets.enabled = true
|
6
|
+
app.config.assets.paths << ::Rails.root.join('app', 'views').to_s
|
7
|
+
app.config.react.server_renderer = ReactiveRuby::ServerRendering::ContextualRenderer
|
8
|
+
app.config.react.view_helper_implementation = ReactiveRuby::Rails::ComponentMount
|
9
|
+
ReactiveRuby::ServerRendering::ContextualRenderer.asset_container_class = ReactiveRuby::ServerRendering::HyperAssetContainer
|
10
|
+
end
|
11
|
+
config.after_initialize do
|
12
|
+
class ::HyperloopController < ::ApplicationController
|
13
|
+
def action_missing(name)
|
14
|
+
render_component
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
[FalseClass, Float, Integer, NilClass, String, Symbol, Time, TrueClass].each do |klass|
|
2
|
+
klass.send(:define_method, :react_serializer) do
|
3
|
+
as_json
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0')
|
8
|
+
[Bignum, Fixnum].each do |klass|
|
9
|
+
klass.send(:define_method, :react_serializer) do
|
10
|
+
as_json
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
BigDecimal.send(:define_method, :react_serializer) { as_json } rescue nil
|
16
|
+
|
17
|
+
Array.send(:define_method, :react_serializer) do
|
18
|
+
self.collect { |e| e.react_serializer }.as_json
|
19
|
+
end
|
20
|
+
|
21
|
+
Hash.send(:define_method, :react_serializer) do
|
22
|
+
Hash[*self.collect { |key, value| [key, value.react_serializer] }.flatten(1)].as_json
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ReactiveRuby
|
2
|
+
module ServerRendering
|
3
|
+
def self.context_instance_name
|
4
|
+
'@context'
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.context_instance_for(context)
|
8
|
+
context.instance_variable_get(context_instance_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
class ContextualRenderer < React::ServerRendering::BundleRenderer
|
12
|
+
def initialize(options = {})
|
13
|
+
super(options)
|
14
|
+
ComponentLoader.new(v8_context).load
|
15
|
+
end
|
16
|
+
|
17
|
+
def before_render(*args)
|
18
|
+
# the base class clears the log history... we don't want that as it is taken
|
19
|
+
# care of in IsomorphicHelpers.load_context
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(component_name, props, prerender_options)
|
23
|
+
if prerender_options.is_a?(Hash)
|
24
|
+
if !v8_runtime? && prerender_options[:context_initializer]
|
25
|
+
raise React::ServerRendering::PrerenderError.new(component_name, props, "you must use 'mini_racer' with the prerender[:context] option") unless v8_runtime?
|
26
|
+
else
|
27
|
+
prerender_options[:context_initializer].call v8_context
|
28
|
+
prerender_options = prerender_options[:static] ? :static : true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
super(component_name, props, prerender_options)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def v8_runtime?
|
38
|
+
ExecJS.runtime.name == 'mini_racer (V8)'
|
39
|
+
end
|
40
|
+
|
41
|
+
def v8_context
|
42
|
+
@v8_context ||= ReactiveRuby::ServerRendering.context_instance_for(@context)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'react/server_rendering/environment_container'
|
2
|
+
require 'react/server_rendering/manifest_container'
|
3
|
+
require 'react/server_rendering/webpacker_manifest_container'
|
4
|
+
|
5
|
+
module ReactiveRuby
|
6
|
+
module ServerRendering
|
7
|
+
class HyperTestAssetContainer
|
8
|
+
def find_asset(logical_path)
|
9
|
+
::Rails.cache.read(logical_path)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class HyperAssetContainer
|
14
|
+
def initialize
|
15
|
+
@ass_containers = []
|
16
|
+
if assets_precompiled?
|
17
|
+
@ass_containers << React::ServerRendering::ManifestContainer.new if React::ServerRendering::ManifestContainer.compatible?
|
18
|
+
else
|
19
|
+
@ass_containers << React::ServerRendering::EnvironmentContainer.new if ::Rails.application.assets
|
20
|
+
end
|
21
|
+
if React::ServerRendering::WebpackerManifestContainer.compatible?
|
22
|
+
@ass_containers << React::ServerRendering::WebpackerManifestContainer.new
|
23
|
+
end
|
24
|
+
@ass_containers << HyperTestAssetContainer.new if ::Rails.env.test?
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_asset(logical_path)
|
28
|
+
@ass_containers.each do |ass|
|
29
|
+
begin
|
30
|
+
asset = ass.find_asset(logical_path)
|
31
|
+
return asset if asset && asset != ''
|
32
|
+
rescue
|
33
|
+
next # no asset found, try the next container
|
34
|
+
end
|
35
|
+
end
|
36
|
+
raise "No asset found for #{logical_path}, tried: #{@ass_containers.map { |c| c.class.name }.join(', ')}"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def assets_precompiled?
|
42
|
+
!::Rails.application.config.assets.compile
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|