isomorfeus-asset-manager 0.12.4 → 0.12.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7162fb3d5c939906f313a318d584172442701208252f8aafc0eebedcf0c4ad9c
4
- data.tar.gz: dc71e81701d13ecf72da6e55804dc71a20b9ddc4cbb13deac91c361015f7571f
3
+ metadata.gz: 118c1d13be80aba5339ecc42d8af01d22b1aa97ac929b8eb7915638ce28a3449
4
+ data.tar.gz: 8828cc73dc59ad93686d0e5c50a5df9da7ba25b9a1e8925537ce04b8bd359df3
5
5
  SHA512:
6
- metadata.gz: bbe144c2ef38e4c50ea177ce6a186c05c2dbe80d1dd168f8d2c39c3526b7a7b37219e84ebb051c31f08f0555dbd996463b3ab6a08e093d20b3bbee89e8550cf4
7
- data.tar.gz: 20fcde6cd21f5d9c280e7b359151f2d4eb61a629ef85c93258fb0872c9c71cf283e16493d30ba14eb9d25e6d642026347896fa82ced73a444c42bfd8372e5996
6
+ metadata.gz: 3e8c8ebec132650ef035c830ee3dcf5caecf9a22cd7674c9cacc1ac673e66b2c75e29b4f414c2222d1fc25cbfc4609e3ab6ccb8f8806d3b4e2cd6aa7a3fd568f
7
+ data.tar.gz: 64de09f406887a737cfd1dc3e976cd4b911acf49cc92e2b64ce24cad185994b1b49ba05f51a5783230a61401d3f5cbab687b4c661f6a16ab4b348aa4c2b22b2d
@@ -63,6 +63,31 @@ module Isomorfeus
63
63
  end
64
64
  js << "\n" if !@js_imports.empty? && !@ruby_imports.empty?
65
65
  unless @ruby_imports.empty?
66
+ if Isomorfeus.development? && @target == :browser
67
+ js << <<~JAVASCRIPT
68
+ // Isomorfeus Asset Manager HMR code begin
69
+ let ws_protocol = (window.location.protocol == 'https:') ? 'wss:' : 'ws:';
70
+ let ws_url = ws_protocol + '//' + window.location.host + "#{Isomorfeus.assets_websocket_path}";
71
+ let hmr_ws = new WebSocket(ws_url);
72
+ hmr_ws.onmessage = function(event) {
73
+ let update = JSON.parse(event.data);
74
+ if (typeof update.error !== 'undefined') { console.error(update.error); return; }
75
+ let start_index = '/* Generated by Opal 1.2.0 */\\nOpal.modules[\\"'.length;
76
+ let end_index = update.javascript.indexOf('"', start_index);
77
+ let opal_module_name = update.javascript.substr(start_index, end_index - start_index);
78
+ console.log('Updating ', opal_module_name);
79
+ if (typeof Opal !== 'undefined' && typeof Opal.require_table !== "undefined" && Opal.require_table['corelib/module']) {
80
+ try {
81
+ eval(update.javascript);
82
+ if (Opal.require_table[opal_module_name]) { Opal.load.call(Opal, opal_module_name); }
83
+ else { Opal.require.call(Opal, opal_module_name); }
84
+ Opal.Isomorfeus.$force_render();
85
+ } catch (e) { console.error(e); return; }
86
+ }
87
+ }
88
+ // Isomorfeus Asset Manager HMR code end
89
+ JAVASCRIPT
90
+ end
66
91
  js << "#{@ruby_imports.map(&:to_s).join("\n")}"
67
92
  end
68
93
  js
@@ -1,18 +1,19 @@
1
1
  module Isomorfeus
2
2
  # available settings
3
3
  if RUBY_ENGINE == 'opal'
4
- add_client_option(:assets_websocket_path)
5
4
  add_client_option(:assets_path)
6
- add_client_option(:opal_assets_path)
7
5
  else
8
6
  class << self
9
7
  attr_reader :env
