Skip to content

Commit

Permalink
feat(experimental): add support for Subresource Integrity via vite-pl…
Browse files Browse the repository at this point in the history
…ugin-manifest-sri
  • Loading branch information
ElMassimo committed Jan 18, 2022
1 parent b62de36 commit 0b3142c
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 15 deletions.
39 changes: 28 additions & 11 deletions vite_rails/lib/vite_rails/tag_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,27 @@ def vite_asset_path(name, **options)
def vite_javascript_tag(*names,
type: 'module',
asset_type: :javascript,
integrity: false,
skip_preload_tags: false,
skip_style_tags: false,
crossorigin: 'anonymous',
media: 'screen',
**options)
entries = vite_manifest.resolve_entries(*names, type: asset_type)
tags = javascript_include_tag(*entries.fetch(:scripts), crossorigin: crossorigin, type: type, extname: false, **options)
tags << vite_preload_tag(*entries.fetch(:imports), crossorigin: crossorigin, **options) unless skip_preload_tags
tags = ''.html_safe

entries.fetch(:main).each do |src, attrs|
tags << javascript_include_tag(src, crossorigin: crossorigin, type: type, extname: false, **attrs, **options)
end

unless skip_preload_tags
entries.fetch(:imports).each do |href, attrs|
tags << vite_preload_tag(href, crossorigin: crossorigin, **attrs, **options)
end
end

tags << stylesheet_link_tag(*entries.fetch(:stylesheets), media: media, crossorigin: crossorigin, **options) unless skip_style_tags

tags
end

Expand All @@ -44,9 +56,12 @@ def vite_typescript_tag(*names, **options)
end

# Public: Renders a <link> tag for the specified Vite entrypoints.
def vite_stylesheet_tag(*names, **options)
style_paths = names.map { |name| vite_asset_path(name, type: :stylesheet) }
stylesheet_link_tag(*style_paths, **options)
def vite_stylesheet_tag(*names, integrity: false, **options)
''.html_safe.tap do |tags|
vite_manifest.resolve_entries(*names, type: :stylesheet).fetch(:main).each do |href, attrs|
tags << stylesheet_link_tag(href, **attrs, **options)
end
end
end

# Public: Renders an <img> tag for the specified Vite asset.
Expand All @@ -68,11 +83,13 @@ def vite_manifest
end

# Internal: Renders a modulepreload link tag.
def vite_preload_tag(*sources, crossorigin:, **options)
sources.map { |source|
href = path_to_asset(source)
try(:request).try(:send_early_hints, 'Link' => %(<#{ href }>; rel=modulepreload; as=script; crossorigin=#{ crossorigin }))
tag.link(rel: 'modulepreload', href: href, as: 'script', crossorigin: crossorigin, **options)
}.join("\n").html_safe
def vite_preload_tag(source, crossorigin:, **options)
href = path_to_asset(source)
try(:request).try(:send_early_hints, 'Link' => %(<#{ href }>; rel=modulepreload; as=script; crossorigin=#{ crossorigin }).tap { |hint|
if integrity = options[:integrity]
hint << "; integrity: #{ integrity }"
end
})
tag.link(rel: 'modulepreload', href: href, as: 'script', type: 'module', crossorigin: crossorigin, **options)
end
end
10 changes: 6 additions & 4 deletions vite_ruby/lib/vite_ruby/manifest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,15 @@ def path_for(name, **options)
lookup!(name, **options).fetch('file')
end

# Public: Returns scripts, imported modules, and stylesheets for the specified
# Public: Returns entries, imported modules, and stylesheets for the specified
# entrypoint files.
def resolve_entries(*names, **options)
entries = names.map { |name| lookup!(name, **options) }
script_paths = entries.map { |entry| entry.fetch('file') }

imports = dev_server_running? ? [] : entries.flat_map { |entry| entry['imports'] }.compact.uniq
{
scripts: script_paths,
imports: imports.map { |entry| entry.fetch('file') }.uniq,
main: entries.map(&TO_ENTRY),
imports: imports.map(&TO_ENTRY).uniq,
stylesheets: dev_server_running? ? [] : (entries + imports).flat_map { |entry| entry['css'] }.compact.uniq,
}
end
Expand Down Expand Up @@ -63,6 +62,9 @@ def react_refresh_preamble

protected

# Internal: Returns a [src, attrs] entry.
TO_ENTRY = ->(entry) { [entry.fetch('file'), entry.slice('integrity').symbolize_keys] }

# Internal: Strict version of lookup.
#
# Returns a relative path for the asset, or raises an error if not found.
Expand Down

0 comments on commit 0b3142c

Please sign in to comment.