mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Automatically set Link header for each stylesheet and script
<link rel="preload"> elements[0] can be serialized in `Link` headers[1] to allow the browser to preload them before it parsed the HTML body. It is particularly useful for scripts included at the bottom of the document. [0] https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content [1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link
This commit is contained in:
parent
70c9f39039
commit
a9012af688
3 changed files with 50 additions and 22 deletions
|
@ -86,11 +86,11 @@ module ActionView
|
|||
def javascript_include_tag(*sources)
|
||||
options = sources.extract_options!.stringify_keys
|
||||
path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
|
||||
early_hints_links = []
|
||||
preload_links = []
|
||||
|
||||
sources_tags = sources.uniq.map { |source|
|
||||
href = path_to_javascript(source, path_options)
|
||||
early_hints_links << "<#{href}>; rel=preload; as=script"
|
||||
preload_links << "<#{href}>; rel=preload; as=script"
|
||||
tag_options = {
|
||||
"src" => href
|
||||
}.merge!(options)
|
||||
|
@ -100,7 +100,7 @@ module ActionView
|
|||
content_tag("script", "", tag_options)
|
||||
}.join("\n").html_safe
|
||||
|
||||
request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request
|
||||
send_preload_links_header(preload_links)
|
||||
|
||||
sources_tags
|
||||
end
|
||||
|
@ -136,11 +136,11 @@ module ActionView
|
|||
def stylesheet_link_tag(*sources)
|
||||
options = sources.extract_options!.stringify_keys
|
||||
path_options = options.extract!("protocol", "host", "skip_pipeline").symbolize_keys
|
||||
early_hints_links = []
|
||||
preload_links = []
|
||||
|
||||
sources_tags = sources.uniq.map { |source|
|
||||
href = path_to_stylesheet(source, path_options)
|
||||
early_hints_links << "<#{href}>; rel=preload; as=style"
|
||||
preload_links << "<#{href}>; rel=preload; as=style"
|
||||
tag_options = {
|
||||
"rel" => "stylesheet",
|
||||
"media" => "screen",
|
||||
|
@ -149,7 +149,7 @@ module ActionView
|
|||
tag(:link, tag_options)
|
||||
}.join("\n").html_safe
|
||||
|
||||
request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request
|
||||
send_preload_links_header(preload_links)
|
||||
|
||||
sources_tags
|
||||
end
|
||||
|
@ -281,12 +281,12 @@ module ActionView
|
|||
crossorigin: crossorigin
|
||||
}.merge!(options.symbolize_keys))
|
||||
|
||||
early_hints_link = "<#{href}>; rel=preload; as=#{as_type}"
|
||||
early_hints_link += "; type=#{mime_type}" if mime_type
|
||||
early_hints_link += "; crossorigin=#{crossorigin}" if crossorigin
|
||||
early_hints_link += "; nopush" if nopush
|
||||
preload_link = "<#{href}>; rel=preload; as=#{as_type}"
|
||||
preload_link += "; type=#{mime_type}" if mime_type
|
||||
preload_link += "; crossorigin=#{crossorigin}" if crossorigin
|
||||
preload_link += "; nopush" if nopush
|
||||
|
||||
request.send_early_hints("Link" => early_hints_link) if respond_to?(:request) && request
|
||||
send_preload_links_header([preload_link])
|
||||
|
||||
link_tag
|
||||
end
|
||||
|
@ -482,6 +482,16 @@ module ActionView
|
|||
type
|
||||
end
|
||||
end
|
||||
|
||||
def send_preload_links_header(preload_links)
|
||||
if respond_to?(:request) && request
|
||||
request.send_early_hints("Link" => preload_links.join("\n"))
|
||||
end
|
||||
|
||||
if respond_to?(:response) && response
|
||||
response.headers["Link"] = [response.headers["Link"].presence, *preload_links].compact.join(",")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -84,7 +84,7 @@ class RoutedRackApp
|
|||
end
|
||||
|
||||
class BasicController
|
||||
attr_accessor :request
|
||||
attr_accessor :request, :response
|
||||
|
||||
def config
|
||||
@config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config|
|
||||
|
|
|
@ -9,23 +9,33 @@ ActionView::Template::Types.delegate_to Mime
|
|||
class AssetTagHelperTest < ActionView::TestCase
|
||||
tests ActionView::Helpers::AssetTagHelper
|
||||
|
||||
attr_reader :request
|
||||
attr_reader :request, :response
|
||||
|
||||
class FakeRequest
|
||||
attr_accessor :script_name
|
||||
def protocol() "http://" end
|
||||
def ssl?() false end
|
||||
def host_with_port() "localhost" end
|
||||
def base_url() "http://www.example.com" end
|
||||
def send_early_hints(links) end
|
||||
end
|
||||
|
||||
class FakeResponse
|
||||
def headers
|
||||
@headers ||= {}
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
@controller = BasicController.new
|
||||
|
||||
@request = Class.new do
|
||||
attr_accessor :script_name
|
||||
def protocol() "http://" end
|
||||
def ssl?() false end
|
||||
def host_with_port() "localhost" end
|
||||
def base_url() "http://www.example.com" end
|
||||
def send_early_hints(links) end
|
||||
end.new
|
||||
|
||||
@request = FakeRequest.new
|
||||
@controller.request = @request
|
||||
|
||||
@response = FakeResponse.new
|
||||
@controller.response = @response
|
||||
end
|
||||
|
||||
def url_for(*args)
|
||||
|
@ -499,6 +509,14 @@ class AssetTagHelperTest < ActionView::TestCase
|
|||
assert_dom_equal %(<script src="/javascripts/foo.js"></script>), javascript_include_tag("foo.js")
|
||||
end
|
||||
|
||||
|
||||
def test_should_set_preload_links
|
||||
stylesheet_link_tag("http://example.com/style.css")
|
||||
javascript_include_tag("http://example.com/all.js")
|
||||
expected = "<http://example.com/style.css>; rel=preload; as=style,<http://example.com/all.js>; rel=preload; as=script"
|
||||
assert_equal expected, @response.headers["Link"]
|
||||
end
|
||||
|
||||
def test_image_path
|
||||
ImagePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue