isomorfeus-preact 10.6.35 → 10.6.39

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06de7c22eb8524e87e402efb9580b29571de8605c2277e7055e2e60d2f64b901
4
- data.tar.gz: 29c9ee7246ef0a4e0a15433990ff00dd0e5295c6f1ed7a4d10ef7d0dc33f84c9
3
+ metadata.gz: 2b4f34a628322571ed50c6923c8b129c750ce09b90953a9e4512f609e4424efa
4
+ data.tar.gz: b9e99d2865e4c14e451b22b0c3f993b3500c724a26e4c5fb66f3213385c15ac1
5
5
  SHA512:
6
- metadata.gz: 25c7696c2f613a637a452ea4ccb4e3c471de1a2f471f79de667a47a6fb5c26c419124e25b145a3214327866f02819bbdb940d341e7bce60e3399a36edcb6a7af
7
- data.tar.gz: 0a4e8945291167adf81552877fc01aa41b41d7aeb639f1a17be3822cc6b43e9a39a07a0b001311d456ba4dfbfbb5f7f4a59fc498ac2fbf5d8505ee37bafbf106
6
+ metadata.gz: d00ca6d3d6f0a21954627f9c0204617abf73729b1c7f1b89976e4273d9f8080a7a532d8dfdd53d6248c91593910698ed2c695630373c21a42229592282fa6f73
7
+ data.tar.gz: 3d653b10253888d69175a077959a8d45f9672a8e5f540e3f97e53efebebe2b5b829ea6436fdd598962e229b69862b868bc493c74cb092e7ed50fd188b79e20a1
@@ -83,7 +83,7 @@ module Isomorfeus
83
83
 
84
84
  def start_app!
85
85
  Isomorfeus.zeitwerk.setup
86
- Isomorfeus::TopLevel.mount!
86
+ Isomorfeus::TopLevel.mount! unless on_ssr?
87
87
  end
88
88
 
89
89
  def force_render
@@ -4,9 +4,9 @@ module Isomorfeus
4
4
  base.include Isomorfeus::AssetManager::ViewHelper
5
5
  end
6
6
 
7
- def cached_mount_component(component_name, props = {}, asset_key = 'ssr.js', skip_ssr: false, use_ssr: false, max_passes: 4)
7
+ def cached_mount_component(component_name, props = {}, asset_key = 'ssr.js', skip_ssr: false, use_ssr: false, max_passes: 4, refresh: false)
8
8
  key = "#{component_name}#{props}#{asset}"
9
- if Isomorfeus.production?
9
+ if !Isomorfeus.development? && !refresh
10
10
  render_result, @ssr_response_status, @ssr_styles = component_cache.fetch(key)
11
11
  return render_result if render_result
12
12
  end
@@ -17,19 +17,13 @@ module Isomorfeus
17
17
  end
18
18
 
19
19
  def mount_component(component_name, props = {}, asset_key = 'ssr.js', skip_ssr: false, use_ssr: false, max_passes: 4)
20
+ ssr_start_time = Time.now if Isomorfeus.development?
20
21
  @ssr_response_status = nil
21
22
  @ssr_styles = nil
22
- thread_id_asset = "#{Thread.current.object_id}#{asset_key}"
23
23
  render_result = "<div data-iso-env=\"#{Isomorfeus.env}\" data-iso-root=\"#{component_name}\" data-iso-props='#{Oj.dump(props, mode: :strict)}'"
24
24
  if !skip_ssr && (Isomorfeus.server_side_rendering || use_ssr)
25
+ thread_id_asset = "#{Thread.current.object_id}#{asset_key}"
25
26
  if Isomorfeus.development?
26
- # always create a new context, effectively reloading code
27
- # delete the existing context first, saves memory
28
- if Isomorfeus.ssr_contexts.key?(thread_id_asset)
29
- uuid = Isomorfeus.ssr_contexts[thread_id_asset].instance_variable_get(:@uuid)
30
- runtime = Isomorfeus.ssr_contexts[thread_id_asset].instance_variable_get(:@runtime)
31
- runtime.vm.delete_context(uuid)
32
- end
33
27
  begin