10
8
  attr_accessor :root
11
9
  attr_accessor :app_root
12
10
  attr_accessor :assets_path
11
+ attr_accessor :assets_websocket_path
13
12
  attr_accessor :asset_manager_tmpdir
13
+ attr_accessor :asset_manager_hmr_channel
14
14
  attr_accessor :node_paths
15
15
  attr_accessor :assets
16
+ attr_accessor :hmr_listener
16
17
 
17
18
  def add_web_js_import(*args)
18
19
  Isomorfeus.assets['web.js'].add_js_import(*args)
@@ -62,6 +63,9 @@ module Isomorfeus
62
63
  end
63
64
  end
64
65
 
66
+ self.hmr_listener = nil
67
+ self.asset_manager_hmr_channel = :isomorfeus_asset_manager_module_updates
68
+ self.assets_websocket_path = '/_assets_websocket'
65
69
  self.assets_path = '/assets'
66
70
  self.assets = {
67
71
  'web.js' => Isomorfeus::AssetManager::Asset.new(:browser),
@@ -3,10 +3,11 @@
3
3
  module Isomorfeus
4
4
  class AssetManager
5
5
  class RackMiddleware
6
- WS_RESPONSE = [0, {}, []]
6
+ WS_RESPONSE = [0, {}, []].freeze
7
7
  attr_reader :asset_manager
8
8
 
9
9
  def initialize(app)
10
+ STDERR.puts "asset manager"
10
11
  @app = app
11
12
  @asset_manager = Isomorfeus::AssetManager.new
12
13
  @compressible_types = %w[application/javascript text/javascript]
@@ -17,60 +18,63 @@ module Isomorfeus
17
18
  @assets_path = Isomorfeus.assets_path + '/'
18
19
  @assets_path_size = @assets_path.size
19
20
  end
21
+ rescue Exception => e
22
+ STDERR.puts "#{e.message}\n#{e.backtrace.join("\n")}\n"
20
23
  end
21
24
 
22
25
  def call(env)
23
- begin
24
- path_info = env['PATH_INFO']
25
- if path_info.start_with?(@assets_path)
26
- asset_key = path_info[@assets_path_size..-1]
26
+ path_info = env['PATH_INFO']
27
+ if path_info.start_with?(@assets_path)
28
+ asset_key = path_info[@assets_path_size..-1]
27
29
 
28
- # get js
29
- if Isomorfeus.assets.key?(asset_key)
30
- asset = Isomorfeus.assets[asset_key]
31
- if asset && asset.target != :node
32
- asset_manager.transition(asset_key, asset)
33
- headers = {}
34
- headers['Last-Modified'] = asset.mtime
35
- headers[Rack::CONTENT_TYPE] = 'application/javascript'
36
- if should_gzip?(env)
37
- headers['Content-Encoding'] = "gzip"
38
- headers[Rack::CONTENT_LENGTH] = asset.bundle_gz_size
39
- return [200, headers, asset.bundle_gz]
40
- else
41
- headers[Rack::CONTENT_LENGTH] = asset.bundle_size
42
- return [200, {}, asset.bundle]
43
- end
44
- end
45
-
46
- # get source map
47
- elsif asset_key.end_with?('.js.map')
48
- asset = Isomorfeus.assets[asset_key[0..-5]]
49
- if asset && asset.target != :node
50
- asset_manager.transition(asset_key, asset) unless asset.bundled?
51
- headers = {}
52
- headers['Last-Modified'] = asset.mtime
53
- headers[Rack::CONTENT_TYPE] = 'application/json'
54
- if should_gzip?(env)
55
- headers['Content-Encoding'] = "gzip"
56
- headers[Rack::CONTENT_LENGTH] = asset.bundle_map_gz.size
57
- return [200, headers, asset.bundle_map_gz]
58
- else
59
- headers[Rack::CONTENT_LENGTH] = asset.bundle_map.size
60
- return [200, {}, asset.bundle_map]
61
- end
62
- end
30
+ # get js
31
+ if Isomorfeus.assets.key?(asset_key)
32
+ asset = Isomorfeus.assets[asset_key]
33
+ if asset && asset.target != :node
34
+ asset_manager.transition(asset_key, asset)
35
+ headers = {}
36
+ headers['Last-Modified'] = asset.mtime
37
+ headers[Rack::CONTENT_TYPE] = 'application/javascript'
38
+ if should_gzip?(env)
39
+ headers['Content-Encoding'] = "gzip"
40
+ headers[Rack::CONTENT_LENGTH] = asset.bundle_gz_size
41
+ return [200, headers, asset.bundle_gz]
42
+ else
43
+ headers[Rack::CONTENT_LENGTH] = asset.bundle_size
44
+ return [200, {}, asset.bundle]
45
+ end
63
46
  end
64
- # elsif Isomorfeus.development? && path_info == Isomorfeus.api_asset_hmr_socket_path
65
- # if env['rack.upgrade?'] == :websocket
66
- # env['rack.upgrade'] = Isomorfeus::AssetManager::ServerSocketProcessor.new
67
- # end
68
- # WS_RESPONSE
47
+
48
+ # get source map
49
+ elsif asset_key.end_with?('.js.map')
50
+ asset = Isomorfeus.assets[asset_key[0..-5]]
51
+ if asset && asset.target != :node
52
+ asset_manager.transition(asset_key, asset) unless asset.bundled?
53
+ headers = {}
54
+ headers['Last-Modified'] = asset.mtime
55
+ headers[Rack::CONTENT_TYPE] = 'application/json'
56
+ if should_gzip?(env)
57
+ headers['Content-Encoding'] = "gzip"
58
+ headers[Rack::CONTENT_LENGTH] = asset.bundle_map_gz.size
59
+ return [200, headers, asset.bundle_map_gz]
60
+ else
61
+ headers[Rack::CONTENT_LENGTH] = asset.bundle_map.size
62
+ return [200, {}, asset.bundle_map]
63
+ end
64
+ end
65
+ end
66
+
67
+ # hot reloading subscription
68
+ elsif Isomorfeus.development? && path_info == Isomorfeus.assets_websocket_path
69
+ if env['rack.upgrade?'] == :websocket
70
+ env['rack.upgrade'] = Isomorfeus::AssetManager::ServerSocketProcessor.new
69
71
  end
70
- rescue Exception => e
71
- STDERR.puts "#{e}\n#{e.backtrace.join("\n")}"
72
+ WS_RESPONSE
73
+ else
72
74
  @app.call(env)
73
75
  end
76
+ rescue Exception => e
77
+ STDERR.puts "#{e.message}\n#{e.backtrace.join("\n")}\n"
74
78
  @app.call(env)
75
79
  end
76
80
 
@@ -1,55 +1,21 @@
1
- module Isomorfeus
2
- class AssetManager
3
- class ServerSocketProcessor
4
- # include Isomorfeus::Transport::ServerProcessor
5
-
6
- # def on_message(client, data)
7
- # # TODO
8
- # if Isomorfeus.development?
9
- # write_lock = Isomorfeus.zeitwerk_lock.try_write_lock
10
- # if write_lock
11
- # Isomorfeus.zeitwerk.reload
12
- # Isomorfeus.zeitwerk_lock.release_write_lock
13
- # end
14
- # Isomorfeus.zeitwerk_lock.acquire_read_lock
15
- # end
16
- # request_hash = Oj.load(data, mode: :strict)
17
- # handler_instance_cache = {}
18
- # response_agent_array = []
19
- # Thread.current[:isomorfeus_user] = user(client)
20
- # Thread.current[:isomorfeus_pub_sub_client] = client
21
- # process_request(request_hash, handler_instance_cache, response_agent_array)
22
- # handler_instance_cache.each_value do |handler|
23
- # handler.resolve if handler.resolving?
24
- # end
25
- # result = {}
26
- # response_agent_array.each do |response_agent|
27
- # result.deep_merge!(response_agent.result)
28
- # end
29
- # client.write Oj.dump(result, mode: :strict) unless result.empty?
30
- # ensure
31
- # Thread.current[:isomorfeus_user] = nil
32
- # Thread.current[:isomorfeus_pub_sub_client] = nil
33
- # Isomorfeus.zeitwerk_lock.release_read_lock if Isomorfeus.development?
34
- # end
35
-
36
- # def on_close(client)
37
- # # nothing for now
38
- # end
39
-
40
- # def on_open(client)
41
- # # nothing for now
42
- # end
43
-
44
- # def on_shutdown(client)
45
- # # nothing for now
46
- # end
47
-
48
- # def user(client)
49
- # current_user = client.instance_variable_get(:@isomorfeus_user)
50
- # return current_user if current_user
51
- # Anonymous.new
52
- # end
53
- end
54
- end
55
- end
1
+ module Isomorfeus
2
+ class AssetManager
3
+ class ServerSocketProcessor
4
+ def on_message(client, data)
5
+ # nothing for now
6
+ end
7
+
8
+ def on_close(client)
9
+ # client.unsubscribe Isomorfeus.asset_manager_hmr_channel
10
+ end
11
+
12
+ def on_open(client)
13
+ client.subscribe Isomorfeus.asset_manager_hmr_channel
14
+ end
15
+
16
+ def on_shutdown(client)
17
+ # nothing for now
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  module Isomorfeus
2
2
  class AssetManager
3
- VERSION = '0.12.4'
3
+ VERSION = '0.12.5'
4
4
  end
5
5
  end
@@ -20,6 +20,8 @@ module Isomorfeus
20
20
  ssr_imports_file = File.join(imports_path, 'ssr.js')
21
21
  Isomorfeus.add_ssr_js_import(ssr_imports_file) if File.exist?(ssr_imports_file)
22
22
  end
23
+
24
+ init_hmr_listener if Isomorfeus.development? && !Isomorfeus.hmr_listener
23
25
  end
24
26
 
25
27
  def transition(asset_key, asset, analyze: false)
@@ -27,7 +29,7 @@ module Isomorfeus
27
29
  asset.mutex.synchronize do
28
30
  return if !Isomorfeus.development? && asset.bundled?
29
31
  asset.touch
30
- compile_ruby_and_save(asset_key, asset)
32
+ build_ruby_and_save(asset_key, asset)
31
33
  save_imports(asset_key, asset)
32
34
  run_esbuild(asset_key, asset, analyze)
33
35
  asset.bundle = bundled_asset(asset_key)
@@ -49,7 +51,7 @@ module Isomorfeus
49
51
  File.write(File.join(@imports_path, asset_key), asset.to_s)
50
52
  end
51
53
 
52
- def compile_ruby_and_save(asset_key, asset)
54
+ def build_ruby_and_save(asset_key, asset)
53
55
  asset.ruby_imports.each do |ruby_import|
54
56
  out_file = File.join(@imports_path, ruby_import.module_name + '.js')
55
57
  next if !Isomorfeus.development? && File.exist?(out_file)
@@ -65,6 +67,13 @@ module Isomorfeus
65
67
  end
66
68
  end
67
69
 
70
+ def compile_ruby(file)
71
+ source = File.read(file)
72
+ module_file = file[(Isomorfeus.app_root.size + 1)..-1]
73
+ compiler = Opal::Compiler.new(source, requirable: true, file: module_file)
74
+ { javascript: compiler.compile }
75
+ end
76
+
68
77
  def print_message(m, level)
69
78
  l = m['location']
70
79
  STDERR.puts "#{l['file']}:#{l['line']}:#{l['column']}: #{level}: #{m['text']}"
@@ -72,17 +81,6 @@ module Isomorfeus
72
81
  end
73
82
 
74
83
  def handle_errors(asset_key, result)
75
- # Todo simplify
76
- # unless result['warnings'].empty?
77
- # result['warnings'].each do |w|
78
- # print_message(w, 'warning')
79
- # unless w['notes'].empty?
80
- # w['notes'].each do |n|
81
- # print_message(n, 'note')
82
- # end
83
- # end
84
- # end
85
- # end
86
84
  unless result['errors'].empty?
87
85
  result['errors'].each do |e|
88
86
  print_message(w, 'error')
@@ -92,7 +90,7 @@ module Isomorfeus
92
90
  end
93
91
  end
94
92
  end
95
- raise "Aseet Manager: error bundling '#{asset_key}'"
93
+ raise "Asset Manager: error bundling '#{asset_key}'"
96
94
  end
97
95
  end
98
96
 
@@ -109,6 +107,25 @@ module Isomorfeus
109
107
  JAVASCRIPT
110
108
  end
111
109
 
110
+ def init_hmr_listener
111
+ return unless Dir.exist?(Isomorfeus.app_root)
112
+ Isomorfeus.hmr_listener = Listen.to(Isomorfeus.app_root) do |modified, added, _|
113
+ (modified + added).each do |file|
114
+ begin
115
+ start = Time.now
116
+ update = compile_ruby(file)
117
+ update_json = Oj.dump(update, mode: :strict)
118
+ Iodine.publish(Isomorfeus.asset_manager_hmr_channel, update_json)
119
+ rescue Exception => e
120
+ message = "#{e.message}\n#{e.backtrace.join("\n")}"
121
+ STDERR.puts message
122
+ Iodine.publish(Isomorfeus.asset_manager_hmr_channel, Oj.dump({ error: message }, mode: :struct))
123
+ end
124
+ end
125
+ end
126
+ Isomorfeus.hmr_listener.start
127
+ end
128
+
112
129
  # possible future improvement
113
130
  # loader: {
114
131
  # '.png': 'dataurl',
@@ -137,14 +154,14 @@ module Isomorfeus
137
154
  target: 'es6',
138
155
  write: true
139
156
  });
