EXPERIMENTAL: preconnect and dns-prefetch resource hints for CDN domains (#26215)
Why this change? In https://web.dev/articles/preconnect-and-dns-prefetch, it describes how hinting to the browser to preconnect to domains which we will eventually use the connection for can help improve the time it takes to load a page. We are putting this behind an experimental flag so that we can test and profile this in a production environment. What does this change introduce? Introduce a hidden experimental `experimental_preconnect_link_header` site setting which when enabled will add the `preconnect` and `dns-prefetch` resource hints to the response headers for full page load requests.
This commit is contained in:
parent
d5b944f1de
commit
36cdb1444c
|
@ -53,7 +53,7 @@ class ApplicationController < ActionController::Base
|
||||||
after_action :add_noindex_header_to_non_canonical, if: :spa_boot_request?
|
after_action :add_noindex_header_to_non_canonical, if: :spa_boot_request?
|
||||||
after_action :set_cross_origin_opener_policy_header, if: :spa_boot_request?
|
after_action :set_cross_origin_opener_policy_header, if: :spa_boot_request?
|
||||||
after_action :clean_xml, if: :is_feed_response?
|
after_action :clean_xml, if: :is_feed_response?
|
||||||
around_action :link_preload, if: -> { spa_boot_request? && GlobalSetting.preload_link_header }
|
around_action :add_link_header, if: -> { spa_boot_request? }
|
||||||
|
|
||||||
HONEYPOT_KEY ||= "HONEYPOT_KEY"
|
HONEYPOT_KEY ||= "HONEYPOT_KEY"
|
||||||
CHALLENGE_KEY ||= "CHALLENGE_KEY"
|
CHALLENGE_KEY ||= "CHALLENGE_KEY"
|
||||||
|
@ -1096,10 +1096,29 @@ class ApplicationController < ActionController::Base
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_preload
|
def add_link_header
|
||||||
@links_to_preload = []
|
@links_to_preload = [] if GlobalSetting.preload_link_header
|
||||||
|
|
||||||
yield
|
yield
|
||||||
response.headers["Link"] = @links_to_preload.join(", ") if !@links_to_preload.empty?
|
|
||||||
|
links = []
|
||||||
|
|
||||||
|
if SiteSetting.experimental_preconnect_link_header
|
||||||
|
[GlobalSetting.cdn_url, SiteSetting.s3_cdn_url].each do |url|
|
||||||
|
next if url.blank?
|
||||||
|
base_url = URI.join(url, "/").to_s.chomp("/")
|
||||||
|
|
||||||
|
links.push("<#{base_url}>; rel=preconnect;")
|
||||||
|
# Not all browsers support the preconnect resource hint so we are adding dns-prefetch as the fallback
|
||||||
|
links.push("<#{base_url}>; rel=dns-prefetch;")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if GlobalSetting.preload_link_header && !@links_to_preload.empty?
|
||||||
|
links = links.concat(@links_to_preload)
|
||||||
|
end
|
||||||
|
|
||||||
|
response.headers["Link"] = links.join(", ") if links.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def spa_boot_request?
|
def spa_boot_request?
|
||||||
|
|
|
@ -2368,6 +2368,9 @@ developer:
|
||||||
experimental_objects_type_for_theme_settings:
|
experimental_objects_type_for_theme_settings:
|
||||||
default: false
|
default: false
|
||||||
hidden: true
|
hidden: true
|
||||||
|
experimental_preconnect_link_header:
|
||||||
|
default: false
|
||||||
|
hidden: true
|
||||||
|
|
||||||
navigation:
|
navigation:
|
||||||
navigation_menu:
|
navigation_menu:
|
||||||
|
|
|
@ -1188,8 +1188,36 @@ RSpec.describe ApplicationController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "preload Link header" do
|
describe "Link header" do
|
||||||
context "with GlobalSetting.preload_link_header" do
|
describe "when `experimental_preconnect_link_header` site setting is enabled" do
|
||||||
|
before { SiteSetting.experimental_preconnect_link_header = true }
|
||||||
|
|
||||||
|
it "should include the `preconnect` and `dns-prefetch` resource hints in the Link header when `GlobalSetting.cdn_url is configured`" do
|
||||||
|
global_setting :cdn_url, "https://cdn.example.com/something"
|
||||||
|
|
||||||
|
get "/latest"
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
expect(response.headers["Link"]).to include(
|
||||||
|
"<https://cdn.example.com>; rel=preconnect;, <https://cdn.example.com>; rel=dns-prefetch;",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should include the `preconnect` and `dns-prefetch` resource hints in the Link header when `SiteSetting.s3_cdn_url is configured`" do
|
||||||
|
SiteSetting.s3_cdn_url = "https://s3.some-cdn.com/something"
|
||||||
|
|
||||||
|
get "/latest"
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
expect(response.headers["Link"]).to include(
|
||||||
|
"<https://s3.some-cdn.com>; rel=preconnect;, <https://s3.some-cdn.com>; rel=dns-prefetch;",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when `GlobalSetting.preload_link_header` is enabled" do
|
||||||
before { global_setting :preload_link_header, true }
|
before { global_setting :preload_link_header, true }
|
||||||
|
|
||||||
it "should have the Link header with assets on full page requests" do
|
it "should have the Link header with assets on full page requests" do
|
||||||
|
@ -1203,7 +1231,7 @@ RSpec.describe ApplicationController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "without GlobalSetting.preload_link_header" do
|
context "when `GlobalSetting.preload_link_header` is disabled" do
|
||||||
before { global_setting :preload_link_header, false }
|
before { global_setting :preload_link_header, false }
|
||||||
|
|
||||||
it "shouldn't have the Link header with assets on full page requests" do
|
it "shouldn't have the Link header with assets on full page requests" do
|
||||||
|
|
Loading…
Reference in New Issue