isomorfeus-asset-manager 0.12.2 → 0.12.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/isomorfeus/asset_manager/asset.rb +25 -0
- data/lib/isomorfeus/asset_manager/config.rb +8 -2
- data/lib/isomorfeus/asset_manager/rack_middleware.rb +53 -49
- data/lib/isomorfeus/asset_manager/server_socket_processor.rb +21 -55
- data/lib/isomorfeus/asset_manager/version.rb +1 -1
- data/lib/isomorfeus/asset_manager.rb +53 -23
- data/lib/isomorfeus-asset-manager.rb +3 -0
- data/node_modules/.package-lock.json +3 -3
- data/node_modules/esbuild-wasm/esbuild.wasm +0 -0
- data/node_modules/esbuild-wasm/esm/browser.d.ts +19 -0
- data/node_modules/esbuild-wasm/esm/browser.js +43 -5
- data/node_modules/esbuild-wasm/esm/browser.min.js +7 -7
- data/node_modules/esbuild-wasm/lib/browser.d.ts +19 -0
- data/node_modules/esbuild-wasm/lib/browser.js +43 -5
- data/node_modules/esbuild-wasm/lib/browser.min.js +13 -5
- data/node_modules/esbuild-wasm/lib/main.d.ts +19 -0
- data/node_modules/esbuild-wasm/lib/main.js +85 -16
- data/node_modules/esbuild-wasm/package.json +1 -1
- data/package.json +1 -1
- metadata +34 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 748ed2bb10bab68fad00bba234cc0175bc5d570d4e5173da53190922d2cfa413
|
4
|
+
data.tar.gz: 905ce53e7fefea4a9d69475c370d507e876348e38f7e296fd53b12f6c7b3923a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dae52b87da0a0da3f1808ae5d113632b5f7262701e58e399d8eb6b8ee4d45b317f285a03efda3df8ab9f6f2e1387c04c6a1e286b294214a9fb16cbb610725381
|
7
|
+
data.tar.gz: d8b04e26aeb39f2cd9abaf2f4f107a8a9d253f87b332f014fdad41cd487050c851301ebf8e01ef1a7a9f804134fab08a7b5eba22d12a9ccbdb16076d5e360bc8
|
@@ -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,20 @@
|
|
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
|
+
attr_accessor :asset_manager_hmr_dirs
|
14
15
|
attr_accessor :node_paths
|
15
16
|
attr_accessor :assets
|
17
|
+
attr_accessor :hmr_listener
|
16
18
|
|
17
19
|
def add_web_js_import(*args)
|
18
20
|
Isomorfeus.assets['web.js'].add_js_import(*args)
|
@@ -62,6 +64,10 @@ module Isomorfeus
|
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
67
|
+
self.hmr_listener = nil
|
68
|
+
self.asset_manager_hmr_channel = :isomorfeus_asset_manager_module_updates
|
69
|
+
self.asset_manager_hmr_dirs = %w[channels, components, data, operations, policies]
|
70
|
+
self.assets_websocket_path = '/_assets_websocket'
|
65
71
|
self.assets_path = '/assets'
|
66
72
|
self.assets = {
|
67
73
|
'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,67 +18,70 @@ 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
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
71
|
-
|
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
|
|
77
81
|
def should_gzip?(env)
|
78
|
-
return true if env.
|
82
|
+
return true if env.key?('HTTP_ACCEPT_ENCODING') && env['HTTP_ACCEPT_ENCODING'].match?(/\bgzip\b/)
|
79
83
|
return false if /\bno-transform\b/.match?(env[Rack::CACHE_CONTROL].to_s) || env['Content-Encoding']&.!~(/\bidentity\b/)
|
80
|
-
return false if @compressible_types && !(env.
|
84
|
+
return false if @compressible_types && !(env.key?(Rack::CONTENT_TYPE) && @compressible_types.include?(env[Rack::CONTENT_TYPE][/[^;]*/]))
|
81
85
|
true
|
82
86
|
end
|
83
87
|
end
|
@@ -1,55 +1,21 @@
|
|
1
|
-
module Isomorfeus
|
2
|
-
class AssetManager
|
3
|
-
class ServerSocketProcessor
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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,9 +1,5 @@
|
|
1
1
|
module Isomorfeus
|
2
2
|
class AssetManager
|
3
|
-
def self.finalize(tmpdir)
|
4
|
-
proc { FileUtils.rm_rf(tmpdir) }
|
5
|
-
end
|
6
|
-
|
7
3
|
def initialize
|
8
4
|
Isomorfeus.set_node_paths
|
9
5
|
|
@@ -12,6 +8,7 @@ module Isomorfeus
|
|
12
8
|
@output_path = File.join(@tmpdir, 'output')
|
13
9
|
FileUtils.mkdir_p(@imports_path)
|
14
10
|
FileUtils.mkdir_p(@output_path)
|
11
|
+
@server_path = File.join(Isomorfeus.app_root, 'server')
|
15
12
|
|
16
13
|
@context = ExecJS.permissive_compile(init_js)
|
17
14
|
|
@@ -25,17 +22,17 @@ module Isomorfeus
|
|
25
22
|
Isomorfeus.add_ssr_js_import(ssr_imports_file) if File.exist?(ssr_imports_file)
|
26
23
|
end
|
27
24
|
|
28
|
-
|
25
|
+
init_hmr_listener if Isomorfeus.development? && !Isomorfeus.hmr_listener
|
29
26
|
end
|
30
27
|
|
31
|
-
def transition(asset_key, asset)
|
28
|
+
def transition(asset_key, asset, analyze: false)
|
32
29
|
return if !Isomorfeus.development? && asset.bundled?
|
33
30
|
asset.mutex.synchronize do
|
34
31
|
return if !Isomorfeus.development? && asset.bundled?
|
35
32
|
asset.touch
|
36
|
-
|
33
|
+
build_ruby_and_save(asset_key, asset)
|
37
34
|
save_imports(asset_key, asset)
|
38
|
-
run_esbuild(asset_key, asset)
|
35
|
+
run_esbuild(asset_key, asset, analyze)
|
39
36
|
asset.bundle = bundled_asset(asset_key)
|
40
37
|
asset.bundle_map = bundled_asset_map(asset_key) unless Isomorfeus.production?
|
41
38
|
end
|
@@ -55,7 +52,7 @@ module Isomorfeus
|
|
55
52
|
File.write(File.join(@imports_path, asset_key), asset.to_s)
|
56
53
|
end
|
57
54
|
|
58
|
-
def
|
55
|
+
def build_ruby_and_save(asset_key, asset)
|
59
56
|
asset.ruby_imports.each do |ruby_import|
|
60
57
|
out_file = File.join(@imports_path, ruby_import.module_name + '.js')
|
61
58
|
next if !Isomorfeus.development? && File.exist?(out_file)
|
@@ -71,6 +68,13 @@ module Isomorfeus
|
|
71
68
|
end
|
72
69
|
end
|
73
70
|
|
71
|
+
def compile_ruby(file)
|
72
|
+
source = File.read(file)
|
73
|
+
module_file = file[(Isomorfeus.app_root.size + 1)..-1]
|
74
|
+
compiler = Opal::Compiler.new(source, requirable: true, file: module_file)
|
75
|
+
{ javascript: compiler.compile }
|
76
|
+
end
|
77
|
+
|
74
78
|
def print_message(m, level)
|
75
79
|
l = m['location']
|
76
80
|
STDERR.puts "#{l['file']}:#{l['line']}:#{l['column']}: #{level}: #{m['text']}"
|
@@ -78,17 +82,6 @@ module Isomorfeus
|
|
78
82
|
end
|
79
83
|
|
80
84
|
def handle_errors(asset_key, result)
|
81
|
-
# Todo simplify
|
82
|
-
unless result['warnings'].empty?
|
83
|
-
result['warnings'].each do |w|
|
84
|
-
print_message(w, 'warning')
|
85
|
-
unless w['notes'].empty?
|
86
|
-
w['notes'].each do |n|
|
87
|
-
print_message(n, 'note')
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
85
|
unless result['errors'].empty?
|
93
86
|
result['errors'].each do |e|
|
94
87
|
print_message(w, 'error')
|
@@ -98,7 +91,7 @@ module Isomorfeus
|
|
98
91
|
end
|
99
92
|
end
|
100
93
|
end
|
101
|
-
raise "
|
94
|
+
raise "Asset Manager: error bundling '#{asset_key}'"
|
102
95
|
end
|
103
96
|
end
|
104
97
|
|
@@ -115,23 +108,52 @@ module Isomorfeus
|
|
115
108
|
JAVASCRIPT
|
116
109
|
end
|
117
110
|
|
111
|
+
def init_hmr_listener
|
112
|
+
return unless Dir.exist?(Isomorfeus.app_root)
|
113
|
+
listen_dirs = []
|
114
|
+
Isomorfeus.asset_manager_hmr_dirs.each do |dir|
|
115
|
+
if File.absolute_path?(dir)
|
116
|
+
listen_dirs << dir if Dir.exist?(dir)
|
117
|
+
else
|
118
|
+
listen_dir = File.join(Isomorfeus.app_root, dir)
|
119
|
+
listen_dirs << listen_dir if Dir.exist?(listen_dir)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
Isomorfeus.hmr_listener = Listen.to(*listen_dirs) do |modified, added, _|
|
123
|
+
(modified + added).each do |file|
|
124
|
+
next if file.start_with?(@server_path)
|
125
|
+
begin
|
126
|
+
update = compile_ruby(file)
|
127
|
+
update_json = Oj.dump(update, mode: :strict)
|
128
|
+
Iodine.publish(Isomorfeus.asset_manager_hmr_channel, update_json)
|
129
|
+
rescue Exception => e
|
130
|
+
message = "#{e.message}\n#{e.backtrace.join("\n")}"
|
131
|
+
STDERR.puts message
|
132
|
+
Iodine.publish(Isomorfeus.asset_manager_hmr_channel, Oj.dump({ error: message }, mode: :struct))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
Isomorfeus.hmr_listener.start
|
137
|
+
end
|
138
|
+
|
118
139
|
# possible future improvement
|
119
140
|
# loader: {
|
120
141
|
# '.png': 'dataurl',
|
121
142
|
# '.svg': 'text',
|
122
143
|
# },
|
123
|
-
def run_esbuild(asset_key, asset)
|
144
|
+
def run_esbuild(asset_key, asset, analyze = false)
|
124
145
|
resolve_paths = ENV['NODE_PATH'].split(Gem.win_platform? ? ';' : ':')
|
125
146
|
resolve_paths << 'node_modules'
|
126
147
|
resolve_paths.uniq!
|
127
148
|
|
128
149
|
result = @context.exec <<~JAVASCRIPT
|
129
|
-
|
150
|
+
let res = esbuild.buildSync({
|
130
151
|
entryPoints: [path.resolve(global.imports_path, '#{asset_key}')],
|
131
152
|
bundle: true,
|
132
153
|
color: false,
|
133
154
|
format: '#{asset.target == :node ? 'cjs' : 'iife'}',
|
134
155
|
legalComments: 'linked',
|
156
|
+
metafile: true,
|
135
157
|
minify: #{Isomorfeus.production? ? 'true' : 'false'},
|
136
158
|
nodePaths: #{resolve_paths},
|
137
159
|
outdir: global.output_path,
|
@@ -142,7 +164,15 @@ module Isomorfeus
|
|
142
164
|
target: 'es6',
|
143
165
|
write: true
|
144
166
|
});
|
167
|
+
global.res_meta = res.metafile;
|
168
|
+
return res;
|
145
169
|
JAVASCRIPT
|
170
|
+
if analyze
|
171
|
+
analysis = @context.await <<~JAVASCRIPT
|
172
|
+
esbuild.analyzeMetafile(global.res_meta, { verbose: true });
|
173
|
+
JAVASCRIPT
|
174
|
+
STDOUT.puts "Bundle analysis for #{asset_key}:\n#{analysis}\n"
|
175
|
+
end
|
146
176
|
handle_errors(asset_key, result)
|
147
177
|
end
|
148
178
|
end
|