140
- global.res = res;
157
+ global.res_meta = res.metafile;
141
158
  return res;
142
159
  JAVASCRIPT
143
160
  if analyze
144
161
  analysis = @context.await <<~JAVASCRIPT
145
- esbuild.analyzeMetafile(global.res.metafile, { verbose: true });
162
+ esbuild.analyzeMetafile(global.res_meta, { verbose: true });
146
163
  JAVASCRIPT
147
- STDOUT.puts "Bundle nalysis for #{asset_key}:\n#{analysis}\n"
164
+ STDOUT.puts "Bundle analysis for #{asset_key}:\n#{analysis}\n"
148
165
  end
149
166
  handle_errors(asset_key, result)
150
167
  end
@@ -3,9 +3,12 @@ require 'thread'
3
3
  require 'tmpdir'
4
4
  require 'zlib'
5
5
  require 'opal'
6
+ require 'opal/compiler'
6
7
  require 'opal/builder'
7
8
  require 'oj'
8
9
  require 'rack'
10
+ require 'listen'
11
+ require 'iodine'
9
12
  require 'isomorfeus-speednode'
10
13
  require 'isomorfeus/asset_manager/version'
11
14
  require 'isomorfeus/asset_manager/js_import'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isomorfeus-asset-manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.4
4
+ version: 0.12.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Biedermann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-10 00:00:00.000000000 Z
11
+ date: 2021-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: iodine
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.44
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.44
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: isomorfeus-speednode
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -24,20 +38,34 @@ dependencies:
24
38
  - - ">="
25
39
  - !ruby/object:Gem::Version
26
40
  version: 0.4.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: listen
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.7.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.7.0
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: oj
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - ">="
59
+ - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: 3.13.3
61
+ version: 3.13.6
34
62
  type: :runtime
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
- - - ">="
66
+ - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: 3.13.3
68
+ version: 3.13.6
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: opal
43
71
  requirement: !ruby/object:Gem::Requirement