class Isomorfeus::AssetManager
Constants
- VERSION
Public Class Methods
new()
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 3 def initialize Isomorfeus.set_node_paths @tmpdir = Isomorfeus.asset_manager_tmpdir @imports_path = File.join(@tmpdir, 'imports') @output_path = File.join(@tmpdir, 'output') FileUtils.mkdir_p(@imports_path) FileUtils.mkdir_p(@output_path) @server_path = File.join(Isomorfeus.app_root, 'server') @context = ExecJS.permissive_compile(init_js) imports_path = File.expand_path(File.join(Isomorfeus.app_root, 'imports')) if Dir.exist?(imports_path) common_imports_file = File.join(imports_path, 'common.js') Isomorfeus.add_common_js_import(common_imports_file) if File.exist?(common_imports_file) web_imports_file = File.join(imports_path, 'web.js') Isomorfeus.add_web_js_import(web_imports_file) if File.exist?(web_imports_file) ssr_imports_file = File.join(imports_path, 'ssr.js') Isomorfeus.add_ssr_js_import(ssr_imports_file) if File.exist?(ssr_imports_file) end init_hmr_listener if Isomorfeus.development? && !Isomorfeus.hmr_listener end
Public Instance Methods
transition(asset_key, asset, analyze: false)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 28 def transition(asset_key, asset, analyze: false) return if !Isomorfeus.development? && asset.bundled? asset.mutex.synchronize do return if !Isomorfeus.development? && asset.bundled? asset.touch build_ruby_and_save(asset_key, asset) save_imports(asset_key, asset) run_esbuild(asset_key, asset, analyze) asset.bundle = bundled_asset(asset_key) asset.bundle_map = bundled_asset_map(asset_key) unless Isomorfeus.production? end end
Private Instance Methods
build_ruby_and_save(asset_key, asset)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 55 def build_ruby_and_save(asset_key, asset) asset.ruby_imports.each do |ruby_import| out_file = File.join(@imports_path, ruby_import.module_name + '.js') next if !Isomorfeus.development? && File.exist?(out_file) js_map_path = File.join(@imports_path, ruby_import.module_name + '.js.map') result = Opal::Builder.build(ruby_import.resolved_path, { esm: true }) FileUtils.mkdir_p(File.join(*[@imports_path].concat(ruby_import.module_name.split('/')[0...-1]))) if ruby_import.module_name.include?('/') js = result.to_s unless Isomorfeus.production? js << "\n//# sourceMappingURL=file://#{js_map_path}\n" File.write(js_map_path, result.source_map) end File.write(out_file, js) end end
bundled_asset(asset_key)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 43 def bundled_asset(asset_key) File.read(File.join(@output_path, asset_key)) end
bundled_asset_map(asset_key)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 47 def bundled_asset_map(asset_key) File.read(File.join(@output_path, asset_key + '.map')) end
compile_ruby(file)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 71 def compile_ruby(file) source = File.read(file) module_file = file[(Isomorfeus.app_root.size + 1)..-1] compiler = Opal::Compiler.new(source, requirable: true, file: module_file) { javascript: compiler.compile } end
handle_errors(asset_key, result)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 84 def handle_errors(asset_key, result) unless result['errors'].empty? result['errors'].each do |e| print_message(w, 'error') unless w['notes'].empty? e['notes'].each do |n| print_message(n, 'note') end end end raise "Asset Manager: error bundling '#{asset_key}'" end end
init_hmr_listener()
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 111 def init_hmr_listener return unless Dir.exist?(Isomorfeus.app_root) listen_dirs = [] Isomorfeus.asset_manager_hmr_dirs.each do |dir| if File.absolute_path?(dir) listen_dirs << dir if Dir.exist?(dir) else listen_dir = File.join(Isomorfeus.app_root, dir) listen_dirs << listen_dir if Dir.exist?(listen_dir) end end Isomorfeus.hmr_listener = Listen.to(*listen_dirs) do |modified, added, _| (modified + added).each do |file| next if file.start_with?(@server_path) begin update = compile_ruby(file) update_json = Oj.dump(update, mode: :strict) Iodine.publish(Isomorfeus.asset_manager_hmr_channel, update_json) rescue Exception => e message = "#{e.message}\n#{e.backtrace.join("\n")}" STDERR.puts message Iodine.publish(Isomorfeus.asset_manager_hmr_channel, Oj.dump({ error: message }, mode: :struct)) end end end Isomorfeus.hmr_listener.start end
init_js()
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 98 def init_js <<~JAVASCRIPT 'use strict'; const path = require('path'); var esbuild_r; try { esbuild_r = require('esbuild'); } catch { esbuild_r = require('esbuild-wasm'); } const esbuild = esbuild_r; global.imports_path = '#{@imports_path}'; global.output_path = '#{@output_path}'; JAVASCRIPT end
print_message(m, level)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 78 def print_message(m, level) l = m['location'] STDERR.puts "#{l['file']}:#{l['line']}:#{l['column']}: #{level}: #{m['text']}" STDERR.puts " #{l['line']} | #{l['lineText']}\n\n" end
run_esbuild(asset_key, asset, analyze = false)
click to toggle source
possible future improvement loader: {
'.png': 'dataurl', '.svg': 'text',
},
# File lib/isomorfeus/asset_manager.rb, line 144 def run_esbuild(asset_key, asset, analyze = false) resolve_paths = ENV['NODE_PATH'].split(Gem.win_platform? ? ';' : ':') resolve_paths << 'node_modules' resolve_paths.uniq! result = @context.exec <<~JAVASCRIPT let res = esbuild.buildSync({ entryPoints: [path.resolve(global.imports_path, '#{asset_key}')], bundle: true, color: false, format: '#{asset.target == :node ? 'cjs' : 'iife'}', legalComments: 'linked', metafile: true, minify: #{Isomorfeus.production? ? 'true' : 'false'}, nodePaths: #{resolve_paths}, outdir: global.output_path, platform: '#{asset.target}', publicPath: '/assets', sourcemap: #{!Isomorfeus.production? ? 'true' : 'false'}, splitting: false, target: 'es6', write: true }); global.res_meta = res.metafile; return res; JAVASCRIPT if analyze analysis = @context.await <<~JAVASCRIPT esbuild.analyzeMetafile(global.res_meta, { verbose: true }); JAVASCRIPT STDOUT.puts "Bundle analysis for #{asset_key}:\n#{analysis}\n" end handle_errors(asset_key, result) end
save_imports(asset_key, asset)
click to toggle source
# File lib/isomorfeus/asset_manager.rb, line 51 def save_imports(asset_key, asset) File.write(File.join(@imports_path, asset_key), asset.to_s) end