Postponed on #2998451: Toolbar tray rendering can result "flickering" resizing of content area to accommodate open trays
Problem/Motivation
#2998451: Toolbar tray rendering can result "flickering" resizing of content area to accommodate open trays 👈 this issue included the addition of inline JavaScript to <head> so it could load before anything on the page was rendered. This resulted in a less visually jarring toolbar initialization.
The JS is currently added via toolbar_page_attachments(), adding a script tag to $page['#attached']['html_head']. Unlike most Drupal JavaScript, the JS code is not in a dedicated file, but created as a HEREDOC variable. It's not the most elegant DX, but it got the job done. We'd like to find a better approach.
Some things that were tried:
- Having this JS be part of a library with
header: true, which was decided against as it adds an additional JS request, even when assets are aggregated - Having the JS be in a dedicated file, but not part of a library. PHP would load the file in
toolbar_page_attachments(), write the contents to a string, which would ultimately become the content of the newly added script tag. This was decided against as it would result in loading a file from the filesystem on every request. This could potentially be addressed by usingFileCacheFactory, but best explored in a dedicated issue such as this instead of blocking the anti-flicker enhancements provided by #2998451
Steps to reproduce
Proposed resolution
Move toolbar.anti-flicker.js back to a regular library definition with header: true
While this is an additionally http request, it is only an http request for users with access to the toolbar, unlike the current implementation which loads inline JavaScript for users without access to the toolbar #3379245: Toolbar anti-flicker js shows for anonymous users.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
JavaScript which was added inline in Drupal 10.1.0 to prevent toolbar flickering has been moved to a file in a new toolbar.anti_flicker library. This resolves reported bugs and CSP issues due to the JavaScript originally being inline.
| Comment | File | Size | Author |
|---|---|---|---|
| #31 | 3355381-31.patch | 8.35 KB | catch |
| #31 | interdiff.txt | 681 bytes | catch |
| #17 | 3355381.patch | 7.69 KB | catch |
| #15 | 3355381.patch | 7.29 KB | catch |
| #13 | toolbar-antiflicker-clean-comments.patch | 1.05 KB | drewcking |
Comments
Comment #3
stewestWe're noticing that the comments from Line 68 web/core/modules/toolbar/toolbar.module are showing when logged out.
Had to add this to themes/THEMENAME/includes/page.inc
Comment #4
kevinquillen commentedSame as #3. This should only load for appropriate users.
Comment #5
drewcking commentedIs there a need for these comments to be in the javascript? It makes sense to move them above this heredoc so that they are PHP comments instead of JS comments.
Comment #6
bnjmnmGood call. No need. I think the comments presence in the heredoc was due to that block of code originally being in a JS file and we didn't think to adjust for it going into the heredoc.
Comment #7
fngatia commentedAm also having problems with the comments as indicated above. My custom js are injecting data/code into the tag in the comments instead of the HTML one. Can the tags wrap tag be avoided?
Comment #8
ambient.impactI'm a bit baffled as to why this made it into a stable release because it feels like this is not a good way to handle this. Core intentionally moved away from inline JavaScript years ago, and this is non-usable on sites with Content Security Policy set up. Just putting this into render-blocking external JavaScript and CSS files linked from the
<head>should accomplish the same thing, in that browsers should prioritize downloading that before starting to render the page, should it not?Comment #9
lucasvm commentedI can confirm this issue still exists on Drupal 10.1 i got fixed by adding this to the .theme file instead of creating a new page inc
Still present on some admin pages.
Comment #10
bnjmnmThe reasons why it was not done this way was discussed in the issue where it was implemented #2998451: Toolbar tray rendering can result "flickering" resizing of content area to accommodate open trays. There's was also an acknowledgement that it might not be the ideal approach, thus the existence of this issue.
I look forward to seeing MRs or patches that improve it, as there seems to be enough interest in this to result in some motivation.
Comment #11
danny englanderI just got hit with this one. My use case is, I have Laveral Mix and BrowserSync running which injects some inline JS to hot reload the page when the CSS has changed from my Sass build. The JS from Laveral Mix inserted itself right within the anti-flicker script so as to break the page just like the screen capture in #3. (Logged in and logged out.)
Comment #12
catchI just found #3379245: Toolbar anti-flicker js shows for anonymous users and in the process of searching for duplicates found this issue.
I wasn't involved in the previous issue, but I think we should do;
Once #3379245: Toolbar anti-flicker js shows for anonymous users is fixed we'd only be adding the JavaScript for users with access to the toolbar, these are authenticated with admin or semi-admin permissions who will mostly be browsing the site with the file already browser cached. So for me it is not worth the workaround to save the cold cache http request for those users.
The other reason is that we already have a library with render-blocking js in the header, although I opened an issue to remove that here: #3375181: Deprecate the touchevents JavaScript library and update CSS. But until that's done it won't be an extra http request in most cases.
Comment #13
drewcking commentedThis patch tweaks the first JS comment block to replace the HTML tags with words, e.g.,
<body>becomes "the body tag".Comment #14
manikandank03 commentedHello drewcking,
Thanks for the patch, in my case I faced the same issue and did the same changes as custom patch and fix the issue.
Here I confirm the patch #13 fix the issue and works fine on Drupal 10.1.1.
Comment #15
catchHere's a patch, moves it back to a file, uses the same approach as https://git.drupalcode.org/project/drupal/-/merge_requests/3464/diffs?co...
I'm bumping this to major:
1. The comments in the inline js are breaking sites as seen above.
2. The current inline js is needlessly rendered for anonymous users #3379245: Toolbar anti-flicker js shows for anonymous users, this not only adds cruft to all those pages, but because the js relies on session storage if you're logged in then log out, you can still get the toolbar classes applied.
Both of those issues could be individually fixed with the current implementation, but I don't think the special-casing is really necessary.
This will result in an extra render-blocking HTTP request as discussed in the original issue, but that extra HTTP request is only for users with access to the toolbar, who are extremely likely to have the file cached.
Comment #16
lauriiiShouldn't we load this library somewhere? 🤔
Comment #17
catchYes that would help - adding the dependency and fixing some cs issues.
Comment #18
drewcking commentedThanks catch, patch in #17 works for me on a fresh install of 10.1.2 when loading the site through browser-sync.
Comment #19
gappleAFAIK browsers' preload scanner will still request the JS file while rendering is blocked for CSS parsing. HTTP 1.1 may hit a limit on concurrent requests that could delay the request for an additional file (KeepAlive should mitigate overhead of an additional connection), but that shouldn't be an issue with HTTP/2.
Since the JS comes right after the CSS, which already blocks rendering, users won't see a FOUC and the execution time of the script seems like more of a concern than the time for an additional HTTP request on the first visit to a page its needed.
----
The CSP module currently removes the inline script.
I think it's best to avoid an inline script that would nudge less aware site-builders to add an
'unsafe-inline', rather than the more complex and less obvious method of removing the script via a hook.Comment #20
lmoeniI tested patch #17 on Drupal 10.1.2 and can confirm that it works.
Thanks for the patch!
Comment #21
lmoeniComment #22
lauriiiI don't think we were able to anticipate all of the downsides of the chosen solution in #3379245: Toolbar anti-flicker js shows for anonymous users. It seems fine to change that decision and go with the option that is slightly less performant in some use cases due to the extra request, but less likely to run into challenges.
I think we should create a new CR and update https://www.drupal.org/node/3350272.
Also wondering if we should backport this or not. It seems like we should backport this, but the fix is adding a new library. I think that should be fine given that it's addressing a bug, and even when the JavaScript is missing, the site remains functional (users just have to suffer from flickering until next cache clear).
Comment #23
catchI'm not sure what to write for a new change record, could we maybe just update https://www.drupal.org/node/3350272?
Something like
Then a release note. I've added a releases notes snippet.
Comment #24
lauriiiI thought we could file a CR to mention that the inline JS has been removed because some modules, like #3358392: Disable toolbar anti-flicker inline JS have made changes to integrate with it (or actually remove it). Not too fussed about it but feels like we file CRs for less impactful changes occasionally 😅
Comment #25
catchHaving written #23 I figured out what we could write for a new one, so here it is: https://www.drupal.org/node/3383056
Then I think we could do the same text update to the original CR as proposed in #23 just adding a link to the CR?
Comment #28
lauriiiCommitted 56e2560 and pushed to 11.x. Cherry picked to 10.1.x as a major bug fix to address the regression. Thanks!
Comment #30
lauriiiLooks like this broke HEAD because #17 was only ran against 10.1.x and
\Drupal\FunctionalJavascriptTests\PerformanceTestBasebased tests are only in 11.x. 🤦♂️Comment #31
catchSince this is a one digit change, moving back to RTBC - will still need #17 for 10.1.x
Comment #33
lauriiiCommitted 3b8df67 and pushed to 11.x. Thanks!