# frozen_string_literal: true require 'sewing_kit/webpack/manifest/base' require 'benchmark' require 'browserslist_useragent' module SewingKit module Webpack class Manifest class Production < Base def initialize @cache_by_user_agent = {} @metadata = nil @metadata_path = nil end def asset_bundle_name(user_agent) metadata_for(user_agent)['name'] end # :nodoc: def asset_dependencies(entrypoint_name, user_agent) metadata_for(user_agent)['entrypoints'][entrypoint_name] end def metadata @metadata ||= load_metadata end private def metadata_for(user_agent) time = Benchmark.realtime do @cache_by_user_agent[user_agent] ||= find_matching_metadata(metadata, user_agent) end Rails.logger.debug( "[sewing_kit] found asset metadata for #{user_agent} in #{time * 1000} milliseconds" ) @cache_by_user_agent[user_agent] end def find_matching_metadata(consolidated_metadata, user_agent) return metadata unless metadata.is_a?(Array) found = consolidated_metadata.find do |metadata_item| metadata_matches?(metadata_item, user_agent) end found || baseline(consolidated_metadata) end def metadata_matches?(metadata_item, user_agent) return false if metadata_item["resolvedBrowsers"].nil? matcher = BrowserslistUseragent::Match.new(metadata_item["resolvedBrowsers"], user_agent) matcher.browser? && matcher.version?(allow_higher: true) rescue ArgumentError # Some user_agent strings have bad semver versions. # In these cases the Semver gem ends up throwing an ArgumentError when we parse the user_agent. # Since we cannot know what kind of browser the user has when parsing fails, # the safest option is to just return false here and let the defaulting logic send the baseline manifest. false end def baseline(consolidated_metadata) consolidated_metadata.last end def load_metadata load_metadata_from_fs(path) end def path return SewingKit.configuration.manifest_path unless SewingKit.configuration.manifest_path.nil? File.join(Rails.root, 'public', 'bundles', SewingKit.configuration.manifest_name) end end end end end