Class: Hyperstack::Hotloader

Inherits:
Object
  • Object
show all
Defined in:
lib/hyperstack/hotloader.rb,
lib/hyperstack/hotloader/server.rb,
lib/hyperstack/hotloader/socket.rb,
lib/hyperstack/hotloader/css_reloader.rb,
lib/hyperstack/hotloader/add_error_boundry.rb

Defined Under Namespace

Modules: AddErrorBoundry Classes: Client, CssReloader, Server, Socket

Constant Summary collapse

@@USE_ALERT =
true

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(port = 25222, ping = nil, &reload_post_callback) ⇒ Hotloader

Returns a new instance of Hotloader.

Parameters:

  • port (Integer) (defaults to: 25222)

    opal hot reloader port to connect to

  • reload_post_callback (Proc)

    optional callback to be called after re evaluating a file for example in react.rb files we want to do a React::Component.force_update!



104
105
106
107
108
109
# File 'lib/hyperstack/hotloader.rb', line 104

def initialize(port=25222, ping=nil, &reload_post_callback)
  @port = port
  @reload_post_callback  = reload_post_callback
  @css_reloader = CssReloader.new
  @ping = ping
end

Class Method Details

.alerts_off!Object



71
72
73
# File 'lib/hyperstack/hotloader.rb', line 71

def self.alerts_off!
  @@USE_ALERT = false
end

.alerts_on!Object



67
68
69
# File 'lib/hyperstack/hotloader.rb', line 67

def self.alerts_on!
  @@USE_ALERT = true
end

.callbackmapsObject



18
19
20
# File 'lib/hyperstack/hotloader.rb', line 18

def self.callbackmaps
  @@callbackmaps ||= Hash.new { |h, k| h[k] = Hash.new { |h1, k1| h1[k1] = Hash.new { |h2, k2| h2[k2] = Array.new }}}
end

.listen(port = 25222, ping = nil) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/hyperstack/hotloader.rb', line 115

def self.listen(port=25222, ping=nil)
  ::Hyperstack::Internal::Component::TopLevelRailsComponent.include AddErrorBoundry
  @server = Hotloader.new(port, ping) do
    # TODO: check this out when Operations are integrated
    # if defined?(Hyperloop::Internal::Operation::ClientDrivers) &&
    #    Hyperloop::ClientDrivers.respond_to?(:initialize_client_drivers_on_boot)
    #   Hyperloop::ClientDrivers.initialize_client_drivers_on_boot
    # end
    Hyperstack::Component.force_update!
  end
  @server.listen
end

.record(klass, instance_var, depth, *items) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/hyperstack/hotloader.rb', line 22

def self.record(klass, instance_var, depth, *items)
  if $_hyperstack_reloader_file_name
    callbackmaps[$_hyperstack_reloader_file_name][klass][instance_var].concat items
  else
    callback = lambda do |stack_frames|
      file_name = `#{stack_frames[depth]}.fileName`
      match = /^(.+\/assets\/)(.+\/)\2/.match(file_name)
      if match
        file_name = file_name.gsub(match[1]+match[2], '')
        callbackmaps[file_name][klass][instance_var].concat items
      end
    end
    error = lambda do |err|
      `console.error(#{"hyperstack hot loader could not find source file for callback: #{err}"})`
    end
    `StackTrace.get().then(#{callback}).catch(#{error})`
   end
end

.remove(file_name) ⇒ Object



41
42
43
44
45
46
47
# File 'lib/hyperstack/hotloader.rb', line 41

def self.remove(file_name)
  callbackmaps[file_name].each do |klass, instance_vars|
    instance_vars.each do |instance_var, items|
      klass.instance_variable_get(instance_var).reject! { |item| items.include? item }
    end
  end
end

Instance Method Details

#connect_to_websocket(port) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/hyperstack/hotloader.rb', line 49

def connect_to_websocket(port)
  host = `window.location.host`.sub(/:\d+/, '')
  host = '127.0.0.1' if host == ''
  protocol = `window.location.protocol` == 'https:' ? 'wss:' : 'ws:'
  ws_url = "#{host}:#{port}"
  puts "Hot-Reloader connecting to #{ws_url}"
  ws = `new WebSocket(#{protocol} + '//' + #{ws_url})`
  `#{ws}.onmessage = #{lambda { |e| reload(e) }}`
  `setInterval(function() { #{ws}.send('') }, #{@ping * 1000})` if @ping
end

#listenObject

Opens a websocket connection that evaluates new files and runs the optional @reload_post_callback



111
112
113
# File 'lib/hyperstack/hotloader.rb', line 111

def listen
  connect_to_websocket(@port)
end

#notify_error(reload_request) ⇒ Object



60
61
62
63
64
# File 'lib/hyperstack/hotloader.rb', line 60

def notify_error(reload_request)
  msg = "Hotloader #{reload_request[:filename]} RELOAD ERROR:\n\n#{$!}"
  puts msg
  alert msg if use_alert?
end

#reload(e) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/hyperstack/hotloader.rb', line 79

def reload(e)
  reload_request = JSON.parse(`e.data`)
  if reload_request[:type] == "ruby"
    puts "Reloading #{reload_request[:filename]} (asset_path: #{reload_request[:asset_path]})"
    begin
      #Hyperstack::Context.reset! false
      file_name = reload_request[:asset_path] #.gsub(/.+hyperstack\//, '')
      Hotloader.remove(file_name)
      $eval_proc.call file_name, reload_request[:source_code]
    rescue
      notify_error(reload_request)
    end
    if @reload_post_callback
      @reload_post_callback.call
    else
      puts "no reloading callback to call"
    end
  end
  if reload_request[:type] == "css"
    @css_reloader.reload(reload_request, `document`)
  end
end

#use_alert?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/hyperstack/hotloader.rb', line 75

def use_alert?
  @@USE_ALERT
end