require 'base64' require 'action_view/helpers' require 'sewing_kit/webpack/manifest' module SewingKit module Webpack module Helper include ActionView::Helpers class UnknownJavaScriptAssetError < StandardError end def sewing_kit_asset_paths(entrypointName, extension: 'js') return '' unless entrypointName.present? paths = SewingKit::Webpack::Manifest.asset_paths(entrypointName) return '' unless paths && paths[extension] entryPaths = paths[extension] if serve_development_assets? && extension == 'js' entryPaths.unshift('/webpack/assets/dll/vendor.js') end entryPaths end def sewing_kit_link_tag(*paths) options = paths.extract_options! tags = paths.uniq.map { |path| next '' if path == '' create_asset_tag(:link, path, options) } safe_join(tags, "\n") end def sewing_kit_script_tag(*paths) options = paths.extract_options! tags = paths.uniq.map { |path| next '' if path == '' create_asset_tag(:script, path, options) } safe_join(tags, "\n") end private def create_asset_tag(tag_type, path, tag_options) raise ArgumentError, "Invalid tag type: #{tag_type}" unless [:script, :link].include? tag_type options = tag_options.clone if tag_options[:integrity] file_hash = extract_hash(path) options[:integrity] = file_hash ? encode_hash(file_hash) : nil end case tag_type when :script content_tag(:script, '', options.reverse_merge(src: path)) when :link tag(:link, options.reverse_merge(href: path, rel: 'stylesheet')) end end def encode_hash(hash) # sewing-kit's default config places a sha256 hash in the filename. Browsers expect integrity # to be the Base64 encoded version of the binary hash prefixed with the hashing algorithm binary_hash = Array(hash).pack('H*') "sha256-#{Base64.strict_encode64(binary_hash)}" end def extract_hash(path) # Consumes sewing-kit's [name]-[chunkhash].[ext] format return unless path =~ /.*-[A-Za-z0-9]{64}\.(js|css)/ path.rpartition('-').last.split('.').first end def serve_development_assets? return false if ENV['SK_SIMULATE_PRODUCTION'] == '1' Rails.env.development? end end end end