-
Notifications
You must be signed in to change notification settings - Fork 120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add uncapped preload headers for style, script assets #11504
Conversation
app/helpers/script_helper.rb
Outdated
@@ -16,12 +16,19 @@ def render_javascript_pack_once_tags(...) | |||
concat javascript_assets_tag | |||
@scripts.each do |name, (url_params, attributes)| | |||
asset_sources.get_sources(name).each do |source| | |||
crossorigin = true if local_crossorigin_sources? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should be able to directly assign this right? I'd go a step further an inline the entire thing, but that would make us have to wrap line 23 below
crossorigin = true if local_crossorigin_sources? | |
crossorigin = local_crossorigin_sources? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This branch was actually a few months old, and that change was one of the first things I tried editing when I resurrected it. But there's a significant difference between nil
and false
in how it's used with javascript_include_tag
, which is the reason for the true if
. I can't recall off the top of my head, but I'll make sure to add some test coverage for it when I write those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah looks like the source code checks for "not nil" and "true"
maybe it would be easier if we updated local_crossorigin_sources?
to match that expected format?
# Fake boolean to match expected values for `:crossorigin` option in `javascript_include_tag`
# @see ActionView::Helpers::AssetTagHelper#javascript_include_tag
# @return [true, nil]
def crossorigin
true if Rails.env.development? && ENV['WEBPACK_PORT'].present?
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tinkered with this a bit, and landed toward a small revision to use presence
in 4e23c1e.
Partly for micro-optimization, since the value is referenced twice and would prefer to avoid evaluating that logic twice. But moreso because the true
/ nil
vs. true
/ false
is less to do with some internal logic specific to javascript_include_tag
, and moreso about the crossorigin
attribute itself, where false
would apply an empty string attribute value, which is significant since it's an HTML boolean attribute.
crossorigin = true if local_crossorigin_sources? | ||
integrity = asset_sources.get_integrity(source) | ||
|
||
if attributes[:preload_links_header] != false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this means that preload_links_header: nil
will add the preload header, that seems counterintuitive to me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shoudl we use the same presence
trick?
if attributes[:preload_links_header] != false | |
if attributes[:preload_links_header].present? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that'd be the opposite behavior from what we expect, since we want :preload_links_header
to be opt-out, not opt-in.
changelog: Internal, Performance, Add preload headers for all style, script assets
ea5090e
to
8183cb1
Compare
'</application.js>; rel=preload; as=script,' \ | ||
'</document-capture.js>; rel=preload; as=script', | ||
'</application.js>;rel=preload;as=script,' \ | ||
'</document-capture.js>;rel=preload;as=script', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whitespace is optional per the spec, which allows us to salvage back some of the bytesize increase these changes could incur.
link-value = "<" URI-Reference ">" *( OWS ";" OWS link-param )
See: https://github.com/18F/identity-idp/pull/11504/files#r1841273216 Co-authored-by: Zach Margolis <[email protected]>
We don't need any of this anymore: - Asset pipeline lookup - Preload headers handling - Server push - Multiple source concatenation - Nonce handling crossorigin as a boolean attribute is same as crossorigin=anonymous
Previously evaluated per script, even though the result would always be the same
I did some local benchmarking and pushed a few more iterations for some small optimizations. The end result is pretty nice, about 75% improvement.
(Benchmark script as HTML comment of this message) |
crossorigin = true if local_crossorigin_sources? | ||
integrity = asset_sources.get_integrity(source) | ||
|
||
if attributes[:preload_links_header] != false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shoudl we use the same presence
trick?
if attributes[:preload_links_header] != false | |
if attributes[:preload_links_header].present? |
* Add unlimited preload headers for style, script assets changelog: Internal, Performance, Add preload headers for all style, script assets * Update spec assertions for dropped whitespace * Add specs * Append with string mutation See: https://github.com/18F/identity-idp/pull/11504/files#r1841273216 Co-authored-by: Zach Margolis <[email protected]> * Use plain tag helper for generating script tag We don't need any of this anymore: - Asset pipeline lookup - Preload headers handling - Server push - Multiple source concatenation - Nonce handling crossorigin as a boolean attribute is same as crossorigin=anonymous * Add spec for preload_links_header attribute handling * Evaluate crossorigin once Previously evaluated per script, even though the result would always be the same * Micro-optimize append * Lowercase header key * Use presence to toggle between true/nil * Sync specs to use lowercase link key --------- Co-authored-by: Zach Margolis <[email protected]>
* Add unlimited preload headers for style, script assets changelog: Internal, Performance, Add preload headers for all style, script assets * Update spec assertions for dropped whitespace * Add specs * Append with string mutation See: https://github.com/18F/identity-idp/pull/11504/files#r1841273216 Co-authored-by: Zach Margolis <[email protected]> * Use plain tag helper for generating script tag We don't need any of this anymore: - Asset pipeline lookup - Preload headers handling - Server push - Multiple source concatenation - Nonce handling crossorigin as a boolean attribute is same as crossorigin=anonymous * Add spec for preload_links_header attribute handling * Evaluate crossorigin once Previously evaluated per script, even though the result would always be the same * Micro-optimize append * Lowercase header key * Use presence to toggle between true/nil * Sync specs to use lowercase link key --------- Co-authored-by: Zach Margolis <[email protected]>
🛠 Summary of changes
Updates asset helpers to bypass internal
stylesheet_link_tag
andjavascript_include_tag
logic for handling preload response headers, appending preload headers without caps. As of rails/rails#48405 (Rails 7.1), preload headers added by tag helpers are capped at 1kb, which is very limiting, especially given our approach of loading many, smaller assets targeted as sidecar assets for UI components.While the caps have created some incentives to be more intentional with preloading (e.g. #10612), we've already addressed the lowest hanging fruit, and a number of critical scripts are currently not being preloaded (e.g. reCAPTCHA behaviors on the sign-in screen).
References:
📜 Testing Plan
Verify that preload headers are included for all scripts and assets, including
integrity
orcrossorigin
directives as appropriate. Compare against https://secure.login.govVerify that there are no style or script regressions in browsing the application, either in local development or in a review application.