isomorfeus-asset-manager 0.12.3 → 0.12.7
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 +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 +55 -19
- 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: 6f2bba888a2b50846a6384f6b5a04036b3e5e7e9e367f867b4cb23996ceb8ba1
|
4
|
+
data.tar.gz: 2ef547ce6fb466c561b1c4964d561c2c5612a2a641179b1dfdb33f555142f6b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b65f19ea35eb669fc45e946afe44b7da36b75910d28b69c4f9fdd9657f23c446c0f22e5fb505bf78755537428f91dcddd391edd4d818f9cabc8b2b3ca115e68
|
7
|
+
data.tar.gz: 7acea3a93903a46f1d59ae45f83617c619812836015c58bbbab9b7ebf1e24c21708b013021eb1898ab9cfcdafaf991ae0f821db6dddbd256097a170118a0a133
|
@@ -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
|
@@ -8,6 +8,7 @@ module Isomorfeus
|
|
8
8
|
@output_path = File.join(@tmpdir, 'output')
|
9
9
|
FileUtils.mkdir_p(@imports_path)
|
10
10
|
FileUtils.mkdir_p(@output_path)
|
11
|
+
@server_path = File.join(Isomorfeus.app_root, 'server')
|
11
12
|
|
12
13
|
@context = ExecJS.permissive_compile(init_js)
|
13
14
|
|
@@ -20,16 +21,18 @@ module Isomorfeus
|
|
20
21
|
ssr_imports_file = File.join(imports_path, 'ssr.js')
|
21
22
|
Isomorfeus.add_ssr_js_import(ssr_imports_file) if File.exist?(ssr_imports_file)
|
22
23
|
end
|
24
|
+
|
25
|
+
init_hmr_listener if Isomorfeus.development? && !Isomorfeus.hmr_listener
|
23
26
|
end
|
24
27
|
|
25
|
-
def transition(asset_key, asset)
|
28
|
+
def transition(asset_key, asset, analyze: false)
|
26
29
|
return if !Isomorfeus.development? && asset.bundled?
|
27
30
|
asset.mutex.synchronize do
|
28
31
|
return if !Isomorfeus.development? && asset.bundled?
|
29
32
|
asset.touch
|
30
|
-
|
33
|
+
build_ruby_and_save(asset_key, asset)
|
31
34
|
save_imports(asset_key, asset)
|
32
|
-
run_esbuild(asset_key, asset)
|
35
|
+
run_esbuild(asset_key, asset, analyze)
|
33
36
|
asset.bundle = bundled_asset(asset_key)
|
34
37
|
asset.bundle_map = bundled_asset_map(asset_key) unless Isomorfeus.production?
|
35
38
|
end
|
@@ -49,12 +52,12 @@ module Isomorfeus
|
|
49
52
|
File.write(File.join(@imports_path, asset_key), asset.to_s)
|
50
53
|
end
|
51
54
|
|
52
|
-
def
|
55
|
+
def build_ruby_and_save(asset_key, asset)
|
53
56
|
asset.ruby_imports.each do |ruby_import|
|
54
57
|
out_file = File.join(@imports_path, ruby_import.module_name + '.js')
|
55
58
|
next if !Isomorfeus.development? && File.exist?(out_file)
|
56
59
|
js_map_path = File.join(@imports_path, ruby_import.module_name + '.js.map')
|
57
|
-
result = Opal::Builder.build(ruby_import.resolved_path, {
|
60
|
+
result = Opal::Builder.build(ruby_import.resolved_path, { esm: true })
|
58
61
|
FileUtils.mkdir_p(File.join(*[@imports_path].concat(ruby_import.module_name.split('/')[0...-1]))) if ruby_import.module_name.include?('/')
|
59
62
|
js = result.to_s
|
60
63
|
unless Isomorfeus.production?
|
@@ -65,6 +68,13 @@ module Isomorfeus
|
|
65
68
|
end
|
66
69
|
end
|
67
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
|
+
|
68
78
|
def print_message(m, level)
|
69
79
|
l = m['location']
|
70
80
|
STDERR.puts "#{l['file']}:#{l['line']}:#{l['column']}: #{level}: #{m['text']}"
|
@@ -72,17 +82,6 @@ module Isomorfeus
|
|
72
82
|
end
|
73
83
|
|
74
84
|
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
85
|
unless result['errors'].empty?
|
87
86
|
result['errors'].each do |e|
|
88
87
|
print_message(w, 'error')
|
@@ -92,7 +91,7 @@ module Isomorfeus
|
|
92
91
|
end
|
93
92
|
end
|
94
93
|
end
|
95
|
-
raise "
|
94
|
+
raise "Asset Manager: error bundling '#{asset_key}'"
|
96
95
|
end
|
97
96
|
end
|
98
97
|
|
@@ -109,23 +108,52 @@ module Isomorfeus
|
|
109
108
|
JAVASCRIPT
|
110
109
|
end
|
111
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
|
+
|
112
139
|
# possible future improvement
|
113
140
|
# loader: {
|
114
141
|
# '.png': 'dataurl',
|
115
142
|
# '.svg': 'text',
|
116
143
|
# },
|
117
|
-
def run_esbuild(asset_key, asset)
|
144
|
+
def run_esbuild(asset_key, asset, analyze = false)
|
118
145
|
resolve_paths = ENV['NODE_PATH'].split(Gem.win_platform? ? ';' : ':')
|
119
146
|
resolve_paths << 'node_modules'
|
120
147
|
resolve_paths.uniq!
|
121
148
|
|
122
149
|
result = @context.exec <<~JAVASCRIPT
|
123
|
-
|
150
|
+
let res = esbuild.buildSync({
|
124
151
|
entryPoints: [path.resolve(global.imports_path, '#{asset_key}')],
|
125
152
|
bundle: true,
|
126
153
|
color: false,
|
127
154
|
format: '#{asset.target == :node ? 'cjs' : 'iife'}',
|
128
155
|
legalComments: 'linked',
|
156
|
+
metafile: true,
|
129
157
|
minify: #{Isomorfeus.production? ? 'true' : 'false'},
|
130
158
|
nodePaths: #{resolve_paths},
|
131
159
|
outdir: global.output_path,
|
@@ -136,7 +164,15 @@ module Isomorfeus
|
|
136
164
|
target: 'es6',
|
137
165
|
write: true
|
138
166
|
});
|
167
|
+
global.res_meta = res.metafile;
|
168
|
+
return res;
|
139
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
|
140
176
|
handle_errors(asset_key, result)
|
141
177
|
end
|
142
178
|
end
|