Class: Assiette::AssetHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/assiette/asset_handler.rb

Constant Summary collapse

CONTENT_TYPES =
{
  ".js" => "application/javascript",
  ".mjs" => "application/javascript",
  ".css" => "text/css",
  ".svg" => "image/svg+xml",
  ".png" => "image/png",
  ".ico" => "image/x-icon"
}.freeze
JS_EXTENSIONS =
%w[.js .mjs].to_set.freeze

Instance Method Summary collapse

Constructor Details

#initialize(root:, additional_directory_mappings: {}) ⇒ AssetHandler

Returns a new instance of AssetHandler.



23
24
25
26
27
28
29
30
# File 'lib/assiette/asset_handler.rb', line 23

def initialize(root:, additional_directory_mappings: {})
  @mappings = build_mappings(root, additional_directory_mappings)
  @integrity_cache = {}
  @integrity_mutex = Mutex.new
  @modules_cache = nil
  @modules_mutex = Mutex.new
  @modules_version = nil
end

Instance Method Details

#absolute_asset_url_path(path, script_name = "") ⇒ Object



52
53
54
55
56
# File 'lib/assiette/asset_handler.rb', line 52

def absolute_asset_url_path(path, script_name = "")
  clean = path.sub(%r{\A/}, "")
  return nil unless resolve_file(clean)
  "#{script_name}/#{clean}?v=#{Assiette.version_tag}"
end

#asset_integrity(path) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/assiette/asset_handler.rb', line 58

def asset_integrity(path)
  version_tag = Assiette.version_tag
  @integrity_mutex.synchronize do
    if @integrity_version != version_tag
      @integrity_cache = {}
      @integrity_version = version_tag
    end
    return @integrity_cache[path] if @integrity_cache.key?(path)

    clean = path.sub(%r{\A/}, "")
    @integrity_cache[path] = compute_integrity(clean, version_tag)
  end
end

#js_modulesObject



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/assiette/asset_handler.rb', line 72

def js_modules
  version_tag = Assiette.version_tag
  @modules_mutex.synchronize do
    return @modules_cache if @modules_version == version_tag

    @modules_cache = @mappings.flat_map { |prefix, root|
      Dir[File.join(root, "**/*.{js,mjs}")].filter_map { |abs|
        next unless File.foreach(abs).any? { |line| line.match?(/\A\s*(import|export)\s/) }
        relative = Pathname.new(abs).relative_path_from(root).to_s
        mod_path = "/#{"#{prefix}/" unless prefix.empty?}#{relative}".squeeze("/")
        {path: mod_path, integrity: asset_integrity(mod_path)}
      }
    }.uniq { |m| m[:path] }.sort_by { |m| m[:path] }

    @modules_version = version_tag
    @modules_cache
  end
end

#resolve_file(path) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/assiette/asset_handler.rb', line 32

def resolve_file(path)
  clean = path.sub(%r{\A/}, "")
  @mappings.each do |prefix, root|
    if prefix.empty?
      relative = clean
    elsif clean.start_with?(prefix + "/")
      relative = clean[(prefix.length + 1)..]
    elsif clean == prefix
      next
    else
      next
    end

    abs = root.join(relative).cleanpath
    next unless abs.to_s.start_with?(root.to_s + "/")
    return abs if abs.exist? && abs.file?
  end
  nil
end