34
28
  init_speednode_context(asset_key, thread_id_asset)
35
29
  rescue Exception => e
@@ -41,7 +35,7 @@ module Isomorfeus
41
35
  end
42
36
  end
43
37
 
44
- start_time = Time.now if Isomorfeus.development?
38
+ ctx = Isomorfeus.ssr_contexts[thread_id_asset]
45
39
  pass = 0
46
40
  # if location_host and scheme are given and if Transport is loaded, connect and then render,
47
41
  # otherwise do not render because only one pass is required
@@ -53,110 +47,84 @@ module Isomorfeus
53
47
  # build javascript for rendering first pass
54
48
  # it will initialize buffers to guard against leaks, maybe caused by previous exceptions
55
49
  javascript = <<~JAVASCRIPT
56
- global.Opal.Preact.render_buffer = [];
57
- global.Opal.Preact.active_components = [];
58
- global.Opal.Preact.active_redux_components = [];
59
- global.FirstPassFinished = false;
60
- global.Exception = false;
61
- global.IsomorfeusSessionId = '#{Thread.current[:isomorfeus_session_id]}';
62
- global.Opal.Isomorfeus['$env=']('#{Isomorfeus.env}');
63
- if (typeof global.Opal.Isomorfeus["$current_locale="] === 'function') {
64
- global.Opal.Isomorfeus["$current_locale="]('#{props[:locale]}');
65
- } else if (typeof global.Opal.Isomorfeus["$negotiated_locale="] === 'function') { // remove later on
66
- global.Opal.Isomorfeus["$negotiated_locale="]('#{props[:locale]}');
67
- }
68
- global.Opal.Isomorfeus['$force_init!']();
69
- global.Opal.Isomorfeus['$ssr_response_status='](200);
70
- global.Opal.Isomorfeus.TopLevel['$ssr_route_path=']('#{props[:location]}');
71
- let api_ws_path = '#{api_ws_path}';
72
- let exception;
73
- if (typeof global.Opal.Isomorfeus.Transport !== 'undefined' && api_ws_path !== '') {
74
- global.Opal.Isomorfeus.TopLevel["$transport_ws_url="]("#{transport_ws_url}");
75
- global.Opal.send(global.Opal.Isomorfeus.Transport.$promise_connect(global.IsomorfeusSessionId), 'then', [], ($$1 = function(){
76
- try {
77
- global.Opal.Isomorfeus.TopLevel.$render_component_to_string('#{component_name}', #{Oj.dump(props, mode: :strict)});
78
- global.FirstPassFinished = 'transport';
79
- } catch (e) {
80
- global.Exception = e;
81
- global.FirstPassFinished = 'transport';
82
- }
83
- }, $$1.$$s = this, $$1.$$arity = 0, $$1))
84
- return false;
85
- } else { global.FirstPassFinished = true; return true; };
50
+ return Opal.Isomorfeus.SSR.first_pass('#{Thread.current[:isomorfeus_session_id]}', '#{Isomorfeus.env}', '#{props[:locale]}', '#{props[:location]}', '#{api_ws_path}', '#{transport_ws_url}', '#{component_name}', #{Oj.dump(props, mode: :strict)})
86
51
  JAVASCRIPT
52
+
53
+ finished = false
87
54
  # execute first render pass
88
55
  begin
89
- first_pass_skipped = Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
56
+ pass += 1
57
+ has_transport, has_store, need_further_pass, exception = ctx.exec(javascript)
58
+ Isomorfeus.raise_error(message: "Server Side Rendering: #{exception['message']}", stack: exception['stack']) if exception
90
59
  rescue Exception => e
91
60
  Isomorfeus.raise_error(error: e)
92
61
  end
93
- # wait for first pass to finish
94
- unless first_pass_skipped
95
- pass += 1
96
- first_pass_finished, exception = Isomorfeus.ssr_contexts[thread_id_asset].exec('return [global.FirstPassFinished, global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false ]')
62
+
63
+ if has_transport
64
+ # wait for first pass to finish
65
+ first_pass_finished, need_further_pass, exception = ctx.eval_script(key: :first_pass_check)
97
66
  Isomorfeus.raise_error(message: "Server Side Rendering: #{exception['message']}", stack: exception['stack']) if exception
98
67
  unless first_pass_finished
99
68
  start_time = Time.now
100
69
  while !first_pass_finished
101
70
  break if (Time.now - start_time) > 10
102
- sleep 0.01
103
- first_pass_finished = Isomorfeus.ssr_contexts[thread_id_asset].exec('return global.FirstPassFinished')
71
+ sleep 0.005
72
+ first_pass_finished, need_further_pass, exception = ctx.eval_script(key: :first_pass_check)
73
+ Isomorfeus.raise_error(message: "Server Side Rendering: #{exception['message']}", stack: exception['stack']) if exception
104
74
  end
105
75
  end
106
- # wait for transport requests to finish
107
- if first_pass_finished == 'transport'
108
- transport_busy = Isomorfeus.ssr_contexts[thread_id_asset].exec('return global.Opal.Isomorfeus.Transport["$busy?"]()')
109
- if transport_busy
110
- start_time = Time.now
111
- while transport_busy
112
- break if (Time.now - start_time) > 5
113
- sleep 0.01
114
- transport_busy = Isomorfeus.ssr_contexts[thread_id_asset].exec('return global.Opal.Isomorfeus.Transport["$busy?"]()')
115
- end
76
+
77
+ # wait for transport to settle
78
+ transport_busy = ctx.eval_script(key: :transport_busy)
79
+ if transport_busy
80
+ start_time = Time.now
81
+ while transport_busy
82
+ break if (Time.now - start_time) > 5
83
+ sleep 0.005
84
+ transport_busy = ctx.eval_script(key: :transport_busy)
116
85
  end
117
86
  end
118
87
  end
119
- # build javascript for additional render passes
120
- # guard against leaks from first pass, maybe because of a exception
121
- javascript = <<~JAVASCRIPT
122
- global.Opal.Preact.render_buffer = [];
123
- global.Opal.Preact.active_components = [];
124
- global.Opal.Preact.active_redux_components = [];
125
- global.Exception = false;
126
- let rendered_tree;
127
- let ssr_styles;
128
- let component;
129
- try {
130
- rendered_tree = global.Opal.Isomorfeus.TopLevel.$render_component_to_string('#{component_name}', #{Oj.dump(props, mode: :strict)});
131
- } catch (e) {
132
- global.Exception = e;
133
- }
134
- let application_state = global.Opal.Isomorfeus.store.native.getState();
135
- let still_busy = (#{pass}<2) ? global.Opal.Isomorfeus.store['$recently_dispatched?']() : false;
136
- if (typeof global.Opal.Isomorfeus.Transport !== 'undefined' && global.Opal.Isomorfeus.Transport["$busy?"]()) { still_busy = true; }
137
- if (typeof global.NanoCSSInstance !== 'undefined') { ssr_styles = global.NanoCSSInstance.raw }
138
- return [rendered_tree, application_state, ssr_styles, global.Opal.Isomorfeus['$ssr_response_status'](), still_busy, global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false];
139
- JAVASCRIPT
140
- # execute further render passes
141
- pass += 1
142
- rendered_tree, application_state, @ssr_styles, @ssr_response_status, still_busy, exception = Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
143
- start_time = Time.now
144
- while still_busy
145
- break if (Time.now - start_time) > 5
146
- while still_busy
147
- break if (Time.now - start_time) > 4
148
- sleep 0.01
149
- still_busy = Isomorfeus.ssr_contexts[thread_id_asset].exec('return (typeof global.Opal.Isomorfeus.Transport !== "undefined") ? global.Opal.Isomorfeus.Transport["$busy?"]() : false')
88
+
89
+ if !need_further_pass
90
+ rendered_tree, application_state, @ssr_styles, @ssr_response_status, exception = ctx.eval_script(key: :first_pass_result)
91
+ Isomorfeus.raise_error(message: "Server Side Rendering: #{exception['message']}", stack: exception['stack']) if exception
92
+ else
93
+ start_time = Time.now
94
+ script_key = if has_transport && has_store
95
+ :sill_busy
96
+ elsif has_transport
97
+ :transport_busy
98
+ elsif has_store
99
+ :store_busy
100
+ else
101
+ nil
102
+ end
103
+ while need_further_pass
104
+ # execute further render passes
105
+ javascript = <<~JAVASCRIPT
106
+ return Opal.Isomorfeus.SSR.further_pass('#{component_name}', #{Oj.dump(props, mode: :strict)})
107
+ JAVASCRIPT
108
+ pass += 1
109
+ rendered_tree, application_state, @ssr_styles, @ssr_response_status, need_further_pass, exception = ctx.exec(javascript)
110
+ Isomorfeus.raise_error(message: "Server Side Rendering: #{exception['message']}", stack: exception['stack']) if exception
111
+ if need_further_pass && script_key
112
+ break if (Time.now - start_time) > 5
113
+ need_further_pass = ctx.eval_script(key: script_key)
114
+ while need_further_pass
115
+ break if (Time.now - start_time) > 4
116
+ sleep 0.01
117
+ need_further_pass = ctx.eval_script(key: script_key)
118
+ end
119
+ break if pass >= max_passes
120
+ else
121
+ break
122
+ end
150
123
  end
151
- pass += 1
152
- rendered_tree, application_state, @ssr_styles, @ssr_response_status, still_busy, exception = Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
153
- break if pass >= max_passes
154
124
  end
155
- javascript = <<~JAVASCRIPT
156
- if (typeof global.Opal.Isomorfeus.Transport !== 'undefined') { global.Opal.Isomorfeus.Transport.$disconnect(); }
157
- JAVASCRIPT
158
- Isomorfeus.ssr_contexts[thread_id_asset].exec(javascript)
159
- Isomorfeus.raise_error(message: exception['message'], stack: exception['stack']) if exception
125
+
126
+ ctx.eval_script(key: :transport_disconnect) if has_transport
127
+
160
128
  render_result << " data-iso-hydrated='true'" if rendered_tree
161
129
  if Isomorfeus.respond_to?(:current_user) && Isomorfeus.current_user && !Isomorfeus.current_user.anonymous?
162
130
  render_result << " data-iso-usid=#{Oj.dump(Isomorfeus.current_user.sid, mode: :strict)}"
@@ -170,10 +138,10 @@ module Isomorfeus
170
138
  render_result << " data-iso-nloc='#{props[:locale]}'>"
171
139
  end
172
140
  render_result << '</div>'
173
- if Isomorfeus.server_side_rendering
141
+ if Isomorfeus.server_side_rendering && !skip_ssr
174
142
  render_result = "<script type='application/javascript'>\nServerSideRenderingStateJSON = #{Oj.dump(application_state, mode: :strict)}\n</script>\n" << render_result
143
+ puts "PreactViewHelper Server Side Rendering rendered #{pass} passes and took ~#{((Time.now - ssr_start_time)*1000).to_i}ms" if Isomorfeus.development?
175
144
  end
176
- STDERR.puts "PreactViewHelper Server Side Rendering rendered #{pass} passes and took ~#{((Time.now - start_time)*1000).to_i}ms" if Isomorfeus.development? && !skip_ssr
177
145
  render_result
178
146
  end
179
147
 
@@ -198,8 +166,32 @@ module Isomorfeus
198
166
  def init_speednode_context(asset_key, thread_id_asset)
199
167
  asset = Isomorfeus.assets[asset_key]
200
168
  raise "#{self.class.name}: Asset not found: #{asset_key}" unless asset
201
- asset_manager.transition(asset_key, asset)
202
- Isomorfeus.ssr_contexts[thread_id_asset] = ExecJS.permissive_compile(asset.bundle)
169
+ if !Isomorfeus.ssr_contexts.key?(thread_id_asset) || !asset.bundled?
170
+ if Isomorfeus.ssr_contexts.key?(thread_id_asset)
171
+ uuid = Isomorfeus.ssr_contexts[thread_id_asset].instance_variable_get(:@uuid)
172
+ runtime = Isomorfeus.ssr_contexts[thread_id_asset].instance_variable_get(:@runtime)
173
+ runtime.vm.delete_context(uuid)
174
+ end
175
+ asset_manager.transition(asset_key, asset)
176
+ Isomorfeus.ssr_contexts[thread_id_asset] = ExecJS.permissive_compile(asset.bundle)
177
+ ctx = Isomorfeus.ssr_contexts[thread_id_asset]
178
+ ctx.exec(top_level_mod)
179
+ ctx.exec(ssr_mod)
180
+ ctx.add_script(key: :first_pass_check, source: '[global.FirstPassFinished, global.NeedFurtherPass, global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false ]')
181
+ ctx.add_script(key: :first_pass_result, source: 'Opal.Isomorfeus.SSR.first_pass_result()')
182
+ ctx.add_script(key: :still_busy, source: 'let nfp = global.Opal.Isomorfeus.Transport["$busy?"]() || global.Opal.Isomorfeus.store["$recently_dispatched?"](); (nfp == nil) ? false : nfp;')
183
+ ctx.add_script(key: :store_busy, source: 'let nfp = global.Opal.Isomorfeus.store["$recently_dispatched?"](); (nfp == nil) ? false : nfp;')
184
+ ctx.add_script(key: :transport_busy, source: 'global.Opal.Isomorfeus.Transport["$busy?"]()')
185
+ ctx.add_script(key: :transport_disconnect, source: 'global.Opal.Isomorfeus.Transport.$disconnect()')
186
+ end
187
+ end
188
+
189
+ def ssr_mod
190
+ @_ssr_mod ||= Opal.compile(File.read(File.expand_path(File.join(File.dirname(__FILE__), 'ssr.rb'))))
191
+ end
192
+
193
+ def top_level_mod
194
+ @_top_level_mod ||= Opal.compile(File.read(File.expand_path(File.join(File.dirname(__FILE__), 'top_level_ssr.rb'))))
203
195
  end
204
196
  end
205
197
  end
@@ -0,0 +1,75 @@
1
+ module Isomorfeus
2
+ module SSR
3
+ %x{
4
+ self.first_pass = function(session_id, env, locale, location, api_ws_path, transport_ws_url, component_name, props) {
5
+ global.Opal.Preact.render_buffer = [];
6
+ global.Opal.Preact.active_components = [];
7
+ global.Opal.Preact.active_redux_components = [];
8
+ global.FirstPassFinished = false;
9
+ global.NeedFurtherPass = false;
10
+ global.RenderedTree = '';
11
+ global.Exception = false;
12
+ global.IsomorfeusSessionId = session_id;
13
+ global.HasTransport = (typeof global.Opal.Isomorfeus.Transport !== 'undefined') && (api_ws_path !== '');
14
+ global.HasStore = typeof global.Opal.Isomorfeus.store !== 'undefined';
15
+ global.Opal.Isomorfeus['$env='](env);
16
+ if (typeof global.Opal.Isomorfeus["$current_locale="] === 'function') { global.Opal.Isomorfeus["$current_locale="](locale); }
17
+ global.Opal.Isomorfeus['$force_init!']();
18
+ global.Opal.Isomorfeus['$ssr_response_status='](200);
19
+ global.Opal.Isomorfeus.TopLevel['$ssr_route_path='](location);
20
+ if (global.HasTransport) {
21
+ global.Opal.Isomorfeus.TopLevel["$transport_ws_url="](transport_ws_url);
22
+ global.Opal.send(global.Opal.Isomorfeus.Transport.$promise_connect(global.IsomorfeusSessionId), 'then', [], ($$1 = function(){
23
+ try {
24
+ global.RenderedTree = global.Opal.Isomorfeus.TopLevel.$render_component_to_string(component_name, props);
25
+ let nfp = global.Opal.Isomorfeus.Transport["$busy?"]() || global.Opal.Isomorfeus.store['$recently_dispatched?']();
26
+ global.NeedFurtherPass = (nfp == nil) ? false : nfp;
27
+ global.FirstPassFinished = false;
28
+ } catch (e) {
29
+ global.Exception = e;
30
+ global.NeedFurtherPass = false;
31
+ }
32
+ }, $$1.$$s = this, $$1.$$arity = 0, $$1))
33
+ } else {
34
+ try {
35
+ global.RenderedTree = global.Opal.Isomorfeus.TopLevel.$render_component_to_string(component_name, props);
36
+ if (global.HasStore) {
37
+ let nfp = global.Opal.Isomorfeus.store['$recently_dispatched?']();
38
+ global.NeedFurtherPass = (nfp == nil) ? false : nfp;
39
+ }
40
+ } catch (e) {
41
+ global.Exception = e;
42
+ global.NeedFurtherPass = false;
43
+ }
44
+ };
45
+ return [global.HasTransport, global.HasStore, global.NeedFurtherPass, global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false];
46
+ }
47
+
48
+ self.first_pass_result = function() {
49
+ let ssr_styles;
50
+ let application_state = global.Opal.Isomorfeus.store.native.getState();
51
+ if (typeof global.NanoCSSInstance !== 'undefined') { ssr_styles = global.NanoCSSInstance.raw }
52
+ return [global.RenderedTree, application_state, ssr_styles, global.Opal.Isomorfeus['$ssr_response_status'](), global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false];
53
+ }
54
+
55
+ self.further_pass = function(component_name, props) {
56
+ global.Opal.Preact.render_buffer = [];
57
+ global.Opal.Preact.active_components = [];
58
+ global.Opal.Preact.active_redux_components = [];
59
+ global.Exception = false;
60
+ let rendered_tree;
61
+ let ssr_styles;
62
+ try {
63
+ rendered_tree = global.Opal.Isomorfeus.TopLevel.$render_component_to_string(component_name, props);
64
+ } catch (e) {
65
+ global.Exception = e;
66
+ }
67
+ let application_state = global.Opal.Isomorfeus.store.native.getState();
68
+ if (typeof global.NanoCSSInstance !== 'undefined') { ssr_styles = global.NanoCSSInstance.raw }
69
+ let nfp = (global.HasTransport && global.Opal.Isomorfeus.Transport["$busy?"]()) || (global.HasStore && global.Opal.Isomorfeus.store["$recently_dispatched?"]());
70
+ global.NeedFurtherPass = (nfp == nil) ? false : nfp;
71
+ return [rendered_tree, application_state, ssr_styles, global.Opal.Isomorfeus['$ssr_response_status'](), global.NeedFurtherPass, global.Exception ? { message: global.Exception.message, stack: global.Exception.stack } : false];
72
+ }
73
+ }
74
+ end
75
+ end
@@ -1,7 +1,7 @@
1
1
  module Isomorfeus
2
2
  class TopLevel
3
3
  class << self
4
- if on_browser? # execution environment
4
+ if on_browser?
5
5
  def mount!
6
6
  Isomorfeus.init
7
7
  Isomorfeus::TopLevel.on_ready do
@@ -94,29 +94,7 @@ module Isomorfeus
94
94
  hydrated ? Preact.hydrate(top, element) : Preact.render(top, element)
95
95
  Isomorfeus.top_component = top
96
96
  end
97
- else # execution environment
98
- attr_accessor :ssr_route_path
99
- attr_accessor :transport_ws_url
100
-
101
- def mount!
102
- # nothing, but keep it for compatibility with browser
103
- end
104
-
105
- def render_component_to_string(component_name, props)
106
- component = nil
107
- %x{
108
- if (typeof component_name === 'string' || component_name instanceof String) {
109
- component = component_name.split(".").reduce(function(o, x) {
110
- return (o !== null && typeof o[x] !== "undefined" && o[x] !== null) ? o[x] : null;
111
- }, Opal.global)
112
- } else {
113
- component = component_name;
114
- }
115
- }
116
- component = Isomorfeus.cached_component_class(component_name) unless component
117
- Preact.render_to_string(Preact.create_element(component, `Opal.Hash.$new(props)`))
118
- end
119
- end # execution environment
97
+ end
120
98
  end
121
99
  end
122
100
  end
@@ -0,0 +1,23 @@
1
+ module Isomorfeus
2
+ class TopLevel
3
+ class << self
4
+ attr_accessor :ssr_route_path
5
+ attr_accessor :transport_ws_url
6
+
7
+ def render_component_to_string(component_name, props)
8
+ component = nil
9
+ %x{
10
+ if (typeof component_name === 'string' || component_name instanceof String) {
11
+ component = component_name.split(".").reduce(function(o, x) {
12
+ return (o !== null && typeof o[x] !== "undefined" && o[x] !== null) ? o[x] : null;
13
+ }, Opal.global)
14
+ } else {
15
+ component = component_name;
16
+ }
17
+ }
18
+ component = Isomorfeus.cached_component_class(component_name) unless component
19
+ Preact.render_to_string(Preact.create_element(component, `Opal.Hash.$new(props)`))
20
+ end
21
+ end
22
+ end
23
+ end
@@ -81,6 +81,7 @@ else
81
81
  require 'uri'
82
82
  require 'oj'
83
83
  require 'opal'
84
+ require 'opal/compiler'
84
85
  require 'opal-activesupport'
85
86
  require 'opal-zeitwerk'
86
87
  require 'isomorfeus-speednode'
@@ -1,10 +1,7 @@
1
1
  module LucidComponent
2
2
  class AppStoreProxy
3
- def initialize(component_instance)
4
- if component_instance
5
- @native = component_instance.to_n
6
- @component_instance = component_instance
7
- end
3
+ def initialize(native)
4
+ @native = native
8
5
  end
9
6
 
10
7
  def [](key)
@@ -22,10 +19,8 @@ module LucidComponent
22
19
  Isomorfeus.store.collect_and_defer_dispatch(action)
23
20
  else
24
21
  # check if we have a component local state value
25
- if @native && `#@native.props.iso_store`
26
- if `#@native.props.iso_store.application_state && #@native.props.iso_store.application_state.hasOwnProperty(key)`
27
- return @native.JS[:props].JS[:iso_store].JS[:application_state].JS[key]
28
- end
22
+ if `#@native?.props?.iso_store?.application_state?.hasOwnProperty?.(key)`
23
+ return `#@native.props.iso_store.application_state[key]`
29
24
  else
30
25
  return AppStore[key]
31
26
  end
@@ -1,11 +1,8 @@
1
1
  module LucidComponent
2
2
  class ClassStoreProxy
3
- def initialize(component_name, component_instance = nil, native = nil)
3
+ def initialize(component_name, native = nil)
4
4
  @component_name = component_name
5
- if component_instance
6
- @native = native
7
- @component_instance = component_instance
8
- end
5
+ @native = native
9
6
  end
10
7
 
11
8
  def [](key)
@@ -24,12 +21,8 @@ module LucidComponent
24
21
  else
25
22
  # get class state
26
23
  # check if we have a component local state value
27
- if @native && @native.JS[:props].JS[:iso_store]
28
- if @native.JS[:props].JS[:iso_store].JS[:class_state] &&
29
- @native.JS[:props].JS[:iso_store].JS[:class_state].JS[@component_name] &&
30
- @native.JS[:props].JS[:iso_store].JS[:class_state].JS[@component_name].JS.hasOwnProperty(key)
31
- return @native.JS[:props].JS[:iso_store].JS[:class_state].JS[@component_name].JS[key]
32
- end
24
+ if `#@native?.props?.iso_store?.class_state?.[#@component_name]?.hasOwnProperty?.(key)`
25
+ return `#@native.props.iso_store.class_state[#@component_name][key]`
33
26
  else
34
27
  a_state = Isomorfeus.store.get_state
35
28
  if a_state.key?(:class_state) && a_state[:class_state].key?(@component_name) && a_state[:class_state][@component_name].key?(key)
@@ -1,8 +1,8 @@
1
1
  module LucidComponent::Initializer
2
2
  def initialize(native_component)
3
3
  @native = native_component
4
- @app_store = LucidComponent::AppStoreProxy.new(self)
5
- @class_store = LucidComponent::ClassStoreProxy.new(self.class.to_s, self, @native)
4
+ @app_store = LucidComponent::AppStoreProxy.new(@native)
5
+ @class_store = LucidComponent::ClassStoreProxy.new(self.class.to_s, @native)
6
6
  @props = `Opal.Preact.Props.$new(#@native)`
7
7
  @state = `Opal.Preact.State.$new(#@native)`
8
8
  end
@@ -3,6 +3,6 @@ module LucidFunc::Initializer
3
3
  self.JS[:native_props] = `{ props: null }`
4
4
  @native_props = `Opal.Preact.Props.$new(#{self})`
5
5
  @app_store = LucidComponent::AppStoreProxy.new(self)
6
- @class_store = LucidComponent::ClassStoreProxy.new(self.class.to_s, self, self)
6
+ @class_store = LucidComponent::ClassStoreProxy.new(self.class.to_s, self)
7
7
  end
8
8
  end
@@ -1,3 +1,3 @@
1
1
  module Preact
2
- VERSION = '10.6.35'
2
+ VERSION = '10.6.39'
3
3
  end
data/lib/preact.rb CHANGED
@@ -196,11 +196,12 @@ module Preact
196
196
  };
197
197
 
198
198
  self.internal_render = function(component, props, string_child, block) {
199
+ const oper = Opal.global.Preact;
199
200
  const operabu = self.render_buffer;
200
201
  let native_props;
201
202
  if (props && props !== nil) { native_props = self.to_native_preact_props(props); }
202
203
  if (string_child) {
203
- operabu[operabu.length - 1].push(Opal.global.Preact.createElement(component, native_props, string_child));
204
+ operabu[operabu.length - 1].push(oper.createElement(component, native_props, string_child));
204
205
  } else if (block && block !== nil) {
205
206
  operabu.push([]);
206
207
  // console.log("internal_render pushed", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString());
@@ -208,19 +209,17 @@ module Preact
208
209
  if (block_result && block_result !== nil) { Opal.Preact.render_block_result(block_result); }
209
210
  // console.log("internal_render popping", Opal.Preact.render_buffer, Opal.Preact.render_buffer.toString());
210
211
  let children = operabu.pop();
211
- operabu[operabu.length - 1].push(Opal.global.Preact.createElement.apply(this, [component, native_props].concat(children)));
212
+ operabu[operabu.length - 1].push(oper.createElement.apply(this, [component, native_props].concat(children)));
212
213
  } else {
213
- operabu[operabu.length - 1].push(Opal.global.Preact.createElement(component, native_props));
214
+ operabu[operabu.length - 1].push(oper.createElement(component, native_props));
214
215
  }
215
216
  };
216
217
 
217
218
  self.deep_force_update = function(vnode) {
218
- if(vnode) {
219
- if (vnode.__c && vnode.__c.forceUpdate) { vnode.__c.forceUpdate(); }
220
- if (vnode.__k) {
221
- for (let i=0; i<vnode.__k.length; i++) {
222
- self.deep_force_update(vnode.__k[i]);
223
- }
219
+ vnode?.__c?.forceUpdate?.();
220
+ if (vnode?.__k) {
221
+ for (let i=0; i<vnode.__k.length; i++) {
222
+ self.deep_force_update(vnode.__k[i]);
224
223
  }
225
224
  }
226
225
  };
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isomorfeus-preact
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.6.35
4
+ version: 10.6.39
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-16 00:00:00.000000000 Z
11
+ date: 2022-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -86,42 +86,42 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.14.10
89
+ version: 0.14.15
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.14.10
96
+ version: 0.14.15
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: isomorfeus-redux
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 4.1.16
103
+ version: 4.1.18
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 4.1.16
110
+ version: 4.1.18
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: isomorfeus-speednode
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.4.9
117
+ version: 0.5.2
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 0.4.9
124
+ version: 0.5.2
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: dalli
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -232,7 +232,9 @@ files:
232
232
  - lib/isomorfeus/preact_view_helper.rb
233
233
  - lib/isomorfeus/props/validate_hash_proxy.rb
234
234
  - lib/isomorfeus/props/validator.rb
235
+ - lib/isomorfeus/ssr.rb
235
236
  - lib/isomorfeus/top_level.rb
237
+ - lib/isomorfeus/top_level_ssr.rb
236
238
  - lib/isomorfeus_preact/lucid_app/api.rb
237
239
  - lib/isomorfeus_preact/lucid_app/base.rb
238
240
  - lib/isomorfeus_preact/lucid_app/mixin.